Merge pull request #1412 from esdrubal/stackframe
[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, ExpectedException (typeof (InvalidOperationException))]
496                 public void CreationWhileInitiallyCanceled ()
497                 {
498                         var token = new CancellationToken (true);
499                         var task = new Task (() => { }, token);
500                         Assert.AreEqual (TaskStatus.Canceled, task.Status);
501                         task.Start ();
502                 }
503
504                 [Test]
505                 public void ContinueWithInvalidArguments ()
506                 {
507                         var task = new Task (() => { });
508                         try {
509                                 task.ContinueWith (null);
510                                 Assert.Fail ("#1");
511                         } catch (ArgumentException) {
512                         }
513
514                         try {
515                                 task.ContinueWith (delegate { }, null);
516                                 Assert.Fail ("#2");
517                         } catch (ArgumentException) {
518                         }
519
520                         try {
521                                 task.ContinueWith (delegate { }, TaskContinuationOptions.OnlyOnCanceled | TaskContinuationOptions.NotOnCanceled);
522                                 Assert.Fail ("#3");
523                         } catch (ArgumentException) {
524                         }
525
526                         try {
527                                 task.ContinueWith (delegate { }, TaskContinuationOptions.OnlyOnRanToCompletion | TaskContinuationOptions.NotOnRanToCompletion);
528                                 Assert.Fail ("#4");
529                         } catch (ArgumentException) {
530                         }
531                 }
532
533                 [Test]
534                 public void ContinueWithOnAnyTestCase()
535                 {
536                         ParallelTestHelper.Repeat (delegate {
537                                 bool result = false;
538                                 
539                                 Task t = Task.Factory.StartNew(delegate { });
540                                 Task cont = t.ContinueWith(delegate { result = true; }, TaskContinuationOptions.None);
541                                 Assert.IsTrue (t.Wait (2000), "First wait, (status, {0})", t.Status);
542                                 Assert.IsTrue (cont.Wait(2000), "Cont wait, (result, {0}) (parent status, {2}) (status, {1})", result, cont.Status, t.Status);
543                                 Assert.IsNull(cont.Exception, "#1");
544                                 Assert.IsNotNull(cont, "#2");
545                                 Assert.IsTrue(result, "#3");
546                         });
547                 }
548                 
549                 [Test]
550                 public void ContinueWithOnCompletedSuccessfullyTestCase()
551                 {
552                         ParallelTestHelper.Repeat (delegate {
553                                 bool result = false;
554                                 
555                                 Task t = Task.Factory.StartNew(delegate { });
556                                 Task cont = t.ContinueWith(delegate { result = true; }, TaskContinuationOptions.OnlyOnRanToCompletion);
557                                 Assert.IsTrue (t.Wait(1000), "#4");
558                                 Assert.IsTrue (cont.Wait(1000), "#5");
559                                 
560                                 Assert.IsNull(cont.Exception, "#1");
561                                 Assert.IsNotNull(cont, "#2");
562                                 Assert.IsTrue(result, "#3");
563                         });
564                 }
565                 
566                 [Test]
567                 public void ContinueWithOnAbortedTestCase()
568                 {
569                         bool result = false;
570                         bool taskResult = false;
571
572                         CancellationTokenSource src = new CancellationTokenSource ();
573                         Task t = new Task (delegate { taskResult = true; }, src.Token);
574
575                         Task cont = t.ContinueWith (delegate { result = true; },
576                                 TaskContinuationOptions.OnlyOnCanceled | TaskContinuationOptions.ExecuteSynchronously);
577
578                         src.Cancel ();
579
580                         Assert.AreEqual (TaskStatus.Canceled, t.Status, "#1a");
581                         Assert.IsTrue (cont.IsCompleted, "#1b");
582                         Assert.IsTrue (result, "#1c");
583
584                         try {
585                                 t.Start ();
586                                 Assert.Fail ("#2");
587                         } catch (InvalidOperationException) {
588                         }
589
590                         Assert.IsTrue (cont.Wait (1000), "#3");
591
592                         Assert.IsFalse (taskResult, "#4");
593
594                         Assert.IsNull (cont.Exception, "#5");
595                         Assert.AreEqual (TaskStatus.RanToCompletion, cont.Status, "#6");
596                 }
597                 
598                 [Test]
599                 public void ContinueWithOnFailedTestCase()
600                 {
601                         ParallelTestHelper.Repeat (delegate {
602                                 bool result = false;
603                                 
604                                 Task t = Task.Factory.StartNew(delegate { throw new Exception("foo"); });       
605                                 Task cont = t.ContinueWith(delegate { result = true; }, TaskContinuationOptions.OnlyOnFaulted);
606                         
607                                 Assert.IsTrue (cont.Wait(1000), "#0");
608                                 Assert.IsNotNull (t.Exception, "#1");
609                                 Assert.IsNotNull (cont, "#2");
610                                 Assert.IsTrue (result, "#3");
611                         });
612                 }
613
614                 [Test]
615                 public void ContinueWithWithStart ()
616                 {
617                         Task t = new Task<int> (() => 1);
618                         t = t.ContinueWith (l => { });
619                         try {
620                                 t.Start ();
621                                 Assert.Fail ();
622                         } catch (InvalidOperationException) {
623                         }
624                 }
625
626                 [Test]
627                 public void ContinueWithChildren ()
628                 {
629                         ParallelTestHelper.Repeat (delegate {
630                                 bool result = false;
631
632                                 var t = Task.Factory.StartNew (() => Task.Factory.StartNew (() => {}, TaskCreationOptions.AttachedToParent));
633
634                                 var mre = new ManualResetEvent (false);
635                                 t.ContinueWith (l => {
636                                         result = true;
637                                         mre.Set ();
638                                 });
639
640                                 Assert.IsTrue (mre.WaitOne (1000), "#1");
641                                 Assert.IsTrue (result, "#2");
642                         }, 2);
643                 }
644
645                 [Test]
646                 public void ContinueWithDifferentOptionsAreCanceledTest ()
647                 {
648                         var mre = new ManualResetEventSlim ();
649                         var task = Task.Factory.StartNew (() => mre.Wait (200));
650                         var contFailed = task.ContinueWith (t => {}, TaskContinuationOptions.OnlyOnFaulted);
651                         var contCanceled = task.ContinueWith (t => {}, TaskContinuationOptions.OnlyOnCanceled);
652                         var contSuccess = task.ContinueWith (t => {}, TaskContinuationOptions.OnlyOnRanToCompletion);
653
654                         mre.Set ();
655                         contSuccess.Wait (100);
656
657                         Assert.IsTrue (contSuccess.IsCompleted);
658                         Assert.IsTrue (contFailed.IsCompleted);
659                         Assert.IsTrue (contCanceled.IsCompleted);
660                         Assert.IsFalse (contSuccess.IsCanceled);
661                         Assert.IsTrue (contFailed.IsCanceled);
662                         Assert.IsTrue (contCanceled.IsCanceled);
663                 }
664
665                 [Test]
666                 public void MultipleTasks()
667                 {
668                         ParallelTestHelper.Repeat (delegate {
669                                 bool r1 = false, r2 = false, r3 = false;
670                                 
671                                 Task t1 = Task.Factory.StartNew(delegate {
672                                         r1 = true;
673                                 });
674                                 Task t2 = Task.Factory.StartNew(delegate {
675                                         r2 = true;
676                                 });
677                                 Task t3 = Task.Factory.StartNew(delegate {
678                                         r3 = true;
679                                 });
680                                 
681                                 t1.Wait(2000);
682                                 t2.Wait(2000);
683                                 t3.Wait(2000);
684                                 
685                                 Assert.IsTrue(r1, "#1");
686                                 Assert.IsTrue(r2, "#2");
687                                 Assert.IsTrue(r3, "#3");
688                         }, 100);
689                 }
690                 
691                 [Test]
692                 public void WaitChildTestCase()
693                 {
694                         ParallelTestHelper.Repeat (delegate {
695                                 bool r1 = false, r2 = false, r3 = false;
696                                 var mre = new ManualResetEventSlim (false);
697                                 var mreStart = new ManualResetEventSlim (false);
698                                 
699                                 Task t = Task.Factory.StartNew(delegate {
700                                         Task.Factory.StartNew(delegate {
701                                                 mre.Wait (300);
702                                                 r1 = true;
703                                         }, TaskCreationOptions.AttachedToParent);
704                                         Task.Factory.StartNew(delegate {
705                                                 r2 = true;
706                                         }, TaskCreationOptions.AttachedToParent);
707                                         Task.Factory.StartNew(delegate {
708                                                 r3 = true;
709                                         }, TaskCreationOptions.AttachedToParent);
710                                         mreStart.Set ();
711                                 });
712                                 
713                                 mreStart.Wait (300);
714                                 Assert.IsFalse (t.Wait (10), "#0a");
715                                 mre.Set ();
716                                 Assert.IsTrue (t.Wait (500), "#0b");
717                                 Assert.IsTrue(r2, "#1");
718                                 Assert.IsTrue(r3, "#2");
719                                 Assert.IsTrue(r1, "#3");
720                                 Assert.AreEqual (TaskStatus.RanToCompletion, t.Status, "#4");
721                         }, 10);
722                 }
723
724                 Task parent_wfc;
725
726                 [Test]
727                 public void WaitingForChildrenToComplete ()
728                 {
729                         Task nested = null;
730                         var mre = new ManualResetEvent (false);
731
732                         parent_wfc = Task.Factory.StartNew (() => {
733                                 nested = Task.Factory.StartNew (() => {
734                                         Assert.IsTrue (mre.WaitOne (4000), "parent_wfc needs to be set first");
735                                         Assert.IsFalse (parent_wfc.Wait (10), "#1a");
736                                         Assert.AreEqual (TaskStatus.WaitingForChildrenToComplete, parent_wfc.Status, "#1b");
737                                 }, TaskCreationOptions.AttachedToParent).ContinueWith (l => {
738                                         Assert.IsTrue (parent_wfc.Wait (2000), "#2a");
739                                         Assert.AreEqual (TaskStatus.RanToCompletion, parent_wfc.Status, "#2b");                                 
740                                 }, TaskContinuationOptions.ExecuteSynchronously);
741                         });
742
743                         mre.Set ();
744                         Assert.IsTrue (parent_wfc.Wait (2000), "#3");
745                         Assert.IsTrue (nested.Wait (2000), "#4");
746                 }
747
748                 [Test]
749                 public void WaitChildWithContinuationAttachedTest ()
750                 {
751                         bool result = false;
752                         var task = new Task(() =>
753                         {
754                                 Task.Factory.StartNew(() =>     {
755                                         Thread.Sleep (200);
756                                 }, TaskCreationOptions.AttachedToParent).ContinueWith(t => {
757                                         Thread.Sleep (200);
758                                         result = true;
759                                 }, TaskContinuationOptions.AttachedToParent);
760                         });
761                         task.Start();
762                         task.Wait();
763                         Assert.IsTrue (result);
764                 }
765
766                 [Test]
767                 public void WaitChildWithContinuationNotAttachedTest ()
768                 {
769                         var task = new Task(() =>
770                         {
771                                 Task.Factory.StartNew(() =>     {
772                                         Thread.Sleep (200);
773                                 }, TaskCreationOptions.AttachedToParent).ContinueWith(t => {
774                                         Thread.Sleep (3000);
775                                 });
776                         });
777                         task.Start();
778                         Assert.IsTrue (task.Wait(400));
779                 }
780
781                 [Test]
782                 public void WaitChildWithNesting ()
783                 {
784                         var result = false;
785                         var t = Task.Factory.StartNew (() => {
786                                 Task.Factory.StartNew (() => {
787                                         Task.Factory.StartNew (() => {
788                                                 Thread.Sleep (500);
789                                                 result = true;
790                                         }, TaskCreationOptions.AttachedToParent);
791                                 }, TaskCreationOptions.AttachedToParent);
792                         });
793                         Assert.IsTrue (t.Wait (4000), "#1");
794                         Assert.IsTrue (result, "#2");
795                 }
796
797                 [Test]
798                 public void DoubleWaitTest ()
799                 {
800                         ParallelTestHelper.Repeat (delegate {
801                                 var evt = new ManualResetEventSlim ();
802                                 var monitor = new object ();
803                                 int finished = 0;
804                                 var t = Task.Factory.StartNew (delegate {
805                                                 var r = evt.Wait (5000);
806                                                 lock (monitor) {
807                                                         finished ++;
808                                                         Monitor.Pulse (monitor);
809                                                 }
810                                                 return r ? 1 : 10; //1 -> ok, 10 -> evt wait failed
811                                         });
812                                 var cntd = new CountdownEvent (2);
813                                 var cntd2 = new CountdownEvent (2);
814
815                                 int r1 = 0, r2 = 0;
816                                 ThreadPool.QueueUserWorkItem (delegate {
817                                                 cntd.Signal ();
818                                                 if (!t.Wait (1000))
819                                                         r1 = 20; // 20 -> task wait failed
820                                                 else if (t.Result != 1)
821                                                         r1 = 30 + t.Result; // 30 -> task result is bad
822                                                 else
823                                                         r1 = 2; //2 -> ok
824                                                 cntd2.Signal ();
825                                                 lock (monitor) {
826                                                         finished ++;
827                                                         Monitor.Pulse (monitor);
828                                                 }
829                                         });
830                                 ThreadPool.QueueUserWorkItem (delegate {
831                                                 cntd.Signal ();
832                                                 if (!t.Wait (1000))
833                                                         r2 = 40; // 40 -> task wait failed
834                                                 else if (t.Result != 1)
835                                                         r2 = 50 + t.Result; // 50 -> task result is bad
836                                                 else
837                                                         r2 = 3; //3 -> ok
838
839                                                 cntd2.Signal ();
840                                                 lock (monitor) {
841                                                         finished ++;
842                                                         Monitor.Pulse (monitor);
843                                                 }
844                                         });
845                                 Assert.IsTrue (cntd.Wait (2000), "#1");
846                                 evt.Set ();
847                                 Assert.IsTrue (cntd2.Wait (2000), "#2");
848                                 Assert.AreEqual (2, r1, "r1");
849                                 Assert.AreEqual (3, r2, "r2");
850
851                                 // Wait for everything to finish to avoid overloading the tpool
852                                 lock (monitor) {
853                                         while (true) {
854                                                 if (finished == 3)
855                                                         break;
856                                                 else
857                                                         Monitor.Wait (monitor);
858                                         }
859                                 }
860                         }, 10);
861                 }
862
863                 [Test]
864                 public void DoubleTimeoutedWaitTest ()
865                 {
866                         var evt = new ManualResetEventSlim ();
867                         var t = new Task (delegate { });
868                         var cntd = new CountdownEvent (2);
869
870                         bool r1 = false, r2 = false;
871                         ThreadPool.QueueUserWorkItem (delegate { r1 = !t.Wait (100); cntd.Signal (); });
872                         ThreadPool.QueueUserWorkItem (delegate { r2 = !t.Wait (100); cntd.Signal (); });
873
874                         cntd.Wait (2000);
875                         Assert.IsTrue (r1);
876                         Assert.IsTrue (r2);
877                 }
878
879                 [Test]
880                 public void RunSynchronously ()
881                 {
882                         var val = 0;
883                         Task t = new Task (() => { Thread.Sleep (100); val = 1; });
884                         t.RunSynchronously ();
885
886                         Assert.AreEqual (1, val, "#1");
887
888                         t = new Task (() => { Thread.Sleep (0); val = 2; });
889
890                         bool? previouslyQueued = null;
891
892                         var scheduler = new MockScheduler ();
893                         scheduler.TryExecuteTaskInlineHandler += (task, b) => {
894                                 previouslyQueued = b;
895                         };
896
897                         t.RunSynchronously (scheduler);
898
899                         Assert.AreEqual (2, val, "#2");
900                         Assert.AreEqual (false, previouslyQueued, "#2a");
901                 }
902
903                 [Test]
904                 public void RunSynchronouslyArgumentChecks ()
905                 {
906                         Task t = new Task (() => { });
907                         try {
908                                 t.RunSynchronously (null);
909                                 Assert.Fail ("#1");
910                         } catch (ArgumentNullException) {
911                         }
912                 }
913
914                 [Test]
915                 public void RunSynchronously_SchedulerException ()
916                 {
917                         var scheduler = new MockScheduler ();
918                         scheduler.TryExecuteTaskInlineHandler += (task, b) => {
919                                 throw new ApplicationException ();
920                         };
921
922                         Task t = new Task (() => { });
923                         try {
924                                 t.RunSynchronously (scheduler);
925                                 Assert.Fail ();
926                         } catch (Exception e) {
927                                 Assert.AreEqual (t.Exception.InnerException, e);
928                         }
929                 }
930
931                 [Test]
932                 public void RunSynchronouslyWithAttachedChildren ()
933                 {
934                         var result = false;
935                         var t = new Task (() => {
936                                 Task.Factory.StartNew (() => { Thread.Sleep (500); result = true; }, TaskCreationOptions.AttachedToParent);
937                         });
938                         t.RunSynchronously ();
939                         Assert.IsTrue (result);
940                 }
941
942                 [Test]
943                 public void RunSynchronouslyOnContinuation ()
944                 {
945                         Task t = new Task<int> (() => 1);
946                         t = t.ContinueWith (l => { });
947                         try {
948                                 t.RunSynchronously ();
949                                 Assert.Fail ("#1");
950                         } catch (InvalidOperationException) {
951                         }
952                 }
953
954                 [Test]
955                 public void UnobservedExceptionOnFinalizerThreadTest ()
956                 {
957                         bool wasCalled = false;
958                         TaskScheduler.UnobservedTaskException += (o, args) => {
959                                 wasCalled = true;
960                                 args.SetObserved ();
961                         };
962                         var inner = new ApplicationException ();
963                         Thread t = new Thread (delegate () {
964                                         Task.Factory.StartNew (() => { throw inner; });
965                                 });
966                         t.Start ();
967                         t.Join ();
968                         Thread.Sleep (1000);
969                         GC.Collect ();
970                         Thread.Sleep (1000);
971                         GC.WaitForPendingFinalizers ();
972
973                         Assert.IsTrue (wasCalled);
974                 }
975
976                 [Test, ExpectedException (typeof (InvalidOperationException))]
977                 public void StartFinishedTaskTest ()
978                 {
979                         var t = Task.Factory.StartNew (delegate () { });
980                         t.Wait ();
981
982                         t.Start ();
983                 }
984
985                 [Test]
986                 public void Start_NullArgument ()
987                 {
988                         var t = Task.Factory.StartNew (delegate () { });
989                         try {
990                                 t.Start (null);
991                                 Assert.Fail ();
992                         } catch (ArgumentNullException) {
993                         }
994                 }
995
996                 [Test, ExpectedException (typeof (InvalidOperationException))]
997                 public void DisposeUnstartedTest ()
998                 {
999                         var t = new Task (() => { });
1000                         t.Dispose ();
1001                 }
1002
1003                 [Test]
1004                 public void ThrowingUnrelatedCanceledExceptionTest ()
1005                 {
1006                         Task t = new Task (() => {
1007                                 throw new TaskCanceledException ();
1008                         });
1009
1010                         t.RunSynchronously ();
1011                         Assert.IsTrue (t.IsFaulted);
1012                         Assert.IsFalse (t.IsCanceled);
1013                 }
1014
1015                 [Test]
1016                 public void CanceledContinuationExecuteSynchronouslyTest ()
1017                 {
1018                         var source = new CancellationTokenSource();
1019                         var token = source.Token;
1020                         var evt = new ManualResetEventSlim ();
1021                         bool result = false;
1022                         bool thrown = false;
1023
1024                         var task = Task.Factory.StartNew (() => evt.Wait (100));
1025                         var cont = task.ContinueWith (t => result = true, token, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default);
1026
1027                         source.Cancel();
1028                         evt.Set ();
1029                         task.Wait (100);
1030                         try {
1031                                 cont.Wait (100);
1032                         } catch (Exception ex) {
1033                                 thrown = true;
1034                         }
1035
1036                         Assert.IsTrue (task.IsCompleted);
1037                         Assert.IsTrue (cont.IsCanceled);
1038                         Assert.IsFalse (result);
1039                         Assert.IsTrue (thrown);
1040                 }
1041
1042                 [Test]
1043                 public void WhenChildTaskErrorIsThrownParentTaskShouldBeFaulted ()
1044                 {
1045                         Task innerTask = null;
1046                         var testTask = new Task (() =>
1047                         {
1048                                 innerTask = new Task (() => 
1049                                 {
1050                                         throw new InvalidOperationException ();
1051                                 }, TaskCreationOptions.AttachedToParent);
1052                                 innerTask.RunSynchronously ();
1053                         });
1054                         testTask.RunSynchronously ();
1055
1056                         Assert.AreNotEqual (TaskStatus.Running, testTask.Status);
1057                         Assert.IsNotNull (innerTask);
1058                         Assert.IsTrue (innerTask.IsFaulted);
1059                         Assert.IsNotNull (testTask.Exception);
1060                         Assert.IsTrue (testTask.IsFaulted);
1061                         Assert.IsNotNull (innerTask.Exception);
1062                 }
1063                 
1064                 [Test]
1065                 public void WhenChildTaskErrorIsThrownOnlyOnFaultedContinuationShouldExecute ()
1066                 {
1067                         var continuationRan = false;
1068                         var testTask = new Task (() =>
1069                         {
1070                                 var task = new Task (() => 
1071                                 {
1072                                         throw new InvalidOperationException();
1073                                 }, TaskCreationOptions.AttachedToParent);
1074                                 task.RunSynchronously ();
1075                         });
1076                         var onErrorTask = testTask.ContinueWith (x => continuationRan = true, TaskContinuationOptions.OnlyOnFaulted);
1077                         testTask.RunSynchronously ();
1078                         onErrorTask.Wait (100);
1079                         Assert.IsTrue (continuationRan);
1080                 }
1081                 
1082                 [Test]
1083                 public void WhenChildTaskErrorIsThrownNotOnFaultedContinuationShouldNotBeExecuted ()
1084                 {
1085                         var continuationRan = false;
1086                         var testTask = new Task (() =>
1087                         {
1088                                 var task = new Task (() => 
1089                                 {
1090                                         throw new InvalidOperationException();
1091                                 }, TaskCreationOptions.AttachedToParent);
1092                                 task.RunSynchronously();
1093                         });
1094                         var onErrorTask = testTask.ContinueWith (x => continuationRan = true, TaskContinuationOptions.NotOnFaulted);
1095                         testTask.RunSynchronously ();
1096                         Assert.IsTrue (onErrorTask.IsCompleted);
1097                         Assert.IsFalse (onErrorTask.IsFaulted);
1098                         Assert.IsFalse (continuationRan);
1099                 }       
1100                 
1101                 [Test]
1102                 public void WhenChildTaskSeveralLevelsDeepHandlesAggregateExceptionErrorStillBubblesToParent ()
1103                 {
1104                         var continuationRan = false;
1105                         AggregateException e = null;
1106                         var testTask = new Task (() =>
1107                         {
1108                                 var child1 = new Task (() =>
1109                                 {
1110                                         var child2 = new Task (() => 
1111                                         {
1112                                                 throw new InvalidOperationException();
1113                                         }, TaskCreationOptions.AttachedToParent);
1114                                         child2.RunSynchronously ();
1115                                 }, TaskCreationOptions.AttachedToParent);
1116                                 
1117                                 child1.RunSynchronously();
1118                                 e = child1.Exception;
1119                                 child1.Exception.Handle (ex => true);
1120                         });
1121                         var onErrorTask = testTask.ContinueWith (x => continuationRan = true, TaskContinuationOptions.OnlyOnFaulted);
1122                         testTask.RunSynchronously ();
1123                         onErrorTask.Wait (100);
1124                         Assert.IsNotNull (e);
1125                         Assert.IsTrue (continuationRan);
1126                 }
1127                 
1128                 [Test]
1129                 public void AlreadyCompletedChildTaskShouldRunContinuationImmediately ()
1130                 {
1131                         string result = "Failed";
1132                         var testTask = new Task (() => 
1133                         {
1134                                 var child = new Task<string> (() =>
1135                                 {
1136                                         return "Success";
1137                                 }, TaskCreationOptions.AttachedToParent);
1138                                 child.RunSynchronously ();
1139                                 child.ContinueWith (x => { Thread.Sleep (50); result = x.Result; }, TaskContinuationOptions.AttachedToParent | TaskContinuationOptions.NotOnFaulted);
1140                         });
1141                         testTask.RunSynchronously ();
1142
1143                         Assert.AreEqual ("Success", result);
1144                 }
1145
1146                 [Test]
1147                 public void InlineNotTrashingParentRelationship ()
1148                 {
1149                         bool r1 = false, r2 = false;
1150                         var t = new Task (() => {
1151                                 new Task (() => { r1 = true; }, TaskCreationOptions.AttachedToParent).RunSynchronously ();
1152                                 Task.Factory.StartNew (() => { Thread.Sleep (100); r2 = true; }, TaskCreationOptions.AttachedToParent);
1153                         });
1154                         t.RunSynchronously ();
1155
1156                         Assert.IsTrue (r1);
1157                         Assert.IsTrue (r2);
1158                 }
1159
1160                 [Test]
1161                 public void AsyncWaitHandleSet ()
1162                 {
1163                         var task = new TaskFactory ().StartNew (() => { });
1164                         var ar = (IAsyncResult)task;
1165                         Assert.IsFalse (ar.CompletedSynchronously, "#1");
1166                         Assert.IsTrue (ar.AsyncWaitHandle.WaitOne (5000), "#2");
1167                 }
1168
1169                 [Test]
1170                 public void StartOnBrokenScheduler ()
1171                 {
1172                         var t = new Task (delegate { });
1173
1174                         try {
1175                                 t.Start (new ExceptionScheduler ());
1176                                 Assert.Fail ("#1");
1177                         } catch (TaskSchedulerException e) {
1178                                 Assert.AreEqual (TaskStatus.Faulted, t.Status, "#2");
1179                                 Assert.AreSame (e, t.Exception.InnerException, "#3");
1180                                 Assert.IsTrue (e.InnerException is ApplicationException, "#4");
1181                         }
1182                 }
1183
1184 #if NET_4_5
1185                 [Test]
1186                 public void ContinuationOnBrokenScheduler ()
1187                 {
1188                         var s = new ExceptionScheduler ();
1189                         Task t = new Task(delegate {});
1190
1191                         var t2 = t.ContinueWith (delegate {
1192                         }, TaskContinuationOptions.ExecuteSynchronously, s);
1193
1194                         var t3 = t.ContinueWith (delegate {
1195                         }, TaskContinuationOptions.ExecuteSynchronously, s);
1196
1197                         t.Start ();
1198
1199                         try {
1200                                 Assert.IsTrue (t3.Wait (2000), "#0");
1201                                 Assert.Fail ("#1");
1202                         } catch (AggregateException e) {
1203                         }
1204
1205                         Assert.AreEqual (TaskStatus.Faulted, t2.Status, "#2");
1206                         Assert.AreEqual (TaskStatus.Faulted, t3.Status, "#3");
1207                 }
1208
1209                 [Test]
1210                 public void Delay_Invalid ()
1211                 {
1212                         try {
1213                                 Task.Delay (-100);
1214                         } catch (ArgumentOutOfRangeException) {
1215                         }
1216                 }
1217
1218                 [Test]
1219                 public void Delay_Start ()
1220                 {
1221                         var t = Task.Delay (5000);
1222                         try {
1223                                 t.Start ();
1224                         } catch (InvalidOperationException) {
1225                         }
1226                 }
1227
1228                 [Test]
1229                 public void Delay_Simple ()
1230                 {
1231                         var t = Task.Delay (300);
1232                         Assert.IsTrue (TaskStatus.WaitingForActivation == t.Status || TaskStatus.Running == t.Status, "#1");
1233                         Assert.IsTrue (t.Wait (400), "#2");
1234                 }
1235
1236                 [Test]
1237                 public void Delay_Cancelled ()
1238                 {
1239                         var cancelation = new CancellationTokenSource ();
1240
1241                         var t = Task.Delay (5000, cancelation.Token);
1242                         Assert.IsTrue (TaskStatus.WaitingForActivation == t.Status || TaskStatus.Running == t.Status, "#1");
1243                         cancelation.Cancel ();
1244                         try {
1245                                 t.Wait (1000);
1246                                 Assert.Fail ("#2");
1247                         } catch (AggregateException) {
1248                                 Assert.AreEqual (TaskStatus.Canceled, t.Status, "#3");
1249                         }
1250                         
1251                         cancelation = new CancellationTokenSource ();
1252                         t = Task.Delay (Timeout.Infinite, cancelation.Token);
1253                         Assert.AreEqual (TaskStatus.WaitingForActivation, t.Status, "#11");
1254                         cancelation.Cancel ();
1255                         try {
1256                                 t.Wait (1000);
1257                                 Assert.Fail ("#12");
1258                         } catch (AggregateException) {
1259                                 Assert.AreEqual (TaskStatus.Canceled, t.Status, "#13");
1260                         }
1261                 }
1262
1263                 [Test]
1264                 public void Delay_TimeManagement ()
1265                 {
1266                         var delay1 = Task.Delay(50);
1267                         var delay2 = Task.Delay(25);
1268                         Assert.IsTrue (Task.WhenAny(new[] { delay1, delay2 }).Wait (1000));
1269                         Assert.AreEqual (TaskStatus.RanToCompletion, delay2.Status);
1270                 }
1271
1272                 [Test]
1273                 public void WaitAny_WithNull ()
1274                 {
1275                         var tasks = new [] {
1276                                 Task.FromResult (2),
1277                                 null
1278                         };
1279
1280                         try {
1281                                 Task.WaitAny (tasks);
1282                                 Assert.Fail ();
1283                         } catch (ArgumentException) {
1284                         }
1285                 }
1286
1287                 [Test]
1288                 public void WhenAll_Empty ()
1289                 {
1290                         var tasks = new Task[0];
1291
1292                         Task t = Task.WhenAll(tasks);
1293
1294                         Assert.IsTrue(t.Wait(1000), "#1");
1295                 }
1296
1297                 [Test]
1298                 public void WhenAll_WithNull ()
1299                 {
1300                         var tasks = new[] {
1301                                 Task.FromResult (2),
1302                                 null
1303                         };
1304
1305                         try {
1306                                 Task.WhenAll (tasks);
1307                                 Assert.Fail ("#1");
1308                         } catch (ArgumentException) {
1309                         }
1310
1311                         tasks = null;
1312                         try {
1313                                 Task.WhenAll (tasks);
1314                                 Assert.Fail ("#2");
1315                         } catch (ArgumentException) {
1316                         }
1317                 }
1318
1319                 [Test]
1320                 public void WhenAll_Start ()
1321                 {
1322                         Task[] tasks = new[] {
1323                                 Task.FromResult (2),
1324                         };
1325
1326                         var t = Task.WhenAll (tasks);
1327                         Assert.AreEqual (TaskStatus.RanToCompletion, t.Status, "#1");
1328
1329                         try {
1330                                 t.Start ();
1331                                 Assert.Fail ("#2");
1332                         } catch (InvalidOperationException) {
1333                         }
1334
1335                         tasks = new [] {
1336                                 new Task (delegate { }),
1337                         };
1338
1339                         t = Task.WhenAll (tasks);
1340                         Assert.AreEqual (TaskStatus.WaitingForActivation, t.Status, "#11");
1341
1342                         try {
1343                                 t.Start ();
1344                                 Assert.Fail ("#12");
1345                         } catch (InvalidOperationException) {
1346                         }
1347                 }
1348
1349                 [Test]
1350                 public void WhenAll_Cancelled ()
1351                 {
1352                         var cancelation = new CancellationTokenSource ();
1353                         var tasks = new Task[] {
1354                                 new Task (delegate { }),
1355                                 new Task (delegate { }, cancelation.Token)
1356                         };
1357
1358                         cancelation.Cancel ();
1359
1360                         var t = Task.WhenAll (tasks);
1361                         Assert.AreEqual (TaskStatus.WaitingForActivation, t.Status, "#1");
1362                         tasks[0].Start ();
1363
1364                         try {
1365                                 Assert.IsTrue (t.Wait (1000), "#2");
1366                                 Assert.Fail ("#2a");
1367                         } catch (AggregateException e) {
1368                                 Assert.That (e.InnerException, Is.TypeOf (typeof (TaskCanceledException)), "#3");
1369                         }
1370                 }
1371
1372                 [Test]
1373                 public void WhenAll_Faulted ()
1374                 {
1375                         var tcs = new TaskCompletionSource<object> ();
1376                         tcs.SetException (new ApplicationException ());
1377
1378                         var tcs2 = new TaskCompletionSource<object> ();
1379                         tcs2.SetException (new InvalidTimeZoneException ());
1380
1381                         var cancelation = new CancellationTokenSource ();
1382                         var tasks = new Task[] {
1383                                 new Task (delegate { }),
1384                                 new Task (delegate { }, cancelation.Token),
1385                                 tcs.Task,
1386                                 tcs2.Task
1387                         };
1388
1389                         cancelation.Cancel ();
1390
1391                         var t = Task.WhenAll (tasks);
1392                         Assert.AreEqual (TaskStatus.WaitingForActivation, t.Status, "#1");
1393                         tasks[0].Start ();
1394
1395                         try {
1396                                 Assert.IsTrue (t.Wait (1000), "#2");
1397                                 Assert.Fail ("#2a");
1398                         } catch (AggregateException e) {
1399                                 Assert.That (e.InnerException, Is.TypeOf (typeof (ApplicationException)), "#3");
1400                                 Assert.That (e.InnerExceptions[1], Is.TypeOf (typeof (InvalidTimeZoneException)), "#4");
1401                         }
1402                 }
1403
1404                 [Test]
1405                 public void WhenAll ()
1406                 {
1407                         var t1 = new Task (delegate { });
1408                         var t2 = new Task (delegate { t1.Start (); });
1409
1410                         var tasks = new Task[] {
1411                                 t1,
1412                                 t2,
1413                         };
1414
1415                         var t = Task.WhenAll (tasks);
1416                         Assert.AreEqual (TaskStatus.WaitingForActivation, t.Status, "#1");
1417                         t2.Start ();
1418
1419                         Assert.IsTrue (t.Wait (1000), "#2");
1420                 }
1421
1422                 [Test]
1423                 public void WhenAllResult_Empty ()
1424                 {
1425                         var tasks = new Task<int>[0];
1426
1427                         Task<int[]> t = Task.WhenAll(tasks);
1428
1429                         Assert.IsTrue(t.Wait(1000), "#1");
1430                         Assert.IsNotNull(t.Result, "#2");
1431                         Assert.AreEqual(t.Result.Length, 0, "#3");
1432                 }
1433
1434                 [Test]
1435                 public void WhenAllResult_WithNull ()
1436                 {
1437                         var tasks = new[] {
1438                                 Task.FromResult (2),
1439                                 null
1440                         };
1441
1442                         try {
1443                                 Task.WhenAll<int> (tasks);
1444                                 Assert.Fail ("#1");
1445                         } catch (ArgumentException) {
1446                         }
1447
1448                         tasks = null;
1449                         try {
1450                                 Task.WhenAll<int> (tasks);
1451                                 Assert.Fail ("#2");
1452                         } catch (ArgumentException) {
1453                         }
1454                 }
1455
1456                 [Test]
1457                 public void WhenAllResult_Cancelled ()
1458                 {
1459                         var cancelation = new CancellationTokenSource ();
1460                         var tasks = new [] {
1461                                 new Task<int> (delegate { return 9; }),
1462                                 new Task<int> (delegate { return 1; }, cancelation.Token)
1463                         };
1464
1465                         cancelation.Cancel ();
1466
1467                         var t = Task.WhenAll (tasks);
1468                         Assert.AreEqual (TaskStatus.WaitingForActivation, t.Status, "#1");
1469                         tasks[0].Start ();
1470
1471                         try {
1472                                 Assert.IsTrue (t.Wait (1000), "#2");
1473                                 Assert.Fail ("#2a");
1474                         } catch (AggregateException e) {
1475                                 Assert.That (e.InnerException, Is.TypeOf (typeof (TaskCanceledException)), "#3");
1476                         }
1477
1478                         try {
1479                                 var r = t.Result;
1480                                 Assert.Fail ("#4");
1481                         } catch (AggregateException) {
1482                         }
1483                 }
1484
1485                 [Test]
1486                 public void WhenAllResult ()
1487                 {
1488                         var t1 = new Task<string> (delegate { return "a"; });
1489                         var t2 = new Task<string> (delegate { t1.Start (); return "b"; });
1490
1491                         var tasks = new [] {
1492                                 t1,
1493                                 t2,
1494                         };
1495
1496                         var t = Task.WhenAll<string> (tasks);
1497                         Assert.AreEqual (TaskStatus.WaitingForActivation, t.Status, "#1");
1498                         t2.Start ();
1499
1500                         Assert.IsTrue (t.Wait (1000), "#2");
1501                         Assert.AreEqual (2, t.Result.Length, "#3");
1502                         Assert.AreEqual ("a", t.Result[0], "#3a");
1503                         Assert.AreEqual ("b", t.Result[1], "#3b");
1504                 }
1505
1506                 [Test]
1507                 public void WhenAllResult_Completed ()
1508                 {
1509                         var tasks = new[] {
1510                                 Task.FromResult (1),
1511                                 Task.FromResult (2)
1512                         };
1513
1514                         var t = Task.WhenAll<int> (tasks);
1515                         Assert.AreEqual (TaskStatus.RanToCompletion, t.Status, "#1");
1516                         Assert.AreEqual (2, t.Result.Length, "#2");
1517                         Assert.AreEqual (1, t.Result[0], "#2a");
1518                         Assert.AreEqual (2, t.Result[1], "#2b");
1519                 }
1520
1521                 [Test]
1522                 public void WhenAny_WithNull ()
1523                 {
1524                         var tasks = new Task[] {
1525                                 Task.FromResult (2),
1526                                 null
1527                         };
1528
1529                         try {
1530                                 Task.WhenAny (tasks);
1531                                 Assert.Fail ("#1");
1532                         } catch (ArgumentException) {
1533                         }
1534
1535                         tasks = null;
1536                         try {
1537                                 Task.WhenAny (tasks);
1538                                 Assert.Fail ("#2");
1539                         } catch (ArgumentException) {
1540                         }
1541
1542                         try {
1543                                 Task.WhenAny (new Task[0]);
1544                                 Assert.Fail ("#3");
1545                         } catch (ArgumentException) {
1546                         }
1547                 }
1548
1549                 [Test]
1550                 public void WhenAny_Start ()
1551                 {
1552                         Task[] tasks = new[] {
1553                                 Task.FromResult (2),
1554                         };
1555
1556                         var t = Task.WhenAny (tasks);
1557                         Assert.AreEqual (TaskStatus.RanToCompletion, t.Status, "#1");
1558
1559                         try {
1560                                 t.Start ();
1561                                 Assert.Fail ("#2");
1562                         } catch (InvalidOperationException) {
1563                         }
1564
1565                         tasks = new[] {
1566                                 new Task (delegate { }),
1567                         };
1568
1569                         t = Task.WhenAny (tasks);
1570                         Assert.AreEqual (TaskStatus.WaitingForActivation, t.Status, "#11");
1571
1572                         try {
1573                                 t.Start ();
1574                                 Assert.Fail ("#12");
1575                         } catch (InvalidOperationException) {
1576                         }
1577                 }
1578
1579                 [Test]
1580                 public void WhenAny_Cancelled ()
1581                 {
1582                         var cancelation = new CancellationTokenSource ();
1583                         var tasks = new Task[] {
1584                                 new Task (delegate { }),
1585                                 new Task (delegate { }, cancelation.Token)
1586                         };
1587
1588                         cancelation.Cancel ();
1589
1590                         var t = Task.WhenAny (tasks);
1591                         Assert.AreEqual (TaskStatus.RanToCompletion, t.Status, "#1");
1592                         tasks[0].Start ();
1593
1594                         Assert.IsTrue (t.Wait (1000), "#2");
1595                         Assert.AreEqual (TaskStatus.Canceled, t.Result.Status, "#3");
1596                 }
1597
1598                 [Test]
1599                 public void WhenAny_Faulted ()
1600                 {
1601                         var tcs = new TaskCompletionSource<object> ();
1602                         tcs.SetException (new ApplicationException ());
1603
1604                         var tcs2 = new TaskCompletionSource<object> ();
1605                         tcs2.SetException (new InvalidTimeZoneException ());
1606
1607                         var cancelation = new CancellationTokenSource ();
1608                         var tasks = new Task[] {
1609                                 new Task (delegate { }),
1610                                 tcs.Task,
1611                                 new Task (delegate { }, cancelation.Token),
1612                                 tcs2.Task
1613                         };
1614
1615                         cancelation.Cancel ();
1616
1617                         var t = Task.WhenAny (tasks);
1618                         Assert.AreEqual (TaskStatus.RanToCompletion, t.Status, "#1");
1619                         tasks[0].Start ();
1620
1621                         Assert.IsTrue (t.Wait (1000), "#2");
1622                         Assert.IsNull (t.Exception, "#3");
1623
1624                         Assert.That (t.Result.Exception.InnerException, Is.TypeOf (typeof (ApplicationException)), "#4");
1625                 }
1626
1627                 [Test]
1628                 public void WhenAny ()
1629                 {
1630                         var t1 = new Task (delegate { });
1631                         var t2 = new Task (delegate { t1.Start (); });
1632
1633                         var tasks = new Task[] {
1634                                 t1,
1635                                 t2,
1636                         };
1637
1638                         var t = Task.WhenAny (tasks);
1639                         Assert.AreEqual (TaskStatus.WaitingForActivation, t.Status, "#1");
1640                         t2.Start ();
1641
1642                         Assert.IsTrue (t.Wait (1000), "#2");
1643                         Assert.IsNotNull (t.Result, "#3");
1644                 }
1645
1646                 [Test]
1647                 public void WhenAnyResult_WithNull ()
1648                 {
1649                         var tasks = new [] {
1650                                 Task.FromResult (2),
1651                                 null
1652                         };
1653
1654                         try {
1655                                 Task.WhenAny<int> (tasks);
1656                                 Assert.Fail ("#1");
1657                         } catch (ArgumentException) {
1658                         }
1659
1660                         tasks = null;
1661                         try {
1662                                 Task.WhenAny<int> (tasks);
1663                                 Assert.Fail ("#2");
1664                         } catch (ArgumentException) {
1665                         }
1666
1667                         try {
1668                                 Task.WhenAny<short> (new Task<short>[0]);
1669                                 Assert.Fail ("#3");
1670                         } catch (ArgumentException) {
1671                         }
1672                 }
1673
1674                 [Test]
1675                 public void WhenAnyResult_Start ()
1676                 {
1677                         var tasks = new[] {
1678                                 Task.FromResult (2),
1679                         };
1680
1681                         var t = Task.WhenAny<int> (tasks);
1682                         Assert.AreEqual (TaskStatus.RanToCompletion, t.Status, "#1");
1683
1684                         try {
1685                                 t.Start ();
1686                                 Assert.Fail ("#2");
1687                         } catch (InvalidOperationException) {
1688                         }
1689
1690                         tasks = new[] {
1691                                 new Task<int> (delegate { return 55; }),
1692                         };
1693
1694                         t = Task.WhenAny<int> (tasks);
1695                         Assert.AreEqual (TaskStatus.WaitingForActivation, t.Status, "#11");
1696
1697                         try {
1698                                 t.Start ();
1699                                 Assert.Fail ("#12");
1700                         } catch (InvalidOperationException) {
1701                         }
1702                 }
1703
1704                 [Test]
1705                 public void WhenAnyResult_Cancelled ()
1706                 {
1707                         var cancelation = new CancellationTokenSource ();
1708                         var tasks = new [] {
1709                                 new Task<double> (delegate { return 1.1; }),
1710                                 new Task<double> (delegate { return -4.4; }, cancelation.Token)
1711                         };
1712
1713                         cancelation.Cancel ();
1714
1715                         var t = Task.WhenAny<double> (tasks);
1716                         Assert.AreEqual (TaskStatus.RanToCompletion, t.Status, "#1");
1717                         tasks[0].Start ();
1718
1719                         Assert.IsTrue (t.Wait (1000), "#2");
1720                         Assert.AreEqual (TaskStatus.Canceled, t.Result.Status, "#3");
1721                 }
1722
1723                 [Test]
1724                 public void WhenAnyResult_Faulted ()
1725                 {
1726                         var tcs = new TaskCompletionSource<object> ();
1727                         tcs.SetException (new ApplicationException ());
1728
1729                         var tcs2 = new TaskCompletionSource<object> ();
1730                         tcs2.SetException (new InvalidTimeZoneException ());
1731
1732                         var cancelation = new CancellationTokenSource ();
1733                         var tasks = new Task<object>[] {
1734                                 new Task<object> (delegate { return null; }),
1735                                 tcs.Task,
1736                                 new Task<object> (delegate { return ""; }, cancelation.Token),
1737                                 tcs2.Task
1738                         };
1739
1740                         cancelation.Cancel ();
1741
1742                         var t = Task.WhenAny<object> (tasks);
1743                         Assert.AreEqual (TaskStatus.RanToCompletion, t.Status, "#1");
1744                         tasks[0].Start ();
1745
1746                         Assert.IsTrue (t.Wait (1000), "#2");
1747                         Assert.IsNull (t.Exception, "#3");
1748
1749                         Assert.That (t.Result.Exception.InnerException, Is.TypeOf (typeof (ApplicationException)), "#4");
1750                 }
1751
1752                 [Test]
1753                 public void WhenAnyResult ()
1754                 {
1755                         var t1 = new Task<byte> (delegate { return 3; });
1756                         var t2 = new Task<byte> (delegate { t1.Start (); return 2; });
1757
1758                         var tasks = new [] {
1759                                 t1,
1760                                 t2,
1761                         };
1762
1763                         var t = Task.WhenAny<byte> (tasks);
1764                         Assert.AreEqual (TaskStatus.WaitingForActivation, t.Status, "#1");
1765                         t2.Start ();
1766
1767                         Assert.IsTrue (t.Wait (1000), "#2");
1768                         Assert.IsTrue (t.Result.Result > 1, "#3");
1769                 }
1770
1771                 [Test]
1772                 public void ContinueWith_StateValue ()
1773                 {
1774                         var t = Task.Factory.StartNew (l => {
1775                                 Assert.AreEqual (1, l, "a-1");
1776                         }, 1);
1777
1778                         var c = t.ContinueWith ((a, b) => {
1779                                 Assert.AreEqual (t, a, "c-1");
1780                                 Assert.AreEqual (2, b, "c-2");
1781                         }, 2);
1782
1783                         var d = t.ContinueWith ((a, b) => {
1784                                 Assert.AreEqual (t, a, "d-1");
1785                                 Assert.AreEqual (3, b, "d-2");
1786                                 return 77;
1787                         }, 3);
1788
1789                         Assert.IsTrue (d.Wait (1000), "#1");
1790
1791                         Assert.AreEqual (1, t.AsyncState, "#2");
1792                         Assert.AreEqual (2, c.AsyncState, "#3");
1793                         Assert.AreEqual (3, d.AsyncState, "#4");
1794                 }
1795
1796                 [Test]
1797                 public void ContinueWith_StateValueGeneric ()
1798                 {
1799                         var t = Task<int>.Factory.StartNew (l => {
1800                                 Assert.AreEqual (1, l, "a-1");
1801                                 return 80;
1802                         }, 1);
1803
1804                         var c = t.ContinueWith ((a, b) => {
1805                                 Assert.AreEqual (t, a, "c-1");
1806                                 Assert.AreEqual (2, b, "c-2");
1807                                 return "c";
1808                         }, 2);
1809
1810                         var d = t.ContinueWith ((a, b) => {
1811                                 Assert.AreEqual (t, a, "d-1");
1812                                 Assert.AreEqual (3, b, "d-2");
1813                                 return 'd';
1814                         }, 3);
1815
1816                         Assert.IsTrue (d.Wait (1000), "#1");
1817
1818                         Assert.AreEqual (1, t.AsyncState, "#2");
1819                         Assert.AreEqual (80, t.Result, "#2r");
1820                         Assert.AreEqual (2, c.AsyncState, "#3");
1821                         Assert.AreEqual ("c", c.Result, "#3r");
1822                         Assert.AreEqual (3, d.AsyncState, "#4");
1823                         Assert.AreEqual ('d', d.Result, "#3r");
1824                 }
1825
1826                 [Test]
1827                 public void ContinueWith_CustomScheduleRejected ()
1828                 {
1829                         var scheduler = new NonInlineableScheduler ();
1830                         var t = Task.Factory.StartNew (delegate { }).
1831                                 ContinueWith (r => {}, CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously, scheduler);
1832                         
1833                         Assert.IsTrue (t.Wait (5000));
1834                 }
1835
1836                 [Test]
1837                 public void FromResult ()
1838                 {
1839                         var t = Task.FromResult<object> (null);
1840                         Assert.IsTrue (t.IsCompleted, "#1");
1841                         Assert.AreEqual (null, t.Result, "#2");
1842                         t.Dispose ();
1843                         t.Dispose ();
1844                 }
1845
1846                 [Test]
1847                 public void LongRunning ()
1848                 {
1849                         bool? is_tp = null;
1850                         bool? is_bg = null;
1851                         var t = new Task (() => { is_tp = Thread.CurrentThread.IsThreadPoolThread; is_bg = Thread.CurrentThread.IsBackground; });
1852                         t.Start ();
1853                         Assert.IsTrue (t.Wait (100));
1854                         Assert.IsTrue ((bool)is_tp, "#1");
1855                         Assert.IsTrue ((bool)is_bg, "#2");
1856
1857                         is_tp = null;
1858                         is_bg = null;
1859                         t = new Task (() => { is_tp = Thread.CurrentThread.IsThreadPoolThread; is_bg = Thread.CurrentThread.IsBackground; }, TaskCreationOptions.LongRunning);
1860                         t.Start ();
1861
1862                         Assert.IsTrue (t.Wait (100));
1863                         Assert.IsFalse ((bool) is_tp, "#11");
1864                         Assert.IsTrue ((bool) is_bg, "#12");
1865                 }
1866
1867                 [Test]
1868                 public void Run_ArgumentCheck ()
1869                 {
1870                         try {
1871                                 Task.Run (null as Action);
1872                                 Assert.Fail ("#1");
1873                         } catch (ArgumentNullException) {
1874                         }
1875                 }
1876
1877                 [Test]
1878                 public void Run ()
1879                 {
1880                         bool ranOnDefaultScheduler = false;
1881                         var t = Task.Run (delegate { ranOnDefaultScheduler = Thread.CurrentThread.IsThreadPoolThread; });
1882                         Assert.AreEqual (TaskCreationOptions.DenyChildAttach, t.CreationOptions, "#1");
1883                         t.Wait ();
1884                         Assert.IsTrue (ranOnDefaultScheduler, "#2");
1885                 }
1886
1887                 [Test]
1888                 public void Run_Cancel ()
1889                 {
1890                         var t = Task.Run (() => 1, new CancellationToken (true));
1891                         try {
1892                                 var r = t.Result;
1893                                 Assert.Fail ("#1");
1894                         } catch (AggregateException) {
1895                         }
1896
1897                         Assert.IsTrue (t.IsCanceled, "#2");
1898                 }
1899
1900                 [Test]
1901                 public void Run_ExistingTaskT ()
1902                 {
1903                         var t = new Task<int> (() => 5);
1904                         var t2 = Task.Run (() => { t.Start (); return t; });
1905
1906                         Assert.IsTrue (t2.Wait (1000), "#1");
1907                         Assert.AreEqual (5, t2.Result, "#2");
1908                 }
1909
1910                 [Test]
1911                 public void Run_ExistingTask ()
1912                 {
1913                         var t = new Task (delegate { throw new Exception ("Foo"); });
1914                         var t2 = Task.Run (() => { t.Start (); return t; });
1915
1916                         try {
1917                                 t2.Wait (1000);
1918                                 Assert.Fail ();
1919                         } catch (Exception) {}
1920
1921                         Assert.AreEqual (TaskStatus.Faulted, t.Status, "#2");
1922                 }
1923
1924                 [Test]
1925                 public void DenyChildAttachTest ()
1926                 {
1927                         var mre = new ManualResetEventSlim ();
1928                         Task nested = null;
1929                         Task parent = Task.Factory.StartNew (() => {
1930                                 nested = Task.Factory.StartNew (() => mre.Wait (2000), TaskCreationOptions.AttachedToParent);
1931                         }, TaskCreationOptions.DenyChildAttach);
1932                         Assert.IsTrue (parent.Wait (1000), "#1");
1933                         mre.Set ();
1934                         Assert.IsTrue (nested.Wait (2000), "#2");
1935                 }
1936
1937                 class SynchronousScheduler : TaskScheduler
1938                 {
1939                         protected override IEnumerable<Task> GetScheduledTasks ()
1940                         {
1941                                 throw new NotImplementedException ();
1942                         }
1943
1944                         protected override void QueueTask (Task task)
1945                         {
1946                                 TryExecuteTaskInline (task, false);
1947                         }
1948
1949                         protected override bool TryExecuteTaskInline (Task task, bool taskWasPreviouslyQueued)
1950                         {
1951                                 return base.TryExecuteTask (task);
1952                         }
1953                 }
1954
1955                 [Test]
1956                 public void HideSchedulerTest ()
1957                 {
1958                         var mre = new ManualResetEventSlim ();
1959                         var ranOnDefault = false;
1960                         var scheduler = new SynchronousScheduler ();
1961
1962                         Task parent = Task.Factory.StartNew (() => {
1963                                 Task.Factory.StartNew (() => {
1964                                         ranOnDefault = Thread.CurrentThread.IsThreadPoolThread;
1965                                         mre.Set ();
1966                                 });
1967                         }, CancellationToken.None, TaskCreationOptions.HideScheduler, scheduler);
1968
1969                         Assert.IsTrue (mre.Wait (1000), "#1");
1970                         Assert.IsTrue (ranOnDefault, "#2");
1971                 }
1972
1973                 [Test]
1974                 public void LazyCancelationTest ()
1975                 {
1976                         var source = new CancellationTokenSource ();
1977                         source.Cancel ();
1978                         var parent = new Task (delegate {});
1979                         var cont = parent.ContinueWith (delegate {}, source.Token, TaskContinuationOptions.LazyCancellation, TaskScheduler.Default);
1980
1981                         Assert.AreNotEqual (TaskStatus.Canceled, cont.Status, "#1");
1982                         parent.Start ();
1983                         try {
1984                                 Assert.IsTrue (cont.Wait (1000), "#2");
1985                                 Assert.Fail ();
1986                         } catch (AggregateException ex) {
1987                                 Assert.That (ex.InnerException, Is.TypeOf (typeof (TaskCanceledException)), "#3");
1988                         }
1989                 }
1990
1991                 [Test]
1992                 public void ChildTaskWithUnscheduledContinuationAttachedToParent ()
1993                 {
1994                         Task inner = null;
1995                         var child = Task.Factory.StartNew (() => {
1996                                 inner  = Task.Run (() => {
1997                                         throw new ApplicationException ();
1998                                 }).ContinueWith (task => { }, TaskContinuationOptions.AttachedToParent | TaskContinuationOptions.NotOnFaulted | TaskContinuationOptions.ExecuteSynchronously);
1999                         });
2000
2001                         int counter = 0;
2002                         var t = child.ContinueWith (t2 => ++counter, TaskContinuationOptions.ExecuteSynchronously);
2003                         Assert.IsTrue (t.Wait (5000), "#1");
2004                         Assert.AreEqual (1, counter, "#2");
2005                         Assert.AreEqual (TaskStatus.RanToCompletion, child.Status, "#3");
2006                         Assert.AreEqual (TaskStatus.Canceled, inner.Status, "#4");
2007                 }
2008
2009                 [Test]
2010                 [Category("NotWorking")]
2011                 public void TaskContinuationChainLeak()
2012                 {
2013                         // Start cranking out tasks, starting each new task upon completion of and from inside the prior task.
2014                         //
2015                         var tester = new TaskContinuationChainLeakTester ();
2016                         tester.Run ();
2017                         tester.TasksPilledUp.WaitOne ();
2018
2019                         // Head task should be out of scope by now.  Manually run the GC and expect that it gets collected.
2020                         // 
2021                         GC.Collect ();
2022                         GC.WaitForPendingFinalizers ();
2023
2024                         try {
2025                                 // It's important that we do the asserting while the task recursion is still going, since that is the 
2026                                 // crux of the problem scenario.
2027                                 //
2028                                 tester.Verify ();
2029                         } finally {
2030                                 tester.Stop ();
2031                         }
2032                 }
2033
2034                 class TaskContinuationChainLeakTester
2035                 {
2036                         volatile bool m_bStop;
2037                         int counter;
2038                         ManualResetEvent mre = new ManualResetEvent (false);
2039                         WeakReference<Task> headTaskWeakRef;
2040
2041                         public ManualResetEvent TasksPilledUp {
2042                                 get {
2043                                         return mre;
2044                                 }
2045                         }
2046
2047                         public void Run ()
2048                         {
2049                                 headTaskWeakRef = new WeakReference<Task> (StartNewTask ());
2050                         }
2051
2052                         public Task StartNewTask ()
2053                         {
2054                                 if (m_bStop)
2055                                         return null;
2056
2057                                 if (++counter == 50)
2058                                         mre.Set ();
2059
2060                                 return Task.Factory.StartNew (DummyWorker).ContinueWith (task => StartNewTask ());
2061                         }
2062
2063                         public void Stop ()
2064                         {
2065                                 m_bStop = true;
2066                         }
2067
2068                         public void Verify ()
2069                         {
2070                                 Task task;
2071                                 Assert.IsFalse (headTaskWeakRef.TryGetTarget (out task));
2072                         }
2073
2074                         void DummyWorker ()
2075                         {
2076                                 Thread.Sleep (0);
2077                         }
2078                 }
2079                 
2080 #endif
2081         }
2082 }
2083 #endif