Merge pull request #1502 from madrang/SafeHandle.CloseTestDispose
[mono.git] / mcs / class / corlib / Test / System.Threading.Tasks / TaskTest.cs
1 //
2 // TaskTest.cs
3 //
4 // Authors:
5 //      Marek Safar  <marek.safar@gmail.com>
6 //
7 // Copyright (c) 2008 Jérémie "Garuma" Laval
8 // Copyright (C) 2011 Xamarin Inc (http://www.xamarin.com)
9 //
10 // Permission is hereby granted, free of charge, to any person obtaining a copy
11 // of this software and associated documentation files (the "Software"), to deal
12 // in the Software without restriction, including without limitation the rights
13 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 // copies of the Software, and to permit persons to whom the Software is
15 // furnished to do so, subject to the following conditions:
16 //
17 // The above copyright notice and this permission notice shall be included in
18 // all copies or substantial portions of the Software.
19 //
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26 // THE SOFTWARE.
27 //
28 //
29
30 #if NET_4_0
31
32 using System;
33 using System.Threading;
34 using System.Threading.Tasks;
35 using System.Collections.Generic;
36 using NUnit.Framework;
37
38 #if !MOBILE
39 using NUnit.Framework.SyntaxHelpers;
40 #endif
41
42 namespace MonoTests.System.Threading.Tasks
43 {
44         [TestFixture]
45         public class TaskTests
46         {
47                 class MockScheduler : TaskScheduler
48                 {
49                         public event Action<Task, bool> TryExecuteTaskInlineHandler;
50
51                         protected override IEnumerable<Task> GetScheduledTasks ()
52                         {
53                                 throw new NotImplementedException ();
54                         }
55
56                         protected override void QueueTask (Task task)
57                         {
58                                 return;
59                         }
60
61                         protected override bool TryExecuteTaskInline (Task task, bool taskWasPreviouslyQueued)
62                         {
63                                 if (TryExecuteTaskInlineHandler != null)
64                                         TryExecuteTaskInlineHandler (task, taskWasPreviouslyQueued);
65
66                                 return base.TryExecuteTask (task);
67                         }
68                 }
69
70                 class NonInlineableScheduler : TaskScheduler
71                 {
72                         protected override IEnumerable<Task> GetScheduledTasks ()
73                         {
74                                 throw new NotImplementedException ();
75                         }
76
77                         protected override void QueueTask (Task task)
78                         {
79                                 if (!base.TryExecuteTask (task))
80                                         throw new ApplicationException ();
81                         }
82
83                         protected override bool TryExecuteTaskInline (Task task, bool taskWasPreviouslyQueued)
84                         {
85                                 return false;
86                         }
87                 }
88
89                 class ExceptionScheduler : TaskScheduler
90                 {
91                         protected override IEnumerable<Task> GetScheduledTasks ()
92                         {
93                                 throw new ApplicationException ("1");
94                         }
95
96                         protected override void QueueTask (Task task)
97                         {
98                                 throw new ApplicationException ("2");
99                         }
100
101                         protected override bool TryExecuteTaskInline (Task task, bool taskWasPreviouslyQueued)
102                         {
103                                 throw new ApplicationException ("3");
104                         }
105                 }
106
107                 int workerThreads;
108                 int completionPortThreads;
109
110                 Task[] tasks;
111                 const int max = 6;
112                 
113                 [SetUp]
114                 public void Setup()
115                 {
116                         ThreadPool.GetMinThreads (out workerThreads, out completionPortThreads);
117                         ThreadPool.SetMinThreads (1, 1);
118
119                         tasks = new Task[max];                  
120                 }
121                 
122                 [TearDown]
123                 public void Teardown()
124                 {
125                         ThreadPool.SetMinThreads (workerThreads, completionPortThreads);
126                 }
127                 
128                 void InitWithDelegate(Action action)
129                 {
130                         for (int i = 0; i < max; i++) {
131                                 tasks[i] = Task.Factory.StartNew(action);
132                         }
133                 }
134                 
135                 [Test]
136                 public void WaitAnyTest()
137                 {
138                         ParallelTestHelper.Repeat (delegate {
139                                 int flag = 0;
140                                 int finished = 0;
141                                 
142                                 InitWithDelegate(delegate {
143                                         int times = Interlocked.Exchange (ref flag, 1);
144                                         if (times == 1) {
145                                                 SpinWait sw = new SpinWait ();
146                                                 while (finished == 0) sw.SpinOnce ();
147                                         } else {
148                                                 Interlocked.Increment (ref finished);
149                                         }
150                                 });
151                                 
152                                 int index = Task.WaitAny(tasks, 1000);
153                                 
154                                 Assert.AreNotEqual (-1, index, "#3");
155                                 Assert.AreEqual (1, flag, "#1");
156                                 Assert.AreEqual (1, finished, "#2");
157                         });
158                 }
159
160                 [Test]
161                 public void WaitAny_Empty ()
162                 {
163                         Assert.AreEqual (-1, Task.WaitAny (new Task[0]));
164                 }
165
166                 [Test]
167                 public void WaitAny_Zero ()
168                 {
169                         Assert.AreEqual (-1, Task.WaitAny (new[] { new Task (delegate { })}, 0), "#1");
170                         Assert.AreEqual (-1, Task.WaitAny (new[] { new Task (delegate { }) }, 20), "#1");
171                 }
172
173                 [Test]
174                 public void WaitAny_Cancelled ()
175                 {
176                         var cancelation = new CancellationTokenSource ();
177                         var tasks = new Task[] {
178                                 new Task (delegate { }),
179                                 new Task (delegate { }, cancelation.Token)
180                         };
181
182                         cancelation.Cancel ();
183
184                         Assert.AreEqual (1, Task.WaitAny (tasks, 1000), "#1");
185                         Assert.IsTrue (tasks[1].IsCompleted, "#2");
186                         Assert.IsTrue (tasks[1].IsCanceled, "#3");
187                 }
188
189                 [Test]
190                 public void WaitAny_CancelledWithoutExecution ()
191                 {
192                         var cancelation = new CancellationTokenSource ();
193                         var tasks = new Task[] {
194                                 new Task (delegate { }),
195                                 new Task (delegate { })
196                         };
197
198                         int res = 0;
199                         var mre = new ManualResetEventSlim (false);
200                         ThreadPool.QueueUserWorkItem (delegate {
201                                 res = Task.WaitAny (tasks, 20);
202                                 mre.Set ();
203                         });
204
205                         cancelation.Cancel ();
206                         Assert.IsTrue (mre.Wait (1000), "#1");
207                         Assert.AreEqual (-1, res);
208                 }
209
210                 [Test]
211                 public void WaitAny_OneException ()
212                 {
213                         var mre = new ManualResetEventSlim (false);
214                         var tasks = new Task[] {
215                                 Task.Factory.StartNew (delegate { mre.Wait (1000); }),
216                                 Task.Factory.StartNew (delegate { throw new ApplicationException (); })
217                         };
218
219                         Assert.AreEqual (1, Task.WaitAny (tasks, 1000), "#1");
220                         Assert.IsFalse (tasks[0].IsCompleted, "#2");
221                         Assert.IsTrue (tasks[1].IsFaulted, "#3");
222
223                         mre.Set ();
224                 }
225
226                 [Test]
227                 public void WaitAny_SingleCanceled ()
228                 {
229                         var src = new CancellationTokenSource ();
230                         var t = Task.Factory.StartNew (() => { Thread.Sleep (200); src.Cancel (); src.Token.ThrowIfCancellationRequested (); }, src.Token);
231                         Assert.AreEqual (0, Task.WaitAny (new [] { t }));
232                 }
233
234                 public void WaitAny_ManyExceptions ()
235                 {
236                         CountdownEvent cde = new CountdownEvent (3);
237                         var tasks = new [] {
238                                 Task.Factory.StartNew (delegate { try { throw new ApplicationException (); } finally { cde.Signal (); } }),
239                                 Task.Factory.StartNew (delegate { try { throw new ApplicationException (); } finally { cde.Signal (); } }),
240                                 Task.Factory.StartNew (delegate { try { throw new ApplicationException (); } finally { cde.Signal (); } })
241                         };
242
243                         Assert.IsTrue (cde.Wait (1000), "#1");
244
245                         try {
246                                 Assert.IsTrue (Task.WaitAll (tasks, 1000), "#2");
247                         } catch (AggregateException e) {
248                                 Assert.AreEqual (3, e.InnerExceptions.Count, "#3");
249                         }
250                 }
251
252                 [Test]
253                 public void WaitAny_ManyCanceled ()
254                 {
255                         var cancellation = new CancellationToken (true);
256                         var tasks = new[] {
257                                 Task.Factory.StartNew (delegate { }, cancellation),
258                                 Task.Factory.StartNew (delegate { }, cancellation),
259                                 Task.Factory.StartNew (delegate { }, cancellation)
260                         };
261
262                         try {
263                                 Assert.IsTrue (Task.WaitAll (tasks, 1000), "#1");
264                         } catch (AggregateException e) {
265                                 Assert.AreEqual (3, e.InnerExceptions.Count, "#2");
266                         }
267                 }
268                 
269                 [Test]
270                 public void WaitAllTest ()
271                 {
272                         ParallelTestHelper.Repeat (delegate {
273                                 int achieved = 0;
274                                 InitWithDelegate(delegate { Interlocked.Increment(ref achieved); });
275                                 Task.WaitAll(tasks);
276                                 Assert.AreEqual(max, achieved, "#1");
277                         });
278                 }
279
280                 [Test]
281                 public void WaitAll_ManyTasks ()
282                 {
283                         for (int r = 0; r < 2000; ++r) {
284                                 var tasks = new Task[60];
285
286                                 for (int i = 0; i < tasks.Length; i++) {
287                                         tasks[i] = Task.Factory.StartNew (delegate { Thread.Sleep (0); });
288                                 }
289
290                                 Assert.IsTrue (Task.WaitAll (tasks, 5000));
291                         }
292                 }
293
294                 [Test]
295                 public void WaitAll_Zero ()
296                 {
297                         Assert.IsFalse (Task.WaitAll (new Task[1] { new Task (delegate { }) }, 0), "#0");
298                         Assert.IsFalse (Task.WaitAll (new Task[1] { new Task (delegate { }) }, 10), "#1");
299                 }
300
301                 [Test]
302                 public void WaitAll_WithExceptions ()
303                 {
304                         InitWithDelegate (delegate { throw new ApplicationException (); });
305
306                         try {
307                                 Task.WaitAll (tasks);
308                                 Assert.Fail ("#1");
309                         } catch (AggregateException e) {
310                                 Assert.AreEqual (6, e.InnerExceptions.Count, "#2");
311                         }
312
313                         Assert.IsNotNull (tasks[0].Exception, "#3");
314                 }
315
316                 [Test]
317                 public void WaitAll_TimeoutWithExceptionsAfter ()
318                 {
319                         CountdownEvent cde = new CountdownEvent (2);
320                         var mre = new ManualResetEvent (false);
321                         var tasks = new[] {
322                                 Task.Factory.StartNew (delegate { mre.WaitOne (); }),
323                                 Task.Factory.StartNew (delegate { try { throw new ApplicationException (); } finally { cde.Signal (); } }),
324                                 Task.Factory.StartNew (delegate { try { throw new ApplicationException (); } finally { cde.Signal (); } })
325                         };
326
327                         Assert.IsTrue (cde.Wait (1000), "#1");
328                         Assert.IsFalse (Task.WaitAll (tasks, 1000), "#2");
329
330                         mre.Set ();
331
332                         try {
333                                 Assert.IsTrue (Task.WaitAll (tasks, 1000), "#3");
334                                 Assert.Fail ("#4");
335                         } catch (AggregateException e) {
336                                 Assert.AreEqual (2, e.InnerExceptions.Count, "#5");
337                         }
338                 }
339
340                 [Test]
341                 public void WaitAll_TimeoutWithExceptionsBefore ()
342                 {
343                         CountdownEvent cde = new CountdownEvent (2);
344                         var mre = new ManualResetEvent (false);
345                         var tasks = new[] {
346                                 Task.Factory.StartNew (delegate { try { throw new ApplicationException (); } finally { cde.Signal (); } }),
347                                 Task.Factory.StartNew (delegate { try { throw new ApplicationException (); } finally { cde.Signal (); } }),
348                                 Task.Factory.StartNew (delegate { mre.WaitOne (); })
349                         };
350
351                         Assert.IsTrue (cde.Wait (1000), "#1");
352                         Assert.IsFalse (Task.WaitAll (tasks, 1000), "#2");
353
354                         mre.Set ();
355
356                         try {
357                                 Assert.IsTrue (Task.WaitAll (tasks, 1000), "#3");
358                                 Assert.Fail ("#4");
359                         } catch (AggregateException e) {
360                                 Assert.AreEqual (2, e.InnerExceptions.Count, "#5");
361                         }
362                 }
363
364                 [Test]
365                 public void WaitAll_Cancelled ()
366                 {
367                         var cancelation = new CancellationTokenSource ();
368                         var tasks = new Task[] {
369                                 new Task (delegate { cancelation.Cancel (); }),
370                                 new Task (delegate { }, cancelation.Token)
371                         };
372
373                         tasks[0].Start ();
374
375                         try {
376                                 Task.WaitAll (tasks);
377                                 Assert.Fail ("#1");
378                         } catch (AggregateException e) {
379                                 var inner = (TaskCanceledException) e.InnerException;
380                                 Assert.AreEqual (tasks[1], inner.Task, "#2");
381                         }
382
383                         Assert.IsTrue (tasks[0].IsCompleted, "#3");
384                         Assert.IsTrue (tasks[1].IsCanceled, "#4");
385                 }
386
387 #if NET_4_5             
388                 [Test]
389                 public void WaitAll_CancelledAndTimeout ()
390                 {
391                         var ct = new CancellationToken (true);
392                         var t1 = new Task (() => {}, ct);
393                         var t2 = Task.Delay (3000);
394                         Assert.IsFalse (Task.WaitAll (new[] { t1, t2 }, 10));
395                 }
396 #endif
397
398                 [Test]
399                 public void WaitAllExceptionThenCancelled ()
400                 {
401                         var cancelation = new CancellationTokenSource ();
402                         var tasks = new Task[] {
403                                 new Task (delegate { cancelation.Cancel (); throw new ApplicationException (); }),
404                                 new Task (delegate { }, cancelation.Token)
405                         };
406
407                         tasks[0].Start ();
408
409                         try {
410                                 Task.WaitAll (tasks);
411                                 Assert.Fail ("#1");
412                         } catch (AggregateException e) {
413                                 Assert.That (e.InnerException, Is.TypeOf (typeof (ApplicationException)), "#2");
414                                 var inner = (TaskCanceledException) e.InnerExceptions[1];
415                                 Assert.AreEqual (tasks[1], inner.Task, "#3");
416                         }
417
418                         Assert.IsTrue (tasks[0].IsCompleted, "#4");
419                         Assert.IsTrue (tasks[1].IsCanceled, "#5");
420                 }
421
422                 [Test]
423                 public void WaitAll_StartedUnderWait ()
424                 {
425                         var task1 = new Task (delegate { });
426
427                         ThreadPool.QueueUserWorkItem (delegate {
428                                 // Sleep little to let task to start and hit internal wait
429                                 Thread.Sleep (20);
430                                 task1.Start ();
431                         });
432
433                         Assert.IsTrue (Task.WaitAll (new [] { task1 }, 1000), "#1");
434                 }
435
436                 [Test]
437                 public void CancelBeforeStart ()
438                 {
439                         var src = new CancellationTokenSource ();
440
441                         Task t = new Task (delegate { }, src.Token);
442                         src.Cancel ();
443                         Assert.AreEqual (TaskStatus.Canceled, t.Status, "#1");
444
445                         try {
446                                 t.Start ();
447                                 Assert.Fail ("#2");
448                         } catch (InvalidOperationException) {
449                         }
450                 }
451
452                 [Test]
453                 public void Wait_CancelledTask ()
454                 {
455                         var src = new CancellationTokenSource ();
456
457                         Task t = new Task (delegate { }, src.Token);
458                         src.Cancel ();
459
460                         try {
461                                 t.Wait (1000);
462                                 Assert.Fail ("#1");
463                         } catch (AggregateException e) {
464                                 var details = (TaskCanceledException) e.InnerException;
465                                 Assert.AreEqual (t, details.Task, "#1e");
466                         }
467
468                         try {
469                                 t.Wait ();
470                                 Assert.Fail ("#2");
471                         } catch (AggregateException e) {
472                                 var details = (TaskCanceledException) e.InnerException;
473                                 Assert.AreEqual (t, details.Task, "#2e");
474                                 Assert.IsNull (details.Task.Exception, "#2e2");
475                         }
476                 }
477
478                 [Test]
479                 public void Wait_Inlined ()
480                 {
481                         bool? previouslyQueued = null;
482
483                         var scheduler = new MockScheduler ();
484                         scheduler.TryExecuteTaskInlineHandler += (task, b) => {
485                                 previouslyQueued = b;
486                         };
487
488                         var tf = new TaskFactory (scheduler);
489                         var t = tf.StartNew (() => { });
490                         t.Wait ();
491
492                         Assert.AreEqual (true, previouslyQueued);
493                 }
494
495                 [Test]
496                 public void CreationWhileInitiallyCanceled ()
497                 {
498                         var token = new CancellationToken (true);
499                         var task = new Task (() => { }, token);
500
501                         try {
502                                 task.Start ();
503                                 Assert.Fail ("#1");
504                         } catch (InvalidOperationException) {
505                         }
506
507                         try {
508                                 task.Wait ();
509                                 Assert.Fail ("#2");
510                         } catch (AggregateException e) {
511                                 Assert.That (e.InnerException, Is.TypeOf (typeof (TaskCanceledException)), "#3");
512                         }
513
514                         Assert.IsTrue (task.IsCanceled, "#4");
515                 }
516
517                 [Test]
518                 public void ContinueWithInvalidArguments ()
519                 {
520                         var task = new Task (() => { });
521                         try {
522                                 task.ContinueWith (null);
523                                 Assert.Fail ("#1");
524                         } catch (ArgumentNullException e) {
525                         }
526
527                         try {
528                                 task.ContinueWith (delegate { }, null);
529                                 Assert.Fail ("#2");
530                         } catch (ArgumentNullException e) {
531                         }
532
533                         try {
534                                 task.ContinueWith (delegate { }, TaskContinuationOptions.OnlyOnCanceled | TaskContinuationOptions.NotOnCanceled);
535                                 Assert.Fail ("#3");
536                         } catch (ArgumentOutOfRangeException) {
537                         }
538
539                         try {
540                                 task.ContinueWith (delegate { }, TaskContinuationOptions.OnlyOnRanToCompletion | TaskContinuationOptions.NotOnRanToCompletion);
541                                 Assert.Fail ("#4");
542                         } catch (ArgumentOutOfRangeException) {
543                         }
544                 }
545
546                 [Test]
547                 public void ContinueWithOnAnyTestCase()
548                 {
549                         ParallelTestHelper.Repeat (delegate {
550                                 bool result = false;
551                                 
552                                 Task t = Task.Factory.StartNew(delegate { });
553                                 Task cont = t.ContinueWith(delegate { result = true; }, TaskContinuationOptions.None);
554                                 Assert.IsTrue (t.Wait (2000), "First wait, (status, {0})", t.Status);
555                                 Assert.IsTrue (cont.Wait(2000), "Cont wait, (result, {0}) (parent status, {2}) (status, {1})", result, cont.Status, t.Status);
556                                 Assert.IsNull(cont.Exception, "#1");
557                                 Assert.IsNotNull(cont, "#2");
558                                 Assert.IsTrue(result, "#3");
559                         });
560                 }
561                 
562                 [Test]
563                 public void ContinueWithOnCompletedSuccessfullyTestCase()
564                 {
565                         ParallelTestHelper.Repeat (delegate {
566                                 bool result = false;
567                                 
568                                 Task t = Task.Factory.StartNew(delegate { });
569                                 Task cont = t.ContinueWith(delegate { result = true; }, TaskContinuationOptions.OnlyOnRanToCompletion);
570                                 Assert.IsTrue (t.Wait(1000), "#4");
571                                 Assert.IsTrue (cont.Wait(1000), "#5");
572                                 
573                                 Assert.IsNull(cont.Exception, "#1");
574                                 Assert.IsNotNull(cont, "#2");
575                                 Assert.IsTrue(result, "#3");
576                         });
577                 }
578                 
579                 [Test]
580                 public void ContinueWithOnAbortedTestCase()
581                 {
582                         bool result = false;
583                         bool taskResult = false;
584
585                         CancellationTokenSource src = new CancellationTokenSource ();
586                         Task t = new Task (delegate { taskResult = true; }, src.Token);
587
588                         Task cont = t.ContinueWith (delegate { result = true; },
589                                 TaskContinuationOptions.OnlyOnCanceled | TaskContinuationOptions.ExecuteSynchronously);
590
591                         src.Cancel ();
592
593                         Assert.AreEqual (TaskStatus.Canceled, t.Status, "#1a");
594                         Assert.IsTrue (cont.IsCompleted, "#1b");
595                         Assert.IsTrue (result, "#1c");
596
597                         try {
598                                 t.Start ();
599                                 Assert.Fail ("#2");
600                         } catch (InvalidOperationException) {
601                         }
602
603                         Assert.IsTrue (cont.Wait (1000), "#3");
604
605                         Assert.IsFalse (taskResult, "#4");
606
607                         Assert.IsNull (cont.Exception, "#5");
608                         Assert.AreEqual (TaskStatus.RanToCompletion, cont.Status, "#6");
609                 }
610                 
611                 [Test]
612                 public void ContinueWithOnFailedTestCase()
613                 {
614                         ParallelTestHelper.Repeat (delegate {
615                                 bool result = false;
616                                 
617                                 Task t = Task.Factory.StartNew(delegate { throw new Exception("foo"); });       
618                                 Task cont = t.ContinueWith(delegate { result = true; }, TaskContinuationOptions.OnlyOnFaulted);
619                         
620                                 Assert.IsTrue (cont.Wait(1000), "#0");
621                                 Assert.IsNotNull (t.Exception, "#1");
622                                 Assert.IsNotNull (cont, "#2");
623                                 Assert.IsTrue (result, "#3");
624                         });
625                 }
626
627                 [Test]
628                 public void ContinueWithWithStart ()
629                 {
630                         Task t = new Task<int> (() => 1);
631                         t = t.ContinueWith (l => { });
632                         try {
633                                 t.Start ();
634                                 Assert.Fail ();
635                         } catch (InvalidOperationException) {
636                         }
637                 }
638
639                 [Test]
640                 public void ContinueWithChildren ()
641                 {
642                         ParallelTestHelper.Repeat (delegate {
643                                 bool result = false;
644
645                                 var t = Task.Factory.StartNew (() => Task.Factory.StartNew (() => {}, TaskCreationOptions.AttachedToParent));
646
647                                 var mre = new ManualResetEvent (false);
648                                 t.ContinueWith (l => {
649                                         result = true;
650                                         mre.Set ();
651                                 });
652
653                                 Assert.IsTrue (mre.WaitOne (1000), "#1");
654                                 Assert.IsTrue (result, "#2");
655                         }, 2);
656                 }
657
658                 [Test]
659                 public void ContinueWithDifferentOptionsAreCanceledTest ()
660                 {
661                         var mre = new ManualResetEventSlim ();
662                         var task = Task.Factory.StartNew (() => mre.Wait (200));
663                         var contFailed = task.ContinueWith (t => {}, TaskContinuationOptions.OnlyOnFaulted);
664                         var contCanceled = task.ContinueWith (t => {}, TaskContinuationOptions.OnlyOnCanceled);
665                         var contSuccess = task.ContinueWith (t => {}, TaskContinuationOptions.OnlyOnRanToCompletion);
666
667                         mre.Set ();
668                         contSuccess.Wait (100);
669
670                         Assert.IsTrue (contSuccess.IsCompleted);
671                         Assert.IsTrue (contFailed.IsCompleted);
672                         Assert.IsTrue (contCanceled.IsCompleted);
673                         Assert.IsFalse (contSuccess.IsCanceled);
674                         Assert.IsTrue (contFailed.IsCanceled);
675                         Assert.IsTrue (contCanceled.IsCanceled);
676                 }
677
678                 [Test]
679                 public void MultipleTasks()
680                 {
681                         ParallelTestHelper.Repeat (delegate {
682                                 bool r1 = false, r2 = false, r3 = false;
683                                 
684                                 Task t1 = Task.Factory.StartNew(delegate {
685                                         r1 = true;
686                                 });
687                                 Task t2 = Task.Factory.StartNew(delegate {
688                                         r2 = true;
689                                 });
690                                 Task t3 = Task.Factory.StartNew(delegate {
691                                         r3 = true;
692                                 });
693                                 
694                                 t1.Wait(2000);
695                                 t2.Wait(2000);
696                                 t3.Wait(2000);
697                                 
698                                 Assert.IsTrue(r1, "#1");
699                                 Assert.IsTrue(r2, "#2");
700                                 Assert.IsTrue(r3, "#3");
701                         }, 100);
702                 }
703                 
704                 [Test]
705                 public void WaitChildTestCase()
706                 {
707                         ParallelTestHelper.Repeat (delegate {
708                                 bool r1 = false, r2 = false, r3 = false;
709                                 var mre = new ManualResetEventSlim (false);
710                                 var mreStart = new ManualResetEventSlim (false);
711                                 
712                                 Task t = Task.Factory.StartNew(delegate {
713                                         Task.Factory.StartNew(delegate {
714                                                 mre.Wait (300);
715                                                 r1 = true;
716                                         }, TaskCreationOptions.AttachedToParent);
717                                         Task.Factory.StartNew(delegate {
718                                                 r2 = true;
719                                         }, TaskCreationOptions.AttachedToParent);
720                                         Task.Factory.StartNew(delegate {
721                                                 r3 = true;
722                                         }, TaskCreationOptions.AttachedToParent);
723                                         mreStart.Set ();
724                                 });
725                                 
726                                 mreStart.Wait (300);
727                                 Assert.IsFalse (t.Wait (10), "#0a");
728                                 mre.Set ();
729                                 Assert.IsTrue (t.Wait (500), "#0b");
730                                 Assert.IsTrue(r2, "#1");
731                                 Assert.IsTrue(r3, "#2");
732                                 Assert.IsTrue(r1, "#3");
733                                 Assert.AreEqual (TaskStatus.RanToCompletion, t.Status, "#4");
734                         }, 10);
735                 }
736
737                 Task parent_wfc;
738
739                 [Test]
740                 public void WaitingForChildrenToComplete ()
741                 {
742                         Task nested = null;
743                         var mre = new ManualResetEvent (false);
744
745                         parent_wfc = Task.Factory.StartNew (() => {
746                                 nested = Task.Factory.StartNew (() => {
747                                         Assert.IsTrue (mre.WaitOne (4000), "parent_wfc needs to be set first");
748                                         Assert.IsFalse (parent_wfc.Wait (10), "#1a");
749                                         Assert.AreEqual (TaskStatus.WaitingForChildrenToComplete, parent_wfc.Status, "#1b");
750                                 }, TaskCreationOptions.AttachedToParent).ContinueWith (l => {
751                                         Assert.IsTrue (parent_wfc.Wait (2000), "#2a");
752                                         Assert.AreEqual (TaskStatus.RanToCompletion, parent_wfc.Status, "#2b");                                 
753                                 }, TaskContinuationOptions.ExecuteSynchronously);
754                         });
755
756                         mre.Set ();
757                         Assert.IsTrue (parent_wfc.Wait (2000), "#3");
758                         Assert.IsTrue (nested.Wait (2000), "#4");
759                 }
760
761                 [Test]
762                 public void WaitChildWithContinuationAttachedTest ()
763                 {
764                         bool result = false;
765                         var task = new Task(() =>
766                         {
767                                 Task.Factory.StartNew(() =>     {
768                                         Thread.Sleep (200);
769                                 }, TaskCreationOptions.AttachedToParent).ContinueWith(t => {
770                                         Thread.Sleep (200);
771                                         result = true;
772                                 }, TaskContinuationOptions.AttachedToParent);
773                         });
774                         task.Start();
775                         task.Wait();
776                         Assert.IsTrue (result);
777                 }
778
779                 [Test]
780                 public void WaitChildWithContinuationNotAttachedTest ()
781                 {
782                         var task = new Task(() =>
783                         {
784                                 Task.Factory.StartNew(() =>     {
785                                         Thread.Sleep (200);
786                                 }, TaskCreationOptions.AttachedToParent).ContinueWith(t => {
787                                         Thread.Sleep (3000);
788                                 });
789                         });
790                         task.Start();
791                         Assert.IsTrue (task.Wait(400));
792                 }
793
794                 [Test]
795                 public void WaitChildWithNesting ()
796                 {
797                         var result = false;
798                         var t = Task.Factory.StartNew (() => {
799                                 Task.Factory.StartNew (() => {
800                                         Task.Factory.StartNew (() => {
801                                                 Thread.Sleep (500);
802                                                 result = true;
803                                         }, TaskCreationOptions.AttachedToParent);
804                                 }, TaskCreationOptions.AttachedToParent);
805                         });
806                         Assert.IsTrue (t.Wait (4000), "#1");
807                         Assert.IsTrue (result, "#2");
808                 }
809
810                 [Test]
811                 public void DoubleWaitTest ()
812                 {
813                         ParallelTestHelper.Repeat (delegate {
814                                 var evt = new ManualResetEventSlim ();
815                                 var monitor = new object ();
816                                 int finished = 0;
817                                 var t = Task.Factory.StartNew (delegate {
818                                                 var r = evt.Wait (5000);
819                                                 lock (monitor) {
820                                                         finished ++;
821                                                         Monitor.Pulse (monitor);
822                                                 }
823                                                 return r ? 1 : 10; //1 -> ok, 10 -> evt wait failed
824                                         });
825                                 var cntd = new CountdownEvent (2);
826                                 var cntd2 = new CountdownEvent (2);
827
828                                 int r1 = 0, r2 = 0;
829                                 ThreadPool.QueueUserWorkItem (delegate {
830                                                 cntd.Signal ();
831                                                 if (!t.Wait (1000))
832                                                         r1 = 20; // 20 -> task wait failed
833                                                 else if (t.Result != 1)
834                                                         r1 = 30 + t.Result; // 30 -> task result is bad
835                                                 else
836                                                         r1 = 2; //2 -> ok
837                                                 cntd2.Signal ();
838                                                 lock (monitor) {
839                                                         finished ++;
840                                                         Monitor.Pulse (monitor);
841                                                 }
842                                         });
843                                 ThreadPool.QueueUserWorkItem (delegate {
844                                                 cntd.Signal ();
845                                                 if (!t.Wait (1000))
846                                                         r2 = 40; // 40 -> task wait failed
847                                                 else if (t.Result != 1)
848                                                         r2 = 50 + t.Result; // 50 -> task result is bad
849                                                 else
850                                                         r2 = 3; //3 -> ok
851
852                                                 cntd2.Signal ();
853                                                 lock (monitor) {
854                                                         finished ++;
855                                                         Monitor.Pulse (monitor);
856                                                 }
857                                         });
858                                 Assert.IsTrue (cntd.Wait (2000), "#1");
859                                 evt.Set ();
860                                 Assert.IsTrue (cntd2.Wait (2000), "#2");
861                                 Assert.AreEqual (2, r1, "r1");
862                                 Assert.AreEqual (3, r2, "r2");
863
864                                 // Wait for everything to finish to avoid overloading the tpool
865                                 lock (monitor) {
866                                         while (true) {
867                                                 if (finished == 3)
868                                                         break;
869                                                 else
870                                                         Monitor.Wait (monitor);
871                                         }
872                                 }
873                         }, 10);
874                 }
875
876                 [Test]
877                 public void DoubleTimeoutedWaitTest ()
878                 {
879                         var evt = new ManualResetEventSlim ();
880                         var t = new Task (delegate { });
881                         var cntd = new CountdownEvent (2);
882
883                         bool r1 = false, r2 = false;
884                         ThreadPool.QueueUserWorkItem (delegate { r1 = !t.Wait (100); cntd.Signal (); });
885                         ThreadPool.QueueUserWorkItem (delegate { r2 = !t.Wait (100); cntd.Signal (); });
886
887                         cntd.Wait (2000);
888                         Assert.IsTrue (r1);
889                         Assert.IsTrue (r2);
890                 }
891
892                 [Test]
893                 public void RunSynchronously ()
894                 {
895                         var val = 0;
896                         Task t = new Task (() => { Thread.Sleep (100); val = 1; });
897                         t.RunSynchronously ();
898
899                         Assert.AreEqual (1, val, "#1");
900
901                         t = new Task (() => { Thread.Sleep (0); val = 2; });
902
903                         bool? previouslyQueued = null;
904
905                         var scheduler = new MockScheduler ();
906                         scheduler.TryExecuteTaskInlineHandler += (task, b) => {
907                                 previouslyQueued = b;
908                         };
909
910                         t.RunSynchronously (scheduler);
911
912                         Assert.AreEqual (2, val, "#2");
913                         Assert.AreEqual (false, previouslyQueued, "#2a");
914                 }
915
916                 [Test]
917                 public void RunSynchronouslyArgumentChecks ()
918                 {
919                         Task t = new Task (() => { });
920                         try {
921                                 t.RunSynchronously (null);
922                                 Assert.Fail ("#1");
923                         } catch (ArgumentNullException) {
924                         }
925                 }
926
927                 [Test]
928                 public void RunSynchronously_SchedulerException ()
929                 {
930                         var scheduler = new MockScheduler ();
931                         scheduler.TryExecuteTaskInlineHandler += (task, b) => {
932                                 throw new ApplicationException ();
933                         };
934
935                         Task t = new Task (() => { });
936                         try {
937                                 t.RunSynchronously (scheduler);
938                                 Assert.Fail ();
939                         } catch (Exception e) {
940                                 Assert.AreEqual (t.Exception.InnerException, e);
941                         }
942                 }
943
944                 [Test]
945                 public void RunSynchronouslyWithAttachedChildren ()
946                 {
947                         var result = false;
948                         var t = new Task (() => {
949                                 Task.Factory.StartNew (() => { Thread.Sleep (500); result = true; }, TaskCreationOptions.AttachedToParent);
950                         });
951                         t.RunSynchronously ();
952                         Assert.IsTrue (result);
953                 }
954
955                 [Test]
956                 public void RunSynchronouslyOnContinuation ()
957                 {
958                         Task t = new Task<int> (() => 1);
959                         t = t.ContinueWith (l => { });
960                         try {
961                                 t.RunSynchronously ();
962                                 Assert.Fail ("#1");
963                         } catch (InvalidOperationException) {
964                         }
965                 }
966
967                 [Test]
968                 public void UnobservedExceptionOnFinalizerThreadTest ()
969                 {
970                         bool wasCalled = false;
971                         TaskScheduler.UnobservedTaskException += (o, args) => {
972                                 wasCalled = true;
973                                 args.SetObserved ();
974                         };
975                         var inner = new ApplicationException ();
976                         Thread t = new Thread (delegate () {
977                                         Task.Factory.StartNew (() => { throw inner; });
978                                 });
979                         t.Start ();
980                         t.Join ();
981                         Thread.Sleep (1000);
982                         GC.Collect ();
983                         Thread.Sleep (1000);
984                         GC.WaitForPendingFinalizers ();
985
986                         Assert.IsTrue (wasCalled);
987                 }
988
989                 [Test, ExpectedException (typeof (InvalidOperationException))]
990                 public void StartFinishedTaskTest ()
991                 {
992                         var t = Task.Factory.StartNew (delegate () { });
993                         t.Wait ();
994
995                         t.Start ();
996                 }
997
998                 [Test]
999                 public void Start_NullArgument ()
1000                 {
1001                         var t = new Task (() => { });
1002                         try {
1003                                 t.Start (null);
1004                                 Assert.Fail ();
1005                         } catch (ArgumentNullException) {
1006                         }
1007                 }
1008
1009                 [Test, ExpectedException (typeof (InvalidOperationException))]
1010                 public void DisposeUnstartedTest ()
1011                 {
1012                         var t = new Task (() => { });
1013                         t.Dispose ();
1014                 }
1015
1016                 [Test]
1017                 public void ThrowingUnrelatedCanceledExceptionTest ()
1018                 {
1019                         Task t = new Task (() => {
1020                                 throw new TaskCanceledException ();
1021                         });
1022
1023                         t.RunSynchronously ();
1024                         Assert.IsTrue (t.IsFaulted);
1025                         Assert.IsFalse (t.IsCanceled);
1026                 }
1027
1028                 [Test]
1029                 public void CanceledContinuationExecuteSynchronouslyTest ()
1030                 {
1031                         var source = new CancellationTokenSource();
1032                         var token = source.Token;
1033                         var evt = new ManualResetEventSlim ();
1034                         bool result = false;
1035                         bool thrown = false;
1036
1037                         var task = Task.Factory.StartNew (() => evt.Wait (100));
1038                         var cont = task.ContinueWith (t => result = true, token, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default);
1039
1040                         source.Cancel();
1041                         evt.Set ();
1042                         task.Wait (100);
1043                         try {
1044                                 cont.Wait (100);
1045                         } catch (Exception ex) {
1046                                 thrown = true;
1047                         }
1048
1049                         Assert.IsTrue (task.IsCompleted);
1050                         Assert.IsTrue (cont.IsCanceled);
1051                         Assert.IsFalse (result);
1052                         Assert.IsTrue (thrown);
1053                 }
1054
1055                 [Test]
1056                 public void WhenChildTaskErrorIsThrownParentTaskShouldBeFaulted ()
1057                 {
1058                         Task innerTask = null;
1059                         var testTask = new Task (() =>
1060                         {
1061                                 innerTask = new Task (() => 
1062                                 {
1063                                         throw new InvalidOperationException ();
1064                                 }, TaskCreationOptions.AttachedToParent);
1065                                 innerTask.RunSynchronously ();
1066                         });
1067                         testTask.RunSynchronously ();
1068
1069                         Assert.AreNotEqual (TaskStatus.Running, testTask.Status);
1070                         Assert.IsNotNull (innerTask);
1071                         Assert.IsTrue (innerTask.IsFaulted);
1072                         Assert.IsNotNull (testTask.Exception);
1073                         Assert.IsTrue (testTask.IsFaulted);
1074                         Assert.IsNotNull (innerTask.Exception);
1075                 }
1076                 
1077                 [Test]
1078                 public void WhenChildTaskErrorIsThrownOnlyOnFaultedContinuationShouldExecute ()
1079                 {
1080                         var continuationRan = false;
1081                         var testTask = new Task (() =>
1082                         {
1083                                 var task = new Task (() => 
1084                                 {
1085                                         throw new InvalidOperationException();
1086                                 }, TaskCreationOptions.AttachedToParent);
1087                                 task.RunSynchronously ();
1088                         });
1089                         var onErrorTask = testTask.ContinueWith (x => continuationRan = true, TaskContinuationOptions.OnlyOnFaulted);
1090                         testTask.RunSynchronously ();
1091                         onErrorTask.Wait (100);
1092                         Assert.IsTrue (continuationRan);
1093                 }
1094                 
1095                 [Test]
1096                 public void WhenChildTaskErrorIsThrownNotOnFaultedContinuationShouldNotBeExecuted ()
1097                 {
1098                         var continuationRan = false;
1099                         var testTask = new Task (() =>
1100                         {
1101                                 var task = new Task (() => 
1102                                 {
1103                                         throw new InvalidOperationException();
1104                                 }, TaskCreationOptions.AttachedToParent);
1105                                 task.RunSynchronously();
1106                         });
1107                         var onErrorTask = testTask.ContinueWith (x => continuationRan = true, TaskContinuationOptions.NotOnFaulted);
1108                         testTask.RunSynchronously ();
1109                         Assert.IsTrue (onErrorTask.IsCompleted);
1110                         Assert.IsFalse (onErrorTask.IsFaulted);
1111                         Assert.IsFalse (continuationRan);
1112                 }       
1113                 
1114                 [Test]
1115                 public void WhenChildTaskSeveralLevelsDeepHandlesAggregateExceptionErrorStillBubblesToParent ()
1116                 {
1117                         var continuationRan = false;
1118                         AggregateException e = null;
1119                         var testTask = new Task (() =>
1120                         {
1121                                 var child1 = new Task (() =>
1122                                 {
1123                                         var child2 = new Task (() => 
1124                                         {
1125                                                 throw new InvalidOperationException();
1126                                         }, TaskCreationOptions.AttachedToParent);
1127                                         child2.RunSynchronously ();
1128                                 }, TaskCreationOptions.AttachedToParent);
1129                                 
1130                                 child1.RunSynchronously();
1131                                 e = child1.Exception;
1132                                 child1.Exception.Handle (ex => true);
1133                         });
1134                         var onErrorTask = testTask.ContinueWith (x => continuationRan = true, TaskContinuationOptions.OnlyOnFaulted);
1135                         testTask.RunSynchronously ();
1136                         onErrorTask.Wait (100);
1137                         Assert.IsNotNull (e);
1138                         Assert.IsTrue (continuationRan);
1139                 }
1140                 
1141                 [Test]
1142                 public void AlreadyCompletedChildTaskShouldRunContinuationImmediately ()
1143                 {
1144                         string result = "Failed";
1145                         var testTask = new Task (() => 
1146                         {
1147                                 var child = new Task<string> (() =>
1148                                 {
1149                                         return "Success";
1150                                 }, TaskCreationOptions.AttachedToParent);
1151                                 child.RunSynchronously ();
1152                                 child.ContinueWith (x => { Thread.Sleep (50); result = x.Result; }, TaskContinuationOptions.AttachedToParent | TaskContinuationOptions.NotOnFaulted);
1153                         });
1154                         testTask.RunSynchronously ();
1155
1156                         Assert.AreEqual ("Success", result);
1157                 }
1158
1159                 [Test]
1160                 public void InlineNotTrashingParentRelationship ()
1161                 {
1162                         bool r1 = false, r2 = false;
1163                         var t = new Task (() => {
1164                                 new Task (() => { r1 = true; }, TaskCreationOptions.AttachedToParent).RunSynchronously ();
1165                                 Task.Factory.StartNew (() => { Thread.Sleep (100); r2 = true; }, TaskCreationOptions.AttachedToParent);
1166                         });
1167                         t.RunSynchronously ();
1168
1169                         Assert.IsTrue (r1);
1170                         Assert.IsTrue (r2);
1171                 }
1172
1173                 [Test]
1174                 public void AsyncWaitHandleSet ()
1175                 {
1176                         var task = new TaskFactory ().StartNew (() => { });
1177                         var ar = (IAsyncResult)task;
1178                         Assert.IsFalse (ar.CompletedSynchronously, "#1");
1179                         Assert.IsTrue (ar.AsyncWaitHandle.WaitOne (5000), "#2");
1180                 }
1181
1182                 [Test]
1183                 public void StartOnBrokenScheduler ()
1184                 {
1185                         var t = new Task (delegate { });
1186
1187                         try {
1188                                 t.Start (new ExceptionScheduler ());
1189                                 Assert.Fail ("#1");
1190                         } catch (TaskSchedulerException e) {
1191                                 Assert.AreEqual (TaskStatus.Faulted, t.Status, "#2");
1192                                 Assert.AreSame (e, t.Exception.InnerException, "#3");
1193                                 Assert.IsTrue (e.InnerException is ApplicationException, "#4");
1194                         }
1195                 }
1196
1197 #if NET_4_5
1198                 [Test]
1199                 public void ContinuationOnBrokenScheduler ()
1200                 {
1201                         var s = new ExceptionScheduler ();
1202                         Task t = new Task(delegate {});
1203
1204                         var t2 = t.ContinueWith (delegate {
1205                         }, TaskContinuationOptions.ExecuteSynchronously, s);
1206
1207                         var t3 = t.ContinueWith (delegate {
1208                         }, TaskContinuationOptions.ExecuteSynchronously, s);
1209
1210                         t.Start ();
1211
1212                         try {
1213                                 Assert.IsTrue (t3.Wait (2000), "#0");
1214                                 Assert.Fail ("#1");
1215                         } catch (AggregateException e) {
1216                         }
1217
1218                         Assert.AreEqual (TaskStatus.Faulted, t2.Status, "#2");
1219                         Assert.AreEqual (TaskStatus.Faulted, t3.Status, "#3");
1220                 }
1221
1222                 [Test]
1223                 public void Delay_Invalid ()
1224                 {
1225                         try {
1226                                 Task.Delay (-100);
1227                         } catch (ArgumentOutOfRangeException) {
1228                         }
1229                 }
1230
1231                 [Test]
1232                 public void Delay_Start ()
1233                 {
1234                         var t = Task.Delay (5000);
1235                         try {
1236                                 t.Start ();
1237                         } catch (InvalidOperationException) {
1238                         }
1239                 }
1240
1241                 [Test]
1242                 public void Delay_Simple ()
1243                 {
1244                         var t = Task.Delay (300);
1245                         Assert.IsTrue (TaskStatus.WaitingForActivation == t.Status || TaskStatus.Running == t.Status, "#1");
1246                         Assert.IsTrue (t.Wait (400), "#2");
1247                 }
1248
1249                 [Test]
1250                 public void Delay_Cancelled ()
1251                 {
1252                         var cancelation = new CancellationTokenSource ();
1253
1254                         var t = Task.Delay (5000, cancelation.Token);
1255                         Assert.IsTrue (TaskStatus.WaitingForActivation == t.Status || TaskStatus.Running == t.Status, "#1");
1256                         cancelation.Cancel ();
1257                         try {
1258                                 t.Wait (1000);
1259                                 Assert.Fail ("#2");
1260                         } catch (AggregateException) {
1261                                 Assert.AreEqual (TaskStatus.Canceled, t.Status, "#3");
1262                         }
1263                         
1264                         cancelation = new CancellationTokenSource ();
1265                         t = Task.Delay (Timeout.Infinite, cancelation.Token);
1266                         Assert.AreEqual (TaskStatus.WaitingForActivation, t.Status, "#11");
1267                         cancelation.Cancel ();
1268                         try {
1269                                 t.Wait (1000);
1270                                 Assert.Fail ("#12");
1271                         } catch (AggregateException) {
1272                                 Assert.AreEqual (TaskStatus.Canceled, t.Status, "#13");
1273                         }
1274                 }
1275
1276                 [Test]
1277                 public void Delay_TimeManagement ()
1278                 {
1279                         var delay1 = Task.Delay(50);
1280                         var delay2 = Task.Delay(25);
1281                         Assert.IsTrue (Task.WhenAny(new[] { delay1, delay2 }).Wait (1000));
1282                         Assert.AreEqual (TaskStatus.RanToCompletion, delay2.Status);
1283                 }
1284
1285                 [Test]
1286                 public void WaitAny_WithNull ()
1287                 {
1288                         var tasks = new [] {
1289                                 Task.FromResult (2),
1290                                 null
1291                         };
1292
1293                         try {
1294                                 Task.WaitAny (tasks);
1295                                 Assert.Fail ();
1296                         } catch (ArgumentException) {
1297                         }
1298                 }
1299
1300                 [Test]
1301                 public void WhenAll_Empty ()
1302                 {
1303                         var tasks = new Task[0];
1304
1305                         Task t = Task.WhenAll(tasks);
1306
1307                         Assert.IsTrue(t.Wait(1000), "#1");
1308                 }
1309
1310                 [Test]
1311                 public void WhenAll_WithNull ()
1312                 {
1313                         var tasks = new[] {
1314                                 Task.FromResult (2),
1315                                 null
1316                         };
1317
1318                         try {
1319                                 Task.WhenAll (tasks);
1320                                 Assert.Fail ("#1");
1321                         } catch (ArgumentException) {
1322                         }
1323
1324                         tasks = null;
1325                         try {
1326                                 Task.WhenAll (tasks);
1327                                 Assert.Fail ("#2");
1328                         } catch (ArgumentException) {
1329                         }
1330                 }
1331
1332                 [Test]
1333                 public void WhenAll_Start ()
1334                 {
1335                         Task[] tasks = new[] {
1336                                 Task.FromResult (2),
1337                         };
1338
1339                         var t = Task.WhenAll (tasks);
1340                         Assert.AreEqual (TaskStatus.RanToCompletion, t.Status, "#1");
1341
1342                         try {
1343                                 t.Start ();
1344                                 Assert.Fail ("#2");
1345                         } catch (InvalidOperationException) {
1346                         }
1347
1348                         tasks = new [] {
1349                                 new Task (delegate { }),
1350                         };
1351
1352                         t = Task.WhenAll (tasks);
1353                         Assert.AreEqual (TaskStatus.WaitingForActivation, t.Status, "#11");
1354
1355                         try {
1356                                 t.Start ();
1357                                 Assert.Fail ("#12");
1358                         } catch (InvalidOperationException) {
1359                         }
1360                 }
1361
1362                 [Test]
1363                 public void WhenAll_Cancelled ()
1364                 {
1365                         var cancelation = new CancellationTokenSource ();
1366                         var tasks = new Task[] {
1367                                 new Task (delegate { }),
1368                                 new Task (delegate { }, cancelation.Token)
1369                         };
1370
1371                         cancelation.Cancel ();
1372
1373                         var t = Task.WhenAll (tasks);
1374                         Assert.AreEqual (TaskStatus.WaitingForActivation, t.Status, "#1");
1375                         tasks[0].Start ();
1376
1377                         try {
1378                                 Assert.IsTrue (t.Wait (1000), "#2");
1379                                 Assert.Fail ("#2a");
1380                         } catch (AggregateException e) {
1381                                 Assert.That (e.InnerException, Is.TypeOf (typeof (TaskCanceledException)), "#3");
1382                         }
1383                 }
1384
1385                 [Test]
1386                 public void WhenAll_Faulted ()
1387                 {
1388                         var tcs = new TaskCompletionSource<object> ();
1389                         tcs.SetException (new ApplicationException ());
1390
1391                         var tcs2 = new TaskCompletionSource<object> ();
1392                         tcs2.SetException (new InvalidTimeZoneException ());
1393
1394                         var cancelation = new CancellationTokenSource ();
1395                         var tasks = new Task[] {
1396                                 new Task (delegate { }),
1397                                 new Task (delegate { }, cancelation.Token),
1398                                 tcs.Task,
1399                                 tcs2.Task
1400                         };
1401
1402                         cancelation.Cancel ();
1403
1404                         var t = Task.WhenAll (tasks);
1405                         Assert.AreEqual (TaskStatus.WaitingForActivation, t.Status, "#1");
1406                         tasks[0].Start ();
1407
1408                         try {
1409                                 Assert.IsTrue (t.Wait (1000), "#2");
1410                                 Assert.Fail ("#2a");
1411                         } catch (AggregateException e) {
1412                                 Assert.That (e.InnerException, Is.TypeOf (typeof (ApplicationException)), "#3");
1413                                 Assert.That (e.InnerExceptions[1], Is.TypeOf (typeof (InvalidTimeZoneException)), "#4");
1414                         }
1415                 }
1416
1417                 [Test]
1418                 public void WhenAll ()
1419                 {
1420                         var t1 = new Task (delegate { });
1421                         var t2 = new Task (delegate { t1.Start (); });
1422
1423                         var tasks = new Task[] {
1424                                 t1,
1425                                 t2,
1426                         };
1427
1428                         var t = Task.WhenAll (tasks);
1429                         Assert.AreEqual (TaskStatus.WaitingForActivation, t.Status, "#1");
1430                         t2.Start ();
1431
1432                         Assert.IsTrue (t.Wait (1000), "#2");
1433                 }
1434
1435                 [Test]
1436                 public void WhenAllResult_Empty ()
1437                 {
1438                         var tasks = new Task<int>[0];
1439
1440                         Task<int[]> t = Task.WhenAll(tasks);
1441
1442                         Assert.IsTrue(t.Wait(1000), "#1");
1443                         Assert.IsNotNull(t.Result, "#2");
1444                         Assert.AreEqual(t.Result.Length, 0, "#3");
1445                 }
1446
1447                 [Test]
1448                 public void WhenAllResult_WithNull ()
1449                 {
1450                         var tasks = new[] {
1451                                 Task.FromResult (2),
1452                                 null
1453                         };
1454
1455                         try {
1456                                 Task.WhenAll<int> (tasks);
1457                                 Assert.Fail ("#1");
1458                         } catch (ArgumentException) {
1459                         }
1460
1461                         tasks = null;
1462                         try {
1463                                 Task.WhenAll<int> (tasks);
1464                                 Assert.Fail ("#2");
1465                         } catch (ArgumentException) {
1466                         }
1467                 }
1468
1469                 [Test]
1470                 public void WhenAllResult_Cancelled ()
1471                 {
1472                         var cancelation = new CancellationTokenSource ();
1473                         var tasks = new [] {
1474                                 new Task<int> (delegate { return 9; }),
1475                                 new Task<int> (delegate { return 1; }, cancelation.Token)
1476                         };
1477
1478                         cancelation.Cancel ();
1479
1480                         var t = Task.WhenAll (tasks);
1481                         Assert.AreEqual (TaskStatus.WaitingForActivation, t.Status, "#1");
1482                         tasks[0].Start ();
1483
1484                         try {
1485                                 Assert.IsTrue (t.Wait (1000), "#2");
1486                                 Assert.Fail ("#2a");
1487                         } catch (AggregateException e) {
1488                                 Assert.That (e.InnerException, Is.TypeOf (typeof (TaskCanceledException)), "#3");
1489                         }
1490
1491                         try {
1492                                 var r = t.Result;
1493                                 Assert.Fail ("#4");
1494                         } catch (AggregateException) {
1495                         }
1496                 }
1497
1498                 [Test]
1499                 public void WhenAllResult ()
1500                 {
1501                         var t1 = new Task<string> (delegate { return "a"; });
1502                         var t2 = new Task<string> (delegate { t1.Start (); return "b"; });
1503
1504                         var tasks = new [] {
1505                                 t1,
1506                                 t2,
1507                         };
1508
1509                         var t = Task.WhenAll<string> (tasks);
1510                         Assert.AreEqual (TaskStatus.WaitingForActivation, t.Status, "#1");
1511                         t2.Start ();
1512
1513                         Assert.IsTrue (t.Wait (1000), "#2");
1514                         Assert.AreEqual (2, t.Result.Length, "#3");
1515                         Assert.AreEqual ("a", t.Result[0], "#3a");
1516                         Assert.AreEqual ("b", t.Result[1], "#3b");
1517                 }
1518
1519                 [Test]
1520                 public void WhenAllResult_Completed ()
1521                 {
1522                         var tasks = new[] {
1523                                 Task.FromResult (1),
1524                                 Task.FromResult (2)
1525                         };
1526
1527                         var t = Task.WhenAll<int> (tasks);
1528                         Assert.AreEqual (TaskStatus.RanToCompletion, t.Status, "#1");
1529                         Assert.AreEqual (2, t.Result.Length, "#2");
1530                         Assert.AreEqual (1, t.Result[0], "#2a");
1531                         Assert.AreEqual (2, t.Result[1], "#2b");
1532                 }
1533
1534                 [Test]
1535                 public void WhenAny_WithNull ()
1536                 {
1537                         var tasks = new Task[] {
1538                                 Task.FromResult (2),
1539                                 null
1540                         };
1541
1542                         try {
1543                                 Task.WhenAny (tasks);
1544                                 Assert.Fail ("#1");
1545                         } catch (ArgumentException) {
1546                         }
1547
1548                         tasks = null;
1549                         try {
1550                                 Task.WhenAny (tasks);
1551                                 Assert.Fail ("#2");
1552                         } catch (ArgumentException) {
1553                         }
1554
1555                         try {
1556                                 Task.WhenAny (new Task[0]);
1557                                 Assert.Fail ("#3");
1558                         } catch (ArgumentException) {
1559                         }
1560                 }
1561
1562                 [Test]
1563                 public void WhenAny_Start ()
1564                 {
1565                         Task[] tasks = new[] {
1566                                 Task.FromResult (2),
1567                         };
1568
1569                         var t = Task.WhenAny (tasks);
1570                         Assert.AreEqual (TaskStatus.RanToCompletion, t.Status, "#1");
1571
1572                         try {
1573                                 t.Start ();
1574                                 Assert.Fail ("#2");
1575                         } catch (InvalidOperationException) {
1576                         }
1577
1578                         tasks = new[] {
1579                                 new Task (delegate { }),
1580                         };
1581
1582                         t = Task.WhenAny (tasks);
1583                         Assert.AreEqual (TaskStatus.WaitingForActivation, t.Status, "#11");
1584
1585                         try {
1586                                 t.Start ();
1587                                 Assert.Fail ("#12");
1588                         } catch (InvalidOperationException) {
1589                         }
1590                 }
1591
1592                 [Test]
1593                 public void WhenAny_Cancelled ()
1594                 {
1595                         var cancelation = new CancellationTokenSource ();
1596                         var tasks = new Task[] {
1597                                 new Task (delegate { }),
1598                                 new Task (delegate { }, cancelation.Token)
1599                         };
1600
1601                         cancelation.Cancel ();
1602
1603                         var t = Task.WhenAny (tasks);
1604                         Assert.AreEqual (TaskStatus.RanToCompletion, t.Status, "#1");
1605                         tasks[0].Start ();
1606
1607                         Assert.IsTrue (t.Wait (1000), "#2");
1608                         Assert.AreEqual (TaskStatus.Canceled, t.Result.Status, "#3");
1609                 }
1610
1611                 [Test]
1612                 public void WhenAny_Faulted ()
1613                 {
1614                         var tcs = new TaskCompletionSource<object> ();
1615                         tcs.SetException (new ApplicationException ());
1616
1617                         var tcs2 = new TaskCompletionSource<object> ();
1618                         tcs2.SetException (new InvalidTimeZoneException ());
1619
1620                         var cancelation = new CancellationTokenSource ();
1621                         var tasks = new Task[] {
1622                                 new Task (delegate { }),
1623                                 tcs.Task,
1624                                 new Task (delegate { }, cancelation.Token),
1625                                 tcs2.Task
1626                         };
1627
1628                         cancelation.Cancel ();
1629
1630                         var t = Task.WhenAny (tasks);
1631                         Assert.AreEqual (TaskStatus.RanToCompletion, t.Status, "#1");
1632                         tasks[0].Start ();
1633
1634                         Assert.IsTrue (t.Wait (1000), "#2");
1635                         Assert.IsNull (t.Exception, "#3");
1636
1637                         Assert.That (t.Result.Exception.InnerException, Is.TypeOf (typeof (ApplicationException)), "#4");
1638                 }
1639
1640                 [Test]
1641                 public void WhenAny ()
1642                 {
1643                         var t1 = new Task (delegate { });
1644                         var t2 = new Task (delegate { t1.Start (); });
1645
1646                         var tasks = new Task[] {
1647                                 t1,
1648                                 t2,
1649                         };
1650
1651                         var t = Task.WhenAny (tasks);
1652                         Assert.AreEqual (TaskStatus.WaitingForActivation, t.Status, "#1");
1653                         t2.Start ();
1654
1655                         Assert.IsTrue (t.Wait (1000), "#2");
1656                         Assert.IsNotNull (t.Result, "#3");
1657                 }
1658
1659                 [Test]
1660                 public void WhenAnyResult_WithNull ()
1661                 {
1662                         var tasks = new [] {
1663                                 Task.FromResult (2),
1664                                 null
1665                         };
1666
1667                         try {
1668                                 Task.WhenAny<int> (tasks);
1669                                 Assert.Fail ("#1");
1670                         } catch (ArgumentException) {
1671                         }
1672
1673                         tasks = null;
1674                         try {
1675                                 Task.WhenAny<int> (tasks);
1676                                 Assert.Fail ("#2");
1677                         } catch (ArgumentException) {
1678                         }
1679
1680                         try {
1681                                 Task.WhenAny<short> (new Task<short>[0]);
1682                                 Assert.Fail ("#3");
1683                         } catch (ArgumentException) {
1684                         }
1685                 }
1686
1687                 [Test]
1688                 public void WhenAnyResult_Start ()
1689                 {
1690                         var tasks = new[] {
1691                                 Task.FromResult (2),
1692                         };
1693
1694                         var t = Task.WhenAny<int> (tasks);
1695                         Assert.AreEqual (TaskStatus.RanToCompletion, t.Status, "#1");
1696
1697                         try {
1698                                 t.Start ();
1699                                 Assert.Fail ("#2");
1700                         } catch (InvalidOperationException) {
1701                         }
1702
1703                         tasks = new[] {
1704                                 new Task<int> (delegate { return 55; }),
1705                         };
1706
1707                         t = Task.WhenAny<int> (tasks);
1708                         Assert.AreEqual (TaskStatus.WaitingForActivation, t.Status, "#11");
1709
1710                         try {
1711                                 t.Start ();
1712                                 Assert.Fail ("#12");
1713                         } catch (InvalidOperationException) {
1714                         }
1715                 }
1716
1717                 [Test]
1718                 public void WhenAnyResult_Cancelled ()
1719                 {
1720                         var cancelation = new CancellationTokenSource ();
1721                         var tasks = new [] {
1722                                 new Task<double> (delegate { return 1.1; }),
1723                                 new Task<double> (delegate { return -4.4; }, cancelation.Token)
1724                         };
1725
1726                         cancelation.Cancel ();
1727
1728                         var t = Task.WhenAny<double> (tasks);
1729                         Assert.AreEqual (TaskStatus.RanToCompletion, t.Status, "#1");
1730                         tasks[0].Start ();
1731
1732                         Assert.IsTrue (t.Wait (1000), "#2");
1733                         Assert.AreEqual (TaskStatus.Canceled, t.Result.Status, "#3");
1734                 }
1735
1736                 [Test]
1737                 public void WhenAnyResult_Faulted ()
1738                 {
1739                         var tcs = new TaskCompletionSource<object> ();
1740                         tcs.SetException (new ApplicationException ());
1741
1742                         var tcs2 = new TaskCompletionSource<object> ();
1743                         tcs2.SetException (new InvalidTimeZoneException ());
1744
1745                         var cancelation = new CancellationTokenSource ();
1746                         var tasks = new Task<object>[] {
1747                                 new Task<object> (delegate { return null; }),
1748                                 tcs.Task,
1749                                 new Task<object> (delegate { return ""; }, cancelation.Token),
1750                                 tcs2.Task
1751                         };
1752
1753                         cancelation.Cancel ();
1754
1755                         var t = Task.WhenAny<object> (tasks);
1756                         Assert.AreEqual (TaskStatus.RanToCompletion, t.Status, "#1");
1757                         tasks[0].Start ();
1758
1759                         Assert.IsTrue (t.Wait (1000), "#2");
1760                         Assert.IsNull (t.Exception, "#3");
1761
1762                         Assert.That (t.Result.Exception.InnerException, Is.TypeOf (typeof (ApplicationException)), "#4");
1763                 }
1764
1765                 [Test]
1766                 public void WhenAnyResult ()
1767                 {
1768                         var t1 = new Task<byte> (delegate { return 3; });
1769                         var t2 = new Task<byte> (delegate { t1.Start (); return 2; });
1770
1771                         var tasks = new [] {
1772                                 t1,
1773                                 t2,
1774                         };
1775
1776                         var t = Task.WhenAny<byte> (tasks);
1777                         Assert.AreEqual (TaskStatus.WaitingForActivation, t.Status, "#1");
1778                         t2.Start ();
1779
1780                         Assert.IsTrue (t.Wait (1000), "#2");
1781                         Assert.IsTrue (t.Result.Result > 1, "#3");
1782                 }
1783
1784                 [Test]
1785                 public void ContinueWith_StateValue ()
1786                 {
1787                         var t = Task.Factory.StartNew (l => {
1788                                 Assert.AreEqual (1, l, "a-1");
1789                         }, 1);
1790
1791                         var c = t.ContinueWith ((a, b) => {
1792                                 Assert.AreEqual (t, a, "c-1");
1793                                 Assert.AreEqual (2, b, "c-2");
1794                         }, 2);
1795
1796                         var d = t.ContinueWith ((a, b) => {
1797                                 Assert.AreEqual (t, a, "d-1");
1798                                 Assert.AreEqual (3, b, "d-2");
1799                                 return 77;
1800                         }, 3);
1801
1802                         Assert.IsTrue (d.Wait (1000), "#1");
1803
1804                         Assert.AreEqual (1, t.AsyncState, "#2");
1805                         Assert.AreEqual (2, c.AsyncState, "#3");
1806                         Assert.AreEqual (3, d.AsyncState, "#4");
1807                 }
1808
1809                 [Test]
1810                 public void ContinueWith_StateValueGeneric ()
1811                 {
1812                         var t = Task<int>.Factory.StartNew (l => {
1813                                 Assert.AreEqual (1, l, "a-1");
1814                                 return 80;
1815                         }, 1);
1816
1817                         var c = t.ContinueWith ((a, b) => {
1818                                 Assert.AreEqual (t, a, "c-1");
1819                                 Assert.AreEqual (2, b, "c-2");
1820                                 return "c";
1821                         }, 2);
1822
1823                         var d = t.ContinueWith ((a, b) => {
1824                                 Assert.AreEqual (t, a, "d-1");
1825                                 Assert.AreEqual (3, b, "d-2");
1826                                 return 'd';
1827                         }, 3);
1828
1829                         Assert.IsTrue (d.Wait (1000), "#1");
1830
1831                         Assert.AreEqual (1, t.AsyncState, "#2");
1832                         Assert.AreEqual (80, t.Result, "#2r");
1833                         Assert.AreEqual (2, c.AsyncState, "#3");
1834                         Assert.AreEqual ("c", c.Result, "#3r");
1835                         Assert.AreEqual (3, d.AsyncState, "#4");
1836                         Assert.AreEqual ('d', d.Result, "#3r");
1837                 }
1838
1839                 [Test]
1840                 public void ContinueWith_CustomScheduleRejected ()
1841                 {
1842                         var scheduler = new NonInlineableScheduler ();
1843                         var t = Task.Factory.StartNew (delegate { }).
1844                                 ContinueWith (r => {}, CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously, scheduler);
1845                         
1846                         Assert.IsTrue (t.Wait (5000));
1847                 }
1848
1849                 [Test]
1850                 public void FromResult ()
1851                 {
1852                         var t = Task.FromResult<object> (null);
1853                         Assert.IsTrue (t.IsCompleted, "#1");
1854                         Assert.AreEqual (null, t.Result, "#2");
1855                         t.Dispose ();
1856                         t.Dispose ();
1857                 }
1858
1859                 [Test]
1860                 public void LongRunning ()
1861                 {
1862                         bool? is_tp = null;
1863                         bool? is_bg = null;
1864                         var t = new Task (() => { is_tp = Thread.CurrentThread.IsThreadPoolThread; is_bg = Thread.CurrentThread.IsBackground; });
1865                         t.Start ();
1866                         t.Wait ();
1867                         Assert.IsTrue ((bool)is_tp, "#1");
1868                         Assert.IsTrue ((bool)is_bg, "#2");
1869
1870                         is_tp = null;
1871                         is_bg = null;
1872                         t = new Task (() => { is_tp = Thread.CurrentThread.IsThreadPoolThread; is_bg = Thread.CurrentThread.IsBackground; }, TaskCreationOptions.LongRunning);
1873                         t.Start ();
1874                         t.Wait ();
1875                         Assert.IsFalse ((bool) is_tp, "#11");
1876                         Assert.IsTrue ((bool) is_bg, "#12");
1877                 }
1878
1879                 [Test]
1880                 public void Run_ArgumentCheck ()
1881                 {
1882                         try {
1883                                 Task.Run (null as Action);
1884                                 Assert.Fail ("#1");
1885                         } catch (ArgumentNullException) {
1886                         }
1887                 }
1888
1889                 [Test]
1890                 public void Run ()
1891                 {
1892                         bool ranOnDefaultScheduler = false;
1893                         var t = Task.Run (delegate { ranOnDefaultScheduler = Thread.CurrentThread.IsThreadPoolThread; });
1894                         Assert.AreEqual (TaskCreationOptions.DenyChildAttach, t.CreationOptions, "#1");
1895                         t.Wait ();
1896                         Assert.IsTrue (ranOnDefaultScheduler, "#2");
1897                 }
1898
1899                 [Test]
1900                 public void Run_Cancel ()
1901                 {
1902                         var t = Task.Run (() => 1, new CancellationToken (true));
1903                         try {
1904                                 var r = t.Result;
1905                                 Assert.Fail ("#1");
1906                         } catch (AggregateException) {
1907                         }
1908
1909                         Assert.IsTrue (t.IsCanceled, "#2");
1910                 }
1911
1912                 [Test]
1913                 public void Run_ExistingTaskT ()
1914                 {
1915                         var t = new Task<int> (() => 5);
1916                         var t2 = Task.Run (() => { t.Start (); return t; });
1917
1918                         Assert.IsTrue (t2.Wait (1000), "#1");
1919                         Assert.AreEqual (5, t2.Result, "#2");
1920                 }
1921
1922                 [Test]
1923                 public void Run_ExistingTask ()
1924                 {
1925                         var t = new Task (delegate { throw new Exception ("Foo"); });
1926                         var t2 = Task.Run (() => { t.Start (); return t; });
1927
1928                         try {
1929                                 t2.Wait (1000);
1930                                 Assert.Fail ();
1931                         } catch (Exception) {}
1932
1933                         Assert.AreEqual (TaskStatus.Faulted, t.Status, "#2");
1934                 }
1935
1936                 [Test]
1937                 public void DenyChildAttachTest ()
1938                 {
1939                         var mre = new ManualResetEventSlim ();
1940                         Task nested = null;
1941                         Task parent = Task.Factory.StartNew (() => {
1942                                 nested = Task.Factory.StartNew (() => mre.Wait (2000), TaskCreationOptions.AttachedToParent);
1943                         }, TaskCreationOptions.DenyChildAttach);
1944                         Assert.IsTrue (parent.Wait (1000), "#1");
1945                         mre.Set ();
1946                         Assert.IsTrue (nested.Wait (2000), "#2");
1947                 }
1948
1949                 class SynchronousScheduler : TaskScheduler
1950                 {
1951                         protected override IEnumerable<Task> GetScheduledTasks ()
1952                         {
1953                                 throw new NotImplementedException ();
1954                         }
1955
1956                         protected override void QueueTask (Task task)
1957                         {
1958                                 TryExecuteTaskInline (task, false);
1959                         }
1960
1961                         protected override bool TryExecuteTaskInline (Task task, bool taskWasPreviouslyQueued)
1962                         {
1963                                 return base.TryExecuteTask (task);
1964                         }
1965                 }
1966
1967                 [Test]
1968                 public void HideSchedulerTest ()
1969                 {
1970                         var mre = new ManualResetEventSlim ();
1971                         var ranOnDefault = false;
1972                         var scheduler = new SynchronousScheduler ();
1973
1974                         Task parent = Task.Factory.StartNew (() => {
1975                                 Task.Factory.StartNew (() => {
1976                                         ranOnDefault = Thread.CurrentThread.IsThreadPoolThread;
1977                                         mre.Set ();
1978                                 });
1979                         }, CancellationToken.None, TaskCreationOptions.HideScheduler, scheduler);
1980
1981                         Assert.IsTrue (mre.Wait (1000), "#1");
1982                         Assert.IsTrue (ranOnDefault, "#2");
1983                 }
1984
1985                 [Test]
1986                 public void LazyCancelationTest ()
1987                 {
1988                         var source = new CancellationTokenSource ();
1989                         source.Cancel ();
1990                         var parent = new Task (delegate {});
1991                         var cont = parent.ContinueWith (delegate {}, source.Token, TaskContinuationOptions.LazyCancellation, TaskScheduler.Default);
1992
1993                         Assert.AreNotEqual (TaskStatus.Canceled, cont.Status, "#1");
1994                         parent.Start ();
1995                         try {
1996                                 Assert.IsTrue (cont.Wait (1000), "#2");
1997                                 Assert.Fail ();
1998                         } catch (AggregateException ex) {
1999                                 Assert.That (ex.InnerException, Is.TypeOf (typeof (TaskCanceledException)), "#3");
2000                         }
2001                 }
2002
2003                 [Test]
2004                 public void ChildTaskWithUnscheduledContinuationAttachedToParent ()
2005                 {
2006                         Task inner = null;
2007                         var child = Task.Factory.StartNew (() => {
2008                                 inner  = Task.Run (() => {
2009                                         throw new ApplicationException ();
2010                                 }).ContinueWith (task => { }, TaskContinuationOptions.AttachedToParent | TaskContinuationOptions.NotOnFaulted | TaskContinuationOptions.ExecuteSynchronously);
2011                         });
2012
2013                         int counter = 0;
2014                         var t = child.ContinueWith (t2 => ++counter, TaskContinuationOptions.ExecuteSynchronously);
2015                         Assert.IsTrue (t.Wait (5000), "#1");
2016                         Assert.AreEqual (1, counter, "#2");
2017                         Assert.AreEqual (TaskStatus.RanToCompletion, child.Status, "#3");
2018                         Assert.AreEqual (TaskStatus.Canceled, inner.Status, "#4");
2019                 }
2020
2021                 [Test]
2022                 [Category("NotWorking")]
2023                 public void TaskContinuationChainLeak()
2024                 {
2025                         // Start cranking out tasks, starting each new task upon completion of and from inside the prior task.
2026                         //
2027                         var tester = new TaskContinuationChainLeakTester ();
2028                         tester.Run ();
2029                         tester.TasksPilledUp.WaitOne ();
2030
2031                         // Head task should be out of scope by now.  Manually run the GC and expect that it gets collected.
2032                         // 
2033                         GC.Collect ();
2034                         GC.WaitForPendingFinalizers ();
2035
2036                         try {
2037                                 // It's important that we do the asserting while the task recursion is still going, since that is the 
2038                                 // crux of the problem scenario.
2039                                 //
2040                                 tester.Verify ();
2041                         } finally {
2042                                 tester.Stop ();
2043                         }
2044                 }
2045
2046                 class TaskContinuationChainLeakTester
2047                 {
2048                         volatile bool m_bStop;
2049                         int counter;
2050                         ManualResetEvent mre = new ManualResetEvent (false);
2051                         WeakReference<Task> headTaskWeakRef;
2052
2053                         public ManualResetEvent TasksPilledUp {
2054                                 get {
2055                                         return mre;
2056                                 }
2057                         }
2058
2059                         public void Run ()
2060                         {
2061                                 headTaskWeakRef = new WeakReference<Task> (StartNewTask ());
2062                         }
2063
2064                         public Task StartNewTask ()
2065                         {
2066                                 if (m_bStop)
2067                                         return null;
2068
2069                                 if (++counter == 50)
2070                                         mre.Set ();
2071
2072                                 return Task.Factory.StartNew (DummyWorker).ContinueWith (task => StartNewTask ());
2073                         }
2074
2075                         public void Stop ()
2076                         {
2077                                 m_bStop = true;
2078                         }
2079
2080                         public void Verify ()
2081                         {
2082                                 Task task;
2083                                 Assert.IsFalse (headTaskWeakRef.TryGetTarget (out task));
2084                         }
2085
2086                         void DummyWorker ()
2087                         {
2088                                 Thread.Sleep (0);
2089                         }
2090                 }
2091                 
2092 #endif
2093         }
2094 }
2095 #endif