5 // Jérémie "Garuma" Laval <jeremie.laval@gmail.com>
6 // Marek Safar <marek.safar@gmail.com>
8 // Copyright (c) 2010 Jérémie "Garuma" Laval
9 // Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
11 // Permission is hereby granted, free of charge, to any person obtaining a copy
12 // of this software and associated documentation files (the "Software"), to deal
13 // in the Software without restriction, including without limitation the rights
14 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15 // copies of the Software, and to permit persons to whom the Software is
16 // furnished to do so, subject to the following conditions:
18 // The above copyright notice and this permission notice shall be included in
19 // all copies or substantial portions of the Software.
21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
33 using System
.Threading
;
34 using System
.Threading
.Tasks
;
35 using System
.Collections
.Generic
;
37 using NUnit
.Framework
;
39 namespace MonoTests
.System
.Threading
.Tasks
42 public class TaskFactoryTests
44 class CompletedAsyncResult
: IAsyncResult
46 public object AsyncState
48 get { throw new NotImplementedException (); }
51 public WaitHandle AsyncWaitHandle
53 get { throw new NotImplementedException (); }
56 public bool CompletedSynchronously
58 get { throw new NotImplementedException (); }
61 public bool IsCompleted
67 class TestAsyncResult
: IAsyncResult
69 WaitHandle wh
= new ManualResetEvent (true);
71 public object AsyncState
73 get { throw new NotImplementedException (); }
76 public WaitHandle AsyncWaitHandle
84 public bool CompletedSynchronously
86 get { throw new NotImplementedException (); }
89 public bool IsCompleted
95 class TestScheduler
: TaskScheduler
97 public bool ExecutedInline { get; set; }
99 protected override void QueueTask (Task task
)
101 throw new NotImplementedException ();
104 protected override bool TryDequeue (Task task
)
106 throw new NotImplementedException ();
109 protected override bool TryExecuteTaskInline (Task task
, bool taskWasPreviouslyQueued
)
111 if (taskWasPreviouslyQueued
)
112 throw new ArgumentException ("taskWasPreviouslyQueued");
114 if (task
.Status
!= TaskStatus
.WaitingToRun
)
115 throw new ArgumentException ("task.Status");
117 ExecutedInline
= true;
118 return TryExecuteTask (task
);
121 protected override IEnumerable
<Task
> GetScheduledTasks ()
123 throw new NotImplementedException ();
133 this.factory
= Task
.Factory
;
137 public void StartNewTest ()
140 factory
.StartNew (() => result
= true).Wait ();
141 Assert
.IsTrue (result
);
145 public void NoDefaultScheduler ()
147 Assert
.IsNull (factory
.Scheduler
, "#1");
151 public void ContinueWhenAll_Simple ()
153 var mre
= new ManualResetEventSlim (false);
155 Task
[] tasks
= new Task
[3];
156 tasks
[0] = new Task (() => { Thread.Sleep (0); Assert.IsTrue (mre.Wait (5000)); }
);
157 tasks
[1] = new Task (() => { Assert.IsTrue (mre.Wait (5000)); }
);
158 tasks
[2] = new Task (() => { Assert.IsTrue (mre.Wait (5000)); }
);
161 Task cont
= factory
.ContinueWhenAll (tasks
, ts
=> {
162 Assert
.AreEqual (tasks
, ts
, "#0");
166 foreach (Task t
in tasks
)
171 Assert
.IsTrue (cont
.Wait (3000), "#1");
172 Assert
.IsTrue (ran
, "#2");
176 public void ContinueWhenAll_WithMixedCompletionState ()
178 var mre
= new ManualResetEventSlim ();
179 var task
= Task
.Factory
.StartNew (() => mre
.Wait (1000));
180 var contFailed
= task
.ContinueWith (t
=> {}, TaskContinuationOptions
.OnlyOnFaulted
);
181 var contCanceled
= task
.ContinueWith (t
=> {}, TaskContinuationOptions
.OnlyOnCanceled
);
182 var contSuccess
= task
.ContinueWith (t
=> {}, TaskContinuationOptions
.OnlyOnRanToCompletion
);
185 var cont
= Task
.Factory
.ContinueWhenAll (new Task
[] { contFailed, contCanceled, contSuccess }
, _
=> ran
= true);
191 Assert
.AreEqual (TaskStatus
.RanToCompletion
, cont
.Status
);
195 public void ContinueWhenAll_InvalidArguments ()
198 factory
.ContinueWhenAll (null, delegate { }
);
200 } catch (ArgumentNullException
) {
204 factory
.ContinueWhenAll (new Task
[0], delegate { }
);
206 } catch (ArgumentException
) {
210 factory
.ContinueWhenAll (new Task
[] { null }
, delegate { }
);
212 } catch (ArgumentException
) {
215 var tasks
= new Task
[] {
216 factory
.StartNew (delegate {})
220 factory
.ContinueWhenAll (tasks
, null);
222 } catch (ArgumentNullException
) {
226 factory
.ContinueWhenAll (tasks
, delegate { }
, CancellationToken
.None
, TaskContinuationOptions
.None
, null);
228 } catch (ArgumentNullException
) {
232 factory
.ContinueWhenAll (tasks
, delegate { }
, CancellationToken
.None
, TaskContinuationOptions
.OnlyOnCanceled
, null);
234 } catch (ArgumentNullException
) {
235 } catch (ArgumentOutOfRangeException
) {
240 public void ContinueWhenAll_WithExceptions ()
242 var t1
= Task
.Factory
.StartNew (() => { throw new ApplicationException ("Foo"); }
);
243 var t2
= Task
.Factory
.StartNew (() => { throw new ApplicationException ("Bar"); }
);
245 var cont
= Task
.Factory
.ContinueWhenAll (new[] { t1, t2 }
, delegate {});
248 Assert
.IsTrue (t1
.IsFaulted
);
249 Assert
.IsTrue (t2
.IsFaulted
);
250 Assert
.AreEqual (TaskStatus
.RanToCompletion
, cont
.Status
);
254 public void ContinueWhenAny_Simple ()
256 var t1
= new ManualResetEvent (false);
257 var t2
= new ManualResetEvent (false);
259 var tasks
= new Task
[2] {
260 Task
.Factory
.StartNew (() => { t1.WaitOne (5000); }
),
261 Task
.Factory
.StartNew (() => { t2.WaitOne (5000); }
)
265 var ct
= new CancellationToken ();
266 Task cont
= factory
.ContinueWhenAny (tasks
, t
=> {
267 Assert
.AreEqual (tasks
[0], t
, "#1");
271 Assert
.AreEqual (TaskStatus
.WaitingForActivation
, cont
.Status
, "#2");
275 Assert
.IsTrue (cont
.Wait (3000), "#10");
276 Assert
.IsTrue (ran
, "#11");
282 public void ContinueWhenAny_WithResult ()
284 var tcs
= new TaskCompletionSource
<int>();
286 Task
[] tasks
= new[] { tcs.Task }
;
287 var res
= Task
.Factory
.ContinueWhenAny (tasks
, l
=> 4);
288 Assert
.AreEqual (4, res
.Result
);
292 public void ContinueWhenAny_InvalidArguments ()
295 factory
.ContinueWhenAny (null, delegate { }
);
297 } catch (ArgumentNullException
) {
301 factory
.ContinueWhenAny (new Task
[0], delegate { }
);
303 } catch (ArgumentException
) {
307 factory
.ContinueWhenAny (new Task
[] { null }
, delegate { }
);
309 } catch (ArgumentException
) {
312 var tasks
= new Task
[] {
313 factory
.StartNew (delegate {})
317 factory
.ContinueWhenAny (tasks
, null);
319 } catch (ArgumentNullException
) {
323 factory
.ContinueWhenAny (tasks
, delegate { }
, CancellationToken
.None
, TaskContinuationOptions
.None
, null);
325 } catch (ArgumentNullException
) {
329 factory
.ContinueWhenAny (tasks
, delegate { }
, CancellationToken
.None
, TaskContinuationOptions
.OnlyOnCanceled
, null);
331 } catch (ArgumentNullException
) {
332 } catch (ArgumentOutOfRangeException
) {
337 public void FromAsyncBeginInvoke_WithResult ()
341 Func
<int, int> func
= (i
) => {
342 Assert
.IsTrue (Thread
.CurrentThread
.IsThreadPoolThread
);
343 result
= true; return i
+ 3;
346 var task
= factory
.FromAsync
<int, int> (func
.BeginInvoke
, func
.EndInvoke
, 1, "state", TaskCreationOptions
.AttachedToParent
);
347 Assert
.IsTrue (task
.Wait (5000), "#1");
348 Assert
.IsTrue (result
, "#2");
349 Assert
.AreEqual (4, task
.Result
, "#3");
350 Assert
.AreEqual ("state", (string) task
.AsyncState
, "#4");
351 Assert
.AreEqual (TaskCreationOptions
.AttachedToParent
, task
.CreationOptions
, "#5");
355 public void FromAsyncBeginMethod_DirectResult ()
358 bool continuationTest
= false;
360 Func
<int, int> func
= (i
) => { result = true; return i + 3; }
;
361 Task
<int> task
= factory
.FromAsync
<int> (func
.BeginInvoke (1, delegate { }
, null), func
.EndInvoke
);
362 var cont
= task
.ContinueWith (_
=> continuationTest
= true, TaskContinuationOptions
.ExecuteSynchronously
);
366 Assert
.IsTrue (result
);
367 Assert
.IsTrue (continuationTest
);
368 Assert
.AreEqual (4, task
.Result
);
372 public void FromAsyncBeginMethod_Exception ()
375 bool continuationTest
= false;
377 Func
<int, int> func
= (i
) => { result = true; throw new ApplicationException ("bleh"); }
;
378 Task
<int> task
= factory
.FromAsync
<int, int> (func
.BeginInvoke
, func
.EndInvoke
, 1, null);
379 var cont
= task
.ContinueWith (_
=> continuationTest
= true, TaskContinuationOptions
.ExecuteSynchronously
);
383 Assert
.IsTrue (cont
.Wait (2000), "#1");
385 Assert
.IsTrue (result
);
386 Assert
.IsTrue (continuationTest
);
387 Assert
.IsNotNull (task
.Exception
);
388 var agg
= task
.Exception
;
389 Assert
.AreEqual (1, agg
.InnerExceptions
.Count
);
390 Assert
.That (agg
.InnerExceptions
[0], Is
.TypeOf (typeof (ApplicationException
)));
391 Assert
.AreEqual (TaskStatus
.Faulted
, task
.Status
);
396 } catch (AggregateException
) {
401 public void FromAsync_ArgumentsCheck ()
403 var result
= new CompletedAsyncResult ();
405 factory
.FromAsync (null, l
=> { }
);
407 } catch (ArgumentNullException
) {
411 factory
.FromAsync (result
, null);
413 } catch (ArgumentNullException
) {
417 factory
.FromAsync (result
, l
=> { }
, TaskCreationOptions
.LongRunning
);
419 } catch (ArgumentOutOfRangeException
) {
423 factory
.FromAsync (result
, l
=> { }
, TaskCreationOptions
.PreferFairness
);
425 } catch (ArgumentOutOfRangeException
) {
429 factory
.FromAsync (result
, l
=> { }
, TaskCreationOptions
.None
, null);
431 } catch (ArgumentNullException
) {
435 factory
.FromAsync (null, l
=> { }
, null, TaskCreationOptions
.None
);
437 } catch (ArgumentNullException
) {
441 factory
.FromAsync ((a
, b
) => null, l
=> { }
, null, TaskCreationOptions
.LongRunning
);
443 } catch (ArgumentOutOfRangeException
) {
448 [Category ("MacNotWorking")] // Randomly fails - https://bugzilla.xamarin.com/show_bug.cgi?id=51255
449 public void FromAsync_Completed ()
451 var completed
= new CompletedAsyncResult ();
454 Action
<IAsyncResult
> end
= l
=> {
455 Assert
.IsFalse (Thread
.CurrentThread
.IsThreadPoolThread
, "#2");
456 valid
= l
== completed
;
458 Task task
= factory
.FromAsync (completed
, end
);
459 Assert
.IsTrue (valid
== true, "#1");
463 public void FromAsync_CompletedWithException ()
465 var completed
= new CompletedAsyncResult ();
467 Action
<IAsyncResult
> end
= l
=> {
468 throw new ApplicationException ();
470 Task task
= factory
.FromAsync (completed
, end
);
471 Assert
.AreEqual (TaskStatus
.Faulted
, task
.Status
, "#1");
475 public void FromAsync_CompletedCanceled ()
477 var completed
= new CompletedAsyncResult ();
479 Action
<IAsyncResult
> end
= l
=> {
480 throw new OperationCanceledException ();
482 Task task
= factory
.FromAsync (completed
, end
);
483 Assert
.AreEqual (TaskStatus
.Canceled
, task
.Status
, "#1");
484 Assert
.IsNull (task
.Exception
, "#2");
488 public void FromAsync_SimpleAsyncResult ()
490 var result
= new TestAsyncResult ();
493 var task
= factory
.FromAsync (result
, l
=> {
497 Assert
.IsTrue (task
.Wait (1000), "#1");
498 Assert
.IsTrue (called
, "#2");
502 public void FromAsync_ResultException ()
504 var result
= new TestAsyncResult ();
506 var task
= factory
.FromAsync (result
, l
=> {
507 throw new ApplicationException ();
511 Assert
.IsFalse (task
.Wait (1000), "#1");
512 } catch (AggregateException
) {
515 Assert
.AreEqual (TaskStatus
.Faulted
, task
.Status
, "#2");
519 public void FromAsync_ReturnInt ()
521 var result
= new TestAsyncResult ();
524 var task
= factory
.FromAsync
<int> (result
, l
=> {
529 Assert
.IsTrue (task
.Wait (1000), "#1");
530 Assert
.IsTrue (called
, "#2");
531 Assert
.AreEqual (4, task
.Result
, "#3");
535 public void FromAsync_Scheduler_Explicit ()
537 var result
= new TestAsyncResult ();
539 var scheduler
= new TestScheduler ();
541 var task
= factory
.FromAsync (result
, l
=> {
543 }, TaskCreationOptions
.None
, scheduler
);
545 Assert
.IsTrue (task
.Wait (5000), "#1");
546 Assert
.IsTrue (called
, "#2");
547 Assert
.IsTrue (scheduler
.ExecutedInline
, "#3");
551 public void FromAsync_Scheduler_Implicit ()
553 var result
= new TestAsyncResult ();
555 var scheduler
= new TestScheduler ();
557 factory
= new TaskFactory (scheduler
);
559 Task task
= factory
.FromAsync (result
, l
=> {
560 Assert
.IsTrue (Thread
.CurrentThread
.IsThreadPoolThread
, "#6");
562 }, TaskCreationOptions
.AttachedToParent
);
564 Assert
.AreEqual (TaskCreationOptions
.AttachedToParent
, task
.CreationOptions
, "#1");
565 Assert
.IsNull (task
.AsyncState
, "#2");
566 Assert
.IsTrue (task
.Wait (5000), "#3");
567 Assert
.IsTrue (called
, "#4");
568 Assert
.IsTrue (scheduler
.ExecutedInline
, "#5");
572 public void FromAsync_BeginCallback ()
575 bool called2
= false;
577 var task
= factory
.FromAsync (
582 if ((TaskCreationOptions
) c
!= TaskCreationOptions
.AttachedToParent
)
585 Assert
.IsFalse (Thread
.CurrentThread
.IsThreadPoolThread
, "#12");
588 var ar
= Task
.CompletedTask
;
595 "h", TaskCreationOptions
.AttachedToParent
);
597 Assert
.AreEqual (TaskCreationOptions
.None
, task
.CreationOptions
, "#1");
598 Assert
.AreEqual (TaskCreationOptions
.AttachedToParent
, (TaskCreationOptions
) task
.AsyncState
, "#2");
599 Assert
.IsTrue (task
.Wait (5000), "#3");
600 Assert
.IsTrue (called
, "#4");
601 Assert
.IsTrue (called2
, "#5");
605 public void StartNewCancelled ()
607 var ct
= new CancellationToken (true);
609 var task
= factory
.StartNew (() => Assert
.Fail ("Should never be called"), ct
);
613 } catch (InvalidOperationException
) {
619 } catch (AggregateException e
) {
620 Assert
.That (e
.InnerException
, Is
.TypeOf (typeof (TaskCanceledException
)), "#3");
623 Assert
.IsTrue (task
.IsCanceled
, "#4");