Merge pull request #4169 from evincarofautumn/fix-xmm-scanning-mac-x86
[mono.git] / mcs / class / corlib / Test / System.Threading.Tasks / TaskFactoryTest.cs
1 //
2 // TaskFactoryTest.cs
3 //
4 // Authors:
5 //       Jérémie "Garuma" Laval <jeremie.laval@gmail.com>
6 //       Marek Safar <marek.safar@gmail.com>
7 // 
8 // Copyright (c) 2010 Jérémie "Garuma" Laval
9 // Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
10 //
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:
17 //
18 // The above copyright notice and this permission notice shall be included in
19 // all copies or substantial portions of the Software.
20 //
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
27 // THE SOFTWARE.
28 //
29 //
30
31
32 using System;
33 using System.Threading;
34 using System.Threading.Tasks;
35 using System.Collections.Generic;
36
37 using NUnit.Framework;
38
39 namespace MonoTests.System.Threading.Tasks
40 {
41         [TestFixture]
42         public class TaskFactoryTests
43         {
44                 class CompletedAsyncResult : IAsyncResult
45                 {
46                         public object AsyncState
47                         {
48                                 get { throw new NotImplementedException (); }
49                         }
50
51                         public WaitHandle AsyncWaitHandle
52                         {
53                                 get { throw new NotImplementedException (); }
54                         }
55
56                         public bool CompletedSynchronously
57                         {
58                                 get { throw new NotImplementedException (); }
59                         }
60
61                         public bool IsCompleted
62                         {
63                                 get { return true; }
64                         }
65                 }
66
67                 class TestAsyncResult : IAsyncResult
68                 {
69                         WaitHandle wh = new ManualResetEvent (true);
70
71                         public object AsyncState
72                         {
73                                 get { throw new NotImplementedException (); }
74                         }
75
76                         public WaitHandle AsyncWaitHandle
77                         {
78                                 get
79                                 {
80                                         return wh;
81                                 }
82                         }
83
84                         public bool CompletedSynchronously
85                         {
86                                 get { throw new NotImplementedException (); }
87                         }
88
89                         public bool IsCompleted
90                         {
91                                 get { return false; }
92                         }
93                 }
94
95                 class TestScheduler : TaskScheduler
96                 {
97                         public bool ExecutedInline { get; set; }
98
99                         protected override void QueueTask (Task task)
100                         {
101                                 throw new NotImplementedException ();
102                         }
103
104                         protected override bool TryDequeue (Task task)
105                         {
106                                 throw new NotImplementedException ();
107                         }
108
109                         protected override bool TryExecuteTaskInline (Task task, bool taskWasPreviouslyQueued)
110                         {
111                                 if (taskWasPreviouslyQueued)
112                                         throw new ArgumentException ("taskWasPreviouslyQueued");
113
114                                 if (task.Status != TaskStatus.WaitingToRun)
115                                         throw new ArgumentException ("task.Status");
116
117                                 ExecutedInline = true;
118                                 return TryExecuteTask (task);
119                         }
120
121                         protected override IEnumerable<Task> GetScheduledTasks ()
122                         {
123                                 throw new NotImplementedException ();
124                         }
125                 }
126
127
128                 TaskFactory factory;
129
130                 [SetUp]
131                 public void Setup ()
132                 {
133                         this.factory = Task.Factory;
134                 }
135
136                 [Test]
137                 public void StartNewTest ()
138                 {
139                         bool result = false;
140                         factory.StartNew (() => result = true).Wait ();
141                         Assert.IsTrue (result);
142                 }
143
144                 [Test]
145                 public void NoDefaultScheduler ()
146                 {
147                         Assert.IsNull (factory.Scheduler, "#1");
148                 }
149
150                 [Test]
151                 public void ContinueWhenAll_Simple ()
152                 {
153                         var mre = new ManualResetEventSlim (false);
154
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)); });
159
160                         bool ran = false;
161                         Task cont = factory.ContinueWhenAll (tasks, ts => {
162                                 Assert.AreEqual (tasks, ts, "#0");
163                                 ran = true;
164                         });
165
166                         foreach (Task t in tasks)
167                                 t.Start ();
168
169                         mre.Set ();
170
171                         Assert.IsTrue (cont.Wait (3000), "#1");
172                         Assert.IsTrue (ran, "#2");
173                 }
174
175                 [Test]
176                 public void ContinueWhenAll_WithMixedCompletionState ()
177                 {
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);
183                         bool ran = false;
184
185                         var cont = Task.Factory.ContinueWhenAll (new Task[] { contFailed, contCanceled, contSuccess }, _ => ran = true);
186
187                         mre.Set ();
188                         cont.Wait (3000);
189
190                         Assert.IsTrue (ran);
191                         Assert.AreEqual (TaskStatus.RanToCompletion, cont.Status);
192                 }
193
194                 [Test]
195                 public void ContinueWhenAll_InvalidArguments ()
196                 {
197                         try {
198                                 factory.ContinueWhenAll (null, delegate { });
199                                 Assert.Fail ("#1");
200                         } catch (ArgumentNullException) {
201                         }
202
203                         try {
204                                 factory.ContinueWhenAll (new Task[0], delegate { });
205                                 Assert.Fail ("#2");
206                         } catch (ArgumentException) {
207                         }
208
209                         try {
210                                 factory.ContinueWhenAll (new Task[] { null }, delegate { });
211                                 Assert.Fail ("#3");
212                         } catch (ArgumentException) {
213                         }
214
215                         var tasks = new Task [] {
216                                 factory.StartNew (delegate {})
217                         };
218
219                         try {
220                                 factory.ContinueWhenAll (tasks, null);
221                                 Assert.Fail ("#4");
222                         } catch (ArgumentNullException) {
223                         }
224
225                         try {
226                                 factory.ContinueWhenAll (tasks, delegate { }, CancellationToken.None, TaskContinuationOptions.None, null);
227                                 Assert.Fail ("#5");
228                         } catch (ArgumentNullException) {
229                         }
230
231                         try {
232                                 factory.ContinueWhenAll (tasks, delegate { }, CancellationToken.None, TaskContinuationOptions.OnlyOnCanceled, null);
233                                 Assert.Fail ("#6");
234                         } catch (ArgumentNullException) {
235                         } catch (ArgumentOutOfRangeException) {
236                         }
237                 }
238
239                 [Test]
240                 public void ContinueWhenAll_WithExceptions ()
241                 {
242                         var t1 = Task.Factory.StartNew (() => { throw new ApplicationException ("Foo"); });
243                         var t2 = Task.Factory.StartNew (() => { throw new ApplicationException ("Bar"); });
244
245                         var cont = Task.Factory.ContinueWhenAll (new[] { t1, t2 }, delegate {});
246                         cont.Wait (200);
247
248                         Assert.IsTrue (t1.IsFaulted);
249                         Assert.IsTrue (t2.IsFaulted);
250                         Assert.AreEqual (TaskStatus.RanToCompletion, cont.Status);
251                 }
252
253                 [Test]
254                 public void ContinueWhenAny_Simple ()
255                 {
256                         var t1 = new ManualResetEvent (false);
257                         var t2 = new ManualResetEvent (false);
258
259                         var tasks = new Task[2] {
260                                 Task.Factory.StartNew (() => { t1.WaitOne (5000); }),
261                                 Task.Factory.StartNew (() => { t2.WaitOne (5000); })
262                         };
263
264                         bool ran = false;
265                         var ct = new CancellationToken ();
266                         Task cont = factory.ContinueWhenAny (tasks, t => {
267                                 Assert.AreEqual (tasks[0], t, "#1");
268                                 ran = true;
269                         }, ct);
270
271                         Assert.AreEqual (TaskStatus.WaitingForActivation, cont.Status, "#2");
272
273                         t1.Set ();
274
275                         Assert.IsTrue (cont.Wait (3000), "#10");
276                         Assert.IsTrue (ran, "#11");
277
278                         t2.Set ();
279                 }
280
281                 [Test]
282                 public void ContinueWhenAny_WithResult ()
283                 {
284                         var tcs = new TaskCompletionSource<int>();
285                         tcs.SetResult(1);
286                         Task[] tasks = new[] { tcs.Task };
287                         var res = Task.Factory.ContinueWhenAny (tasks, l => 4);
288                         Assert.AreEqual (4, res.Result);
289                 }
290
291                 [Test]
292                 public void ContinueWhenAny_InvalidArguments ()
293                 {
294                         try {
295                                 factory.ContinueWhenAny (null, delegate { });
296                                 Assert.Fail ("#1");
297                         } catch (ArgumentNullException) {
298                         }
299
300                         try {
301                                 factory.ContinueWhenAny (new Task[0], delegate { });
302                                 Assert.Fail ("#2");
303                         } catch (ArgumentException) {
304                         }
305
306                         try {
307                                 factory.ContinueWhenAny (new Task[] { null }, delegate { });
308                                 Assert.Fail ("#3");
309                         } catch (ArgumentException) {
310                         }
311
312                         var tasks = new Task [] {
313                                 factory.StartNew (delegate {})
314                         };
315
316                         try {
317                                 factory.ContinueWhenAny (tasks, null);
318                                 Assert.Fail ("#4");
319                         } catch (ArgumentNullException) {
320                         }
321
322                         try {
323                                 factory.ContinueWhenAny (tasks, delegate { }, CancellationToken.None, TaskContinuationOptions.None, null);
324                                 Assert.Fail ("#5");
325                         } catch (ArgumentNullException) {
326                         }
327
328                         try {
329                                 factory.ContinueWhenAny (tasks, delegate { }, CancellationToken.None, TaskContinuationOptions.OnlyOnCanceled, null);
330                                 Assert.Fail ("#6");
331                         } catch (ArgumentNullException) {
332                         } catch (ArgumentOutOfRangeException) {
333                         }
334                 }
335
336                 [Test]
337                 public void FromAsyncBeginInvoke_WithResult ()
338                 {
339                         bool result = false;
340
341                         Func<int, int> func = (i) => {
342                                 Assert.IsTrue (Thread.CurrentThread.IsThreadPoolThread);
343                                 result = true; return i + 3;
344                         };
345
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");
352                 }
353
354                 [Test]
355                 public void FromAsyncBeginMethod_DirectResult ()
356                 {
357                         bool result = false;
358                         bool continuationTest = false;
359
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);
363                         task.Wait ();
364                         cont.Wait ();
365
366                         Assert.IsTrue (result);
367                         Assert.IsTrue (continuationTest);
368                         Assert.AreEqual (4, task.Result);
369                 }
370
371                 [Test]
372                 public void FromAsyncBeginMethod_Exception ()
373                 {
374                         bool result = false;
375                         bool continuationTest = false;
376
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);
380                         try {
381                                 task.Wait (2000);
382                         } catch { }
383                         Assert.IsTrue (cont.Wait (2000), "#1");
384
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);
392
393                         try {
394                                 var a = task.Result;
395                                 Assert.Fail ();
396                         } catch (AggregateException) {
397                         }
398                 }
399
400                 [Test]
401                 public void FromAsync_ArgumentsCheck ()
402                 {
403                         var result = new CompletedAsyncResult ();
404                         try {
405                                 factory.FromAsync (null, l => { });
406                                 Assert.Fail ("#1");
407                         } catch (ArgumentNullException) {
408                         }
409
410                         try {
411                                 factory.FromAsync (result, null);
412                                 Assert.Fail ("#2");
413                         } catch (ArgumentNullException) {
414                         }
415
416                         try {
417                                 factory.FromAsync (result, l => { }, TaskCreationOptions.LongRunning);
418                                 Assert.Fail ("#3");
419                         } catch (ArgumentOutOfRangeException) {
420                         }
421
422                         try {
423                                 factory.FromAsync (result, l => { }, TaskCreationOptions.PreferFairness);
424                                 Assert.Fail ("#4");
425                         } catch (ArgumentOutOfRangeException) {
426                         }
427
428                         try {
429                                 factory.FromAsync (result, l => { }, TaskCreationOptions.None, null);
430                                 Assert.Fail ("#5");
431                         } catch (ArgumentNullException) {
432                         }
433
434                         try {
435                                 factory.FromAsync (null, l => { }, null, TaskCreationOptions.None);
436                                 Assert.Fail ("#6");
437                         } catch (ArgumentNullException) {
438                         }
439
440                         try {
441                                 factory.FromAsync ((a, b) => null, l => { }, null, TaskCreationOptions.LongRunning);
442                                 Assert.Fail ("#7");
443                         } catch (ArgumentOutOfRangeException) {
444                         }
445                 }
446
447                 [Test]
448                 [Category ("MacNotWorking")] // Randomly fails - https://bugzilla.xamarin.com/show_bug.cgi?id=51255
449                 public void FromAsync_Completed ()
450                 {
451                         var completed = new CompletedAsyncResult ();
452                         bool? valid = null;
453
454                         Action<IAsyncResult> end = l => {
455                                 Assert.IsFalse (Thread.CurrentThread.IsThreadPoolThread, "#2");
456                                 valid = l == completed;
457                         };
458                         Task task = factory.FromAsync (completed, end);
459                         Assert.IsTrue (valid == true, "#1");
460                 }
461
462                 [Test]
463                 public void FromAsync_CompletedWithException ()
464                 {
465                         var completed = new CompletedAsyncResult ();
466
467                         Action<IAsyncResult> end = l => {
468                                 throw new ApplicationException ();
469                         };
470                         Task task = factory.FromAsync (completed, end);
471                         Assert.AreEqual (TaskStatus.Faulted, task.Status, "#1");
472                 }
473
474                 [Test]
475                 public void FromAsync_CompletedCanceled ()
476                 {
477                         var completed = new CompletedAsyncResult ();
478
479                         Action<IAsyncResult> end = l => {
480                                 throw new OperationCanceledException ();
481                         };
482                         Task task = factory.FromAsync (completed, end);
483                         Assert.AreEqual (TaskStatus.Canceled, task.Status, "#1");
484                         Assert.IsNull (task.Exception, "#2");
485                 }
486
487                 [Test]
488                 public void FromAsync_SimpleAsyncResult ()
489                 {
490                         var result = new TestAsyncResult ();
491                         bool called = false;
492
493                         var task = factory.FromAsync (result, l => {
494                                 called = true;
495                         });
496
497                         Assert.IsTrue (task.Wait (1000), "#1");
498                         Assert.IsTrue (called, "#2");
499                 }
500
501                 [Test]
502                 public void FromAsync_ResultException ()
503                 {
504                         var result = new TestAsyncResult ();
505
506                         var task = factory.FromAsync (result, l => {
507                                 throw new ApplicationException ();
508                         });
509
510                         try {
511                                 Assert.IsFalse (task.Wait (1000), "#1");
512                         } catch (AggregateException) {
513                         }
514
515                         Assert.AreEqual (TaskStatus.Faulted, task.Status, "#2");
516                 }
517
518                 [Test]
519                 public void FromAsync_ReturnInt ()
520                 {
521                         var result = new TestAsyncResult ();
522                         bool called = false;
523
524                         var task = factory.FromAsync<int> (result, l => {
525                                 called = true;
526                                 return 4;
527                         });
528
529                         Assert.IsTrue (task.Wait (1000), "#1");
530                         Assert.IsTrue (called, "#2");
531                         Assert.AreEqual (4, task.Result, "#3");
532                 }
533
534                 [Test]
535                 public void FromAsync_Scheduler_Explicit ()
536                 {
537                         var result = new TestAsyncResult ();
538                         bool called = false;
539                         var scheduler = new TestScheduler ();
540
541                         var task = factory.FromAsync (result, l => {
542                                 called = true;
543                         }, TaskCreationOptions.None, scheduler);
544
545                         Assert.IsTrue (task.Wait (5000), "#1");
546                         Assert.IsTrue (called, "#2");
547                         Assert.IsTrue (scheduler.ExecutedInline, "#3");
548                 }
549
550                 [Test]
551                 public void FromAsync_Scheduler_Implicit ()
552                 {
553                         var result = new TestAsyncResult ();
554                         bool called = false;
555                         var scheduler = new TestScheduler ();
556
557                         factory = new TaskFactory (scheduler);
558
559                         Task task = factory.FromAsync (result, l => {
560                                 Assert.IsTrue (Thread.CurrentThread.IsThreadPoolThread, "#6");
561                                 called = true;
562                         }, TaskCreationOptions.AttachedToParent);
563
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");
569                 }
570
571                 [Test]
572                 [Category ("MacNotWorking")] // Randomly fails - https://bugzilla.xamarin.com/show_bug.cgi?id=51255
573                 public void FromAsync_BeginCallback ()
574                 {
575                         bool called = false;
576                         bool called2 = false;
577
578                         var task = factory.FromAsync (
579                                 (a, b, c) => {
580                                         if (a != "h")
581                                                 Assert.Fail ("#10");
582
583                                         if ((TaskCreationOptions) c != TaskCreationOptions.AttachedToParent)
584                                                 Assert.Fail ("#11");
585
586                                         Assert.IsFalse (Thread.CurrentThread.IsThreadPoolThread, "#12");
587
588                                         called2 = true;
589                                         b.Invoke (null);
590                                         return null;
591                                 },
592                                 l => {
593                                         called = true;
594                                 },
595                                 "h", TaskCreationOptions.AttachedToParent);
596
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");
602                 }
603
604                 [Test]
605                 public void StartNewCancelled ()
606                 {
607                         var ct = new CancellationToken (true);
608
609                         var task = factory.StartNew (() => Assert.Fail ("Should never be called"), ct);
610                         try {
611                                 task.Start ();
612                                 Assert.Fail ("#1");
613                         } catch (InvalidOperationException) {
614                         }
615
616                         try {
617                                 task.Wait ();
618                                 Assert.Fail ("#2");
619                         } catch (AggregateException e) {
620                                 Assert.That (e.InnerException, Is.TypeOf (typeof (TaskCanceledException)), "#3");
621                         }
622
623                         Assert.IsTrue (task.IsCanceled, "#4");
624                 }
625         }
626 }