1 /***
2  * Copyright (C) Microsoft. All rights reserved.
3  * Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
4  *
5  * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
6  *
7  * Basic tests for PPLX operations
8  *
9  * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
10  ****/
11 #include "stdafx.h"
12 
13 using namespace ::pplx;
14 using namespace ::tests::common::utilities;
15 
16 namespace tests
17 {
18 namespace functional
19 {
20 namespace PPLX
21 {
IsTrue(bool condition,const wchar_t *,...)22 static void IsTrue(bool condition, const wchar_t*, ...) { VERIFY_IS_TRUE(condition); }
23 
IsFalse(bool condition,...)24 static void IsFalse(bool condition, ...) { VERIFY_IS_TRUE(condition == false); }
25 
LogFailure(const wchar_t * msg,...)26 static void LogFailure(const wchar_t* msg, ...)
27 {
28     wprintf(L"%s", msg);
29     VERIFY_IS_TRUE(false);
30 }
31 
32 namespace helpers
33 {
FibSerial(int n)34 static int FibSerial(int n)
35 {
36     if (n < 2) return n;
37 
38     return FibSerial(n - 1) + FibSerial(n - 2);
39 }
40 
DoRandomParallelWork()41 static void DoRandomParallelWork()
42 {
43     int param = (rand() % 8) + 20;
44     // Calculate fib in serial
45     volatile int val = FibSerial(param);
46     val;
47 }
48 
49 template<typename _EX, typename _T>
VerifyException(task<_T> & task)50 bool VerifyException(task<_T>& task)
51 {
52     bool gotException = true;
53     bool wrongException = false;
54 
55     try
56     {
57         task.get();
58         gotException = false;
59     }
60     catch (const _EX&)
61     {
62     }
63     catch (...)
64     {
65         wrongException = true;
66     }
67 
68     return (gotException && !wrongException);
69 }
70 
71 template<typename _T>
VerifyNoException(task<_T> & task)72 bool VerifyNoException(task<_T>& task)
73 {
74     try
75     {
76         task.get();
77     }
78     catch (...)
79     {
80         return false;
81     }
82     return true;
83 }
84 
85 template<typename _T>
VerifyCanceled(task<_T> & task)86 bool VerifyCanceled(task<_T>& task)
87 {
88     try
89     {
90         task.get();
91     }
92     catch (task_canceled&)
93     {
94         return true;
95     }
96     catch (...)
97     {
98         return false;
99     }
100     return false;
101 }
102 
103 template<typename _T>
ObserveException(task<_T> & task)104 void ObserveException(task<_T>& task)
105 {
106     try
107     {
108         task.get();
109     }
110     catch (...)
111     {
112     }
113 }
114 
115 template<typename Iter>
ObserveAllExceptions(Iter begin,Iter end)116 void ObserveAllExceptions(Iter begin, Iter end)
117 {
118     typedef typename std::iterator_traits<Iter>::value_type::result_type TaskType;
119     for (auto it = begin; it != end; ++it)
120     {
121         ObserveException(*it);
122     }
123 }
124 } // namespace helpers
125 
SUITE(pplxtask_tests)126 SUITE(pplxtask_tests)
127 {
128     TEST(TestCancellationTokenRegression)
129     {
130         for (int i = 0; i < 500; i++)
131         {
132             task_completion_event<void> tce;
133             task<void> starter(tce);
134 
135             cancellation_token_source ct;
136 
137             task<int> t1 = starter.then([]() -> int { return 47; }, ct.get_token());
138 
139             task<int> t2([]() -> int { return 82; });
140 
141             task<int> t3([]() -> int { return 147; });
142 
143             auto t4 = (t1 && t2 && t3).then([=](std::vector<int> vec) -> int { return vec[0] + vec[1] + vec[3]; });
144 
145             ct.cancel();
146 
147             tce.set();
148             // this should not hang
149             task_status t4Status = t4.wait();
150             IsTrue(t4Status == canceled,
151                    L"operator && did not properly cancel. Expected: %d, Actual: %d",
152                    canceled,
153                    t4Status);
154         }
155     }
156     TEST(TestTasks_basic)
157     {
158         {
159             task<int> t1([]() -> int { return 47; });
160 
161             auto t2 = t1.then([=](int i) -> float {
162                 IsTrue(i == 47,
163                        L"Continuation did not recieve the correct value from ancestor. Expected: 47, Actual: %d",
164                        i);
165                 return (float)i / 2;
166             });
167 
168             float t2Result = t2.get();
169             IsTrue(t2Result == 23.5,
170                    L"Continuation task did not produce the correct result. Expected: 23.5, Actual: %f",
171                    t2Result);
172 
173             task_status t2Status = t2.wait();
174             IsTrue(t2Status == completed,
175                    L"Continuation task was not in completed state. Expected: %d, Actual: %d",
176                    completed,
177                    t2Status);
178 
179             task<int> t3([]() -> int { return 0; });
180 
181             IsTrue(t1 == t1, L"task operator== resulted false on equivalent tasks");
182             IsFalse(t1 != t1, L"task operator!= resulted true on equivalent tasks");
183             IsFalse(t1 == t3, L"task operator== resulted true on different tasks");
184             IsTrue(t1 != t3, L"task operator!= resulted false on different tasks");
185 
186             t3.wait();
187         }
188     }
189 
190     TEST(TestTasks_default_construction)
191     {
192         // Test that default constructed task<T> properly throw exceptions
193         {
194             task<int> t1;
195 
196             try
197             {
198                 t1.wait();
199                 LogFailure(L"t1.wait() should have thrown an exception");
200             }
201             catch (invalid_operation)
202             {
203             }
204 
205             try
206             {
207                 t1.get();
208                 LogFailure(L"t1.get() should have thrown an exception");
209             }
210             catch (invalid_operation)
211             {
212             }
213 
214             try
215             {
216                 t1.then([](int i) { return i; });
217 
218                 LogFailure(L"t1.then() should have thrown an exception");
219             }
220             catch (invalid_operation)
221             {
222             }
223         }
224     }
225 
226     TEST(TestTasks_void_tasks)
227     {
228         // Test void tasks
229         {
230             int value = 0;
231             task<void> t1([&value]() { value = 147; });
232 
233             auto t2 = t1.then([&]() {
234                 IsTrue(value == 147,
235                        L"void continuation did not recieve the correct value from ancestor. Expected: 147, Actual: %d",
236                        value);
237                 value++;
238             });
239 
240             IsTrue(t2.wait() == completed, L"void task was not in completed state.");
241 
242             IsTrue(value == 148, L"void tasks did not properly execute. Expected: 148, Actual: %d", value);
243 
244             task<void> t3([]() {});
245 
246             IsTrue(t1 == t1, L"task operator== resulted false on equivalent tasks");
247             IsFalse(t1 != t1, L"task operator!= resulted true on equivalent tasks");
248             IsFalse(t1 == t3, L"task operator== resulted true on different tasks");
249             IsTrue(t1 != t3, L"task operator!= resulted false on different tasks");
250         }
251     }
252 
253     TEST(TestTasks_void_tasks_default_construction)
254     {
255         // Test that default constructed task<void> properly throw exceptions
256         {
257             task<void> t1;
258 
259             try
260             {
261                 t1.wait();
262                 LogFailure(L"t1.wait() should have thrown an exception");
263             }
264             catch (invalid_operation)
265             {
266             }
267 
268             try
269             {
270                 t1.get();
271                 LogFailure(L"t1.get() should have thrown an exception");
272             }
273             catch (invalid_operation)
274             {
275             }
276 
277             try
278             {
279                 t1.then([]() {});
280                 LogFailure(L"t1.contiue_with() should have thrown an exception");
281             }
282             catch (invalid_operation)
283             {
284             }
285         }
286     }
287 
288     TEST(TestTasks_movable_then)
289     {
290 #ifndef _MSC_VER
291         // create movable only type
292         struct A
293         {
294             A() = default;
295             A(A&&) = default;
296             A& operator=(A&&) = default;
297 
298             // explicitly delete copy functions
299             A(const A&) = delete;
300             A& operator=(const A&) = delete;
301 
302             char operator()(int) { return 'c'; }
303         } a;
304 
305         task<int> task = create_task([] { return 2; });
306         auto f = task.then(std::move(a));
307 
308         IsTrue(f.get() == 'c', L".then should be able to work with movable functors");
309 #endif // _MSC_VER
310     }
311 
312     TEST(TestTasks_constant_this)
313     {
314 #ifdef _MSC_VER
315 #if _MSC_VER < 1700
316         // Dev10 compiler gives an error => .then(func) where func = int!
317 #else
318         {
319             // Test constant 'this' pointer in member functions then(), wait() and get(),
320             // so that they can be used in Lambda.
321             task<int> t1([]() -> int { return 0; });
322 
323             auto func = [t1]() -> int {
324                 t1.then([](int last) -> int { return last; });
325                 t1.wait();
326                 return t1.get();
327             };
328 
329             IsTrue(func() == 0, L"Tasks should be able to used inside a Lambda.");
330         }
331 #endif // _MSC_VER < 1700
332 #endif // _MSC_VER
333     }
334 
335     TEST(TestTasks_fire_and_forget)
336     {
337         // Test Fire-and-forget behavior
338         extensibility::event_t evt;
339         bool flag = false;
340         {
341             task<int> t1([&flag, &evt]() -> int {
342                 flag = true;
343                 evt.set();
344                 return 0;
345             });
346         }
347 
348         evt.wait();
349         IsTrue(flag == true, L"Fire-and-forget task did not properly execute.");
350     }
351     TEST(TestTasks_create_task)
352     {
353         // test create task
354         task<int> t1 = create_task([]() -> int { return 4; });
355         IsTrue(t1.get() == 4, L"create_task for simple task did not properly execute.");
356         IsTrue(create_task(t1).get() == 4, L"create_task from a task task did not properly execute.");
357         task<void> t2 = create_task([]() {});
358         task<int> t3 = create_task([]() -> task<int> { return create_task([]() -> int { return 4; }); });
359         IsTrue(t3.get() == 4, L"create_task for task unwrapping did not properly execute.");
360     }
361 
362     TEST(TestTaskCompletionEvents_basic)
363     {
364         task_completion_event<int> tce;
365         task<int> completion(tce);
366         auto completion2 = create_task(tce);
367 
368         task<void> setEvent([=]() { tce.set(50); });
369 
370         int result = completion.get();
371         IsTrue(result == 50, L"Task Completion Event did not get the right result. Expected: 50, Actual: %d", result);
372         IsTrue(completion2.get() == 50,
373                L"create_task didn't construct correct task for task_completion_event, Expected: 50, Actual: %d",
374                result);
375     }
376 
377     TEST(TestTaskCompletionEvents_basic2)
378     {
379         task_completion_event<void> tce;
380         task<void> completion(tce);
381         auto completion2 = create_task(tce);
382 
383         task<void> setEvent([=]() { tce.set(); });
384 
385         // this should not hang, because of the set of tce
386         completion.wait();
387         completion2.wait();
388     }
389 
390     TEST(TestTaskCompletionEvents_set_exception_basic)
391     {
392         task_completion_event<void> tce;
393         task<void> t(tce);
394         tce.set_exception(42);
395 
396         t.then([=](task<void> p) {
397              try
398              {
399                  p.get();
400                  IsTrue(false, L"Exception not propagated to task t when calling set_exception.");
401              }
402              catch (int n)
403              {
404                  IsTrue(n == 42, L"%ws:%u:bad exception value", __FILE__, __LINE__);
405              }
406          })
407             .wait();
408     }
409 
410     TEST(TestTaskCompletionEvents_set_exception_multiple)
411     {
412         task_completion_event<void> tce;
413         task<void> t(tce);
414         tce.set_exception(42);
415 
416         t.then([=](task<void> p) {
417              try
418              {
419                  p.get();
420                  IsTrue(false, L"Exception not propagated to task t's first continuation when calling set_exception.");
421              }
422              catch (int n)
423              {
424                  IsTrue(n == 42, L"%ws:%u:bad exception value", __FILE__, __LINE__);
425              }
426          })
427             .wait();
428 
429         t.then([=](task<void> p) {
430              try
431              {
432                  p.get();
433                  IsTrue(false, L"Exception not propagated to task t's second continuation when calling set_exception.");
434              }
435              catch (int n)
436              {
437                  IsTrue(n == 42, L"%ws:%u:bad exception value", __FILE__, __LINE__);
438              }
439          })
440             .wait();
441     }
442 
443     TEST(TestTaskCompletionEvents_set_exception_struct)
444     {
445 #if defined(_MSC_VER) && _MSC_VER < 1700
446         // The Dev10 compiler hits an ICE with this code
447 #else
448         struct s
449         {
450         };
451 
452         task_completion_event<void> tce;
453         task<void> t(tce);
454         tce.set_exception(s());
455         t.then([=](task<void> p) {
456              try
457              {
458                  p.get();
459                  IsTrue(false, L"Exception not caught.");
460              }
461              catch (s)
462              {
463                  // Do nothing
464              }
465              catch (...)
466              {
467                  IsTrue(false, L"%ws:%u:not the right exception", __FILE__, __LINE__);
468              }
469          })
470             .wait();
471 #endif // _MSC_VER < 1700
472     }
473 
474     TEST(TestTaskCompletionEvents_multiple_tasks)
475     {
476         task_completion_event<void> tce;
477         task<void> t1(tce);
478         task<void> t2(tce);
479         tce.set_exception(1);
480 
481         t1.then([=](task<void> p) {
482             try
483             {
484                 p.get();
485                 IsTrue(false, L"An exception was not thrown when calling t1.get().  An exception was expected.");
486             }
487             catch (int ex)
488             {
489                 IsTrue(ex == 1, L"%ws:%u:wrong exception value", __FILE__, __LINE__);
490             }
491             catch (...)
492             {
493                 IsTrue(false, L"%ws:%u:not the right exception", __FILE__, __LINE__);
494             }
495         });
496 
497         t2.then([=](task<void> p) {
498             try
499             {
500                 p.get();
501                 IsTrue(false, L"An exception was not thrown when calling t2.get().  An exception was expected.");
502             }
503             catch (int ex)
504             {
505                 IsTrue(ex == 1, L"%ws:%u:wrong exception value", __FILE__, __LINE__);
506             }
507             catch (...)
508             {
509                 IsTrue(false, L"%ws:%u:not the right exception", __FILE__, __LINE__);
510             }
511         });
512     }
513 
514     TEST(TestTaskCompletionEvents_set_exception_after_set)
515     {
516         task_completion_event<int> tce;
517         task<int> t(tce);
518         tce.set(1);
519         auto result = tce.set_exception(std::current_exception());
520         IsFalse(result, L"set_exception must return false, but did not");
521         t.then([=](task<int> p) {
522              try
523              {
524                  int n = p.get();
525                  IsTrue(n == 1, L"Value not properly propagated to continuation");
526              }
527              catch (...)
528              {
529                  IsTrue(false, L"An exception was unexpectedly thrown in the continuation task");
530              }
531          })
532             .wait();
533     }
534 
535     TEST(TestTaskCompletionEvents_set_exception_after_set2)
536     {
537         task_completion_event<int> tce;
538         task<int> t(tce);
539         tce.set_exception(1);
540         auto result = tce.set_exception(2);
541         IsFalse(result, L"set_exception must return false, but did not");
542         t.then([=](task<int> p) {
543              try
544              {
545                  p.get();
546                  IsTrue(false, L"%ws:%u:expected exception not thrown", __FILE__, __LINE__);
547              }
548              catch (int n)
549              {
550                  IsTrue(n == 1, L"%ws:%u:unexpected exception payload", __FILE__, __LINE__);
551              }
552          })
553             .wait();
554     }
555 
556     TEST(TestTaskCompletionEvents_set_after_set_exception)
557     {
558         task_completion_event<int> tce;
559         task<int> t(tce);
560         tce.set_exception(42);
561         tce.set(1); // should be no-op
562         t.then([=](task<int> p) {
563              try
564              {
565                  p.get();
566                  IsTrue(false, L"Exception should have been thrown here.");
567              }
568              catch (int e)
569              {
570                  IsTrue(e == 42, L"%ws:%u:not the right exception value", __FILE__, __LINE__);
571              }
572              catch (...)
573              {
574                  IsTrue(false, L"%ws:%u:not the right exception", __FILE__, __LINE__);
575              }
576          })
577             .wait();
578     }
579 
580     TEST(TestTaskOperators_and_or)
581     {
582         task<int> t1([]() -> int { return 47; });
583 
584         task<int> t2([]() -> int { return 82; });
585 
586         auto t3 = (t1 && t2).then([=](std::vector<int> vec) -> int {
587             IsTrue(vec.size() == 2,
588                    L"operator&& did not produce a correct vector size. Expected: 2, Actual: %d",
589                    vec.size());
590             IsTrue(vec[0] == 47, L"operator&& did not produce a correct vector[0]. Expected: 47, Actual: %d", vec[0]);
591             IsTrue(vec[1] == 82, L"operator&& did not produce a correct vector[1]. Expected: 82, Actual: %d", vec[1]);
592             return vec[0] + vec[1];
593         });
594 
595         int t3Result = t3.get();
596         IsTrue(t3Result == 129,
597                L"operator&& task did not produce the correct result. Expected: 129, Actual: %d",
598                t3Result);
599     }
600 
601     TEST(TestTaskOperators_and_or2)
602     {
603         task<int> t1([]() -> int { return 47; });
604 
605         task<int> t2([]() -> int { return 82; });
606 
607         task<int> t3([]() -> int { return 147; });
608 
609         task<int> t4([]() -> int { return 192; });
610 
611         auto t5 = (t1 && t2 && t3 && t4).then([=](std::vector<int> vec) -> int {
612             IsTrue(vec.size() == 4,
613                    L"operator&& did not produce a correct vector size. Expected: 4, Actual: %d",
614                    vec.size());
615             IsTrue(vec[0] == 47, L"operator&& did not produce a correct vector[0]. Expected: 47, Actual: %d", vec[0]);
616             IsTrue(vec[1] == 82, L"operator&& did not produce a correct vector[1]. Expected: 82, Actual: %d", vec[1]);
617             IsTrue(vec[2] == 147, L"operator&& did not produce a correct vector[2]. Expected: 147, Actual: %d", vec[2]);
618             IsTrue(vec[3] == 192, L"operator&& did not produce a correct vector[3]. Expected: 192, Actual: %d", vec[3]);
619             int count = 0;
620             for (unsigned i = 0; i < vec.size(); i++)
621                 count += vec[i];
622             return count;
623         });
624 
625         int t5Result = t5.get();
626         IsTrue(t5Result == 468,
627                L"operator&& task did not produce the correct result. Expected: 468, Actual: %d",
628                t5Result);
629     }
630 
631     TEST(TestTaskOperators_and_or3)
632     {
633         task<int> t1([]() -> int { return 47; });
634 
635         task<int> t2([]() -> int { return 82; });
636 
637         task<int> t3([]() -> int { return 147; });
638 
639         task<int> t4([]() -> int { return 192; });
640 
641         auto t5 = ((t1 && t2) && (t3 && t4)).then([=](std::vector<int> vec) -> int {
642             IsTrue(vec.size() == 4,
643                    L"operator&& did not produce a correct vector size. Expected: 4, Actual: %d",
644                    vec.size());
645             IsTrue(vec[0] == 47, L"operator&& did not produce a correct vector[0]. Expected: 47, Actual: %d", vec[0]);
646             IsTrue(vec[1] == 82, L"operator&& did not produce a correct vector[1]. Expected: 82, Actual: %d", vec[1]);
647             IsTrue(vec[2] == 147, L"operator&& did not produce a correct vector[2]. Expected: 147, Actual: %d", vec[2]);
648             IsTrue(vec[3] == 192, L"operator&& did not produce a correct vector[3]. Expected: 192, Actual: %d", vec[3]);
649             int count = 0;
650             for (unsigned i = 0; i < vec.size(); i++)
651                 count += vec[i];
652             return count;
653         });
654 
655         int t5Result = t5.get();
656         IsTrue(t5Result == 468,
657                L"operator&& task did not produce the correct result. Expected: 468, Actual: %d",
658                t5Result);
659     }
660 
661     TEST(TestTaskOperators_and_or4)
662     {
663         extensibility::event_t evt;
664 
665         task<int> t1([&evt]() -> int {
666             evt.wait();
667             return 47;
668         });
669 
670         task<int> t2([]() -> int { return 82; });
671 
672         auto t3 = (t1 || t2).then([=](int p) -> int {
673             IsTrue(p == 82, L"operator|| did not get the right result. Expected: 82, Actual: %d", p);
674             return p;
675         });
676 
677         t3.wait();
678 
679         evt.set();
680         t1.wait();
681     }
682 
683     TEST(TestTaskOperators_and_or5)
684     {
685         extensibility::event_t evt;
686 
687         task<int> t1([&evt]() -> int {
688             evt.wait();
689             return 47;
690         });
691 
692         task<int> t2([&evt]() -> int {
693             evt.wait();
694             return 82;
695         });
696 
697         task<int> t3([]() -> int { return 147; });
698 
699         task<int> t4([&evt]() -> int {
700             evt.wait();
701             return 192;
702         });
703 
704         auto t5 = (t1 || t2 || t3 || t4).then([=](int result) -> int {
705             IsTrue(result == 147, L"operator|| did not produce a correct result. Expected: 147, Actual: %d", result);
706             return result;
707         });
708 
709         t5.wait();
710 
711         evt.set();
712         t1.wait();
713         t2.wait();
714         t4.wait();
715     }
716 
717     TEST(TestTaskOperators_and_or_sequence)
718     {
719         // testing ( t1 && t2 ) || t3, operator&& finishes first
720         extensibility::event_t evt;
721 
722         task<int> t1([]() -> int { return 47; });
723 
724         task<int> t2([]() -> int { return 82; });
725 
726         task<int> t3([&evt]() -> int {
727             evt.wait();
728             return 147;
729         });
730 
731         auto t4 = ((t1 && t2) || t3).then([=](std::vector<int> vec) -> int {
732             IsTrue(vec.size() == 2,
733                    L"(t1 && t2) || t3 did not produce a correct vector size. Expected: 2, Actual: %d",
734                    vec.size());
735             IsTrue(vec[0] == 47,
736                    L"(t1 && t2) || t3 did not produce a correct vector[0]. Expected: 47, Actual: %d",
737                    vec[0]);
738             IsTrue(vec[1] == 82,
739                    L"(t1 && t2) || t3 did not produce a correct vector[1]. Expected: 82, Actual: %d",
740                    vec[1]);
741             return vec[0] + vec[1];
742         });
743 
744         int t4Result = t4.get();
745         IsTrue(t4.get() == 129,
746                L"(t1 && t2) || t3 task did not produce the correct result. Expected: 129, Actual: %d",
747                t4Result);
748 
749         evt.set();
750         t3.wait();
751     }
752 
753     TEST(TestTaskOperators_and_or_sequence2)
754     {
755         // testing ( t1 && t2 ) || t3, operator|| finishes first
756         extensibility::event_t evt;
757 
758         task<int> t1([&evt]() -> int {
759             evt.wait();
760             return 47;
761         });
762 
763         task<int> t2([&evt]() -> int {
764             evt.wait();
765             return 82;
766         });
767 
768         task<int> t3([]() -> int { return 147; });
769 
770         auto t4 = ((t1 && t2) || t3).then([=](std::vector<int> vec) -> int {
771             IsTrue(vec.size() == 1,
772                    L"(t1 && t2) || t3 did not produce a correct vector size. Expected: 1, Actual: %d",
773                    vec.size());
774             IsTrue(vec[0] == 147,
775                    L"(t1 && t2) || t3 did not produce a correct vector[0]. Expected: 147, Actual: %d",
776                    vec[0]);
777             return vec[0];
778         });
779 
780         int t4Result = t4.get();
781         IsTrue(t4.get() == 147,
782                L"(t1 && t2) || t3 task did not produce the correct result. Expected: 147, Actual: %d",
783                t4Result);
784 
785         evt.set();
786         t1.wait();
787         t2.wait();
788     }
789 
790     TEST(TestTaskOperators_and_or_sequence3)
791     {
792         // testing t1 && (t2 || t3)
793         extensibility::event_t evt;
794 
795         task<int> t1([]() -> int { return 47; });
796 
797         task<int> t2([&evt]() -> int {
798             evt.wait();
799             return 82;
800         });
801 
802         task<int> t3([]() -> int { return 147; });
803 
804         auto t4 = (t1 && (t2 || t3)).then([=](std::vector<int> vec) -> int {
805             IsTrue(vec.size() == 2,
806                    L"t1 && (t2 || t3) did not produce a correct vector size. Expected: 2, Actual: %d",
807                    vec.size());
808             IsTrue(vec[0] == 47,
809                    L"t1 && (t2 || t3) did not produce a correct vector[0]. Expected: 47, Actual: %d",
810                    vec[0]);
811             IsTrue(vec[1] == 147,
812                    L"t1 && (t2 || t3) did not produce a correct vector[1]. Expected: 147, Actual: %d",
813                    vec[1]);
814             return vec[0] + vec[1];
815         });
816 
817         int t4Result = t4.get();
818         IsTrue(t4.get() == 194,
819                L"t1 && (t2 || t3) task did not produce the correct result. Expected: 194 Actual: %d",
820                t4Result);
821 
822         evt.set();
823         t2.wait();
824     }
825 
826     TEST(TestTaskOperators_cancellation)
827     {
828         task_completion_event<void> tce;
829         task<void> starter(tce);
830 
831         cancellation_token_source ct;
832 
833         task<int> t1 = starter.then([]() -> int { return 47; }, ct.get_token());
834 
835         task<int> t2([]() -> int { return 82; });
836 
837         task<int> t3([]() -> int { return 147; });
838 
839         auto t4 = (t1 && t2 && t3).then([=](std::vector<int> vec) -> int { return vec[0] + vec[1] + vec[3]; });
840 
841         ct.cancel();
842 
843         tce.set();
844         // this should not hang
845         task_status t4Status = t4.wait();
846         IsTrue(
847             t4Status == canceled, L"operator && did not properly cancel. Expected: %d, Actual: %d", canceled, t4Status);
848     }
849 
850     TEST(TestTaskOperators_cancellation_and)
851     {
852         task_completion_event<void> tce;
853         task<void> starter(tce);
854 
855         cancellation_token_source ct;
856 
857         task<void> t1 = starter.then([]() -> void {}, ct.get_token());
858 
859         task<void> t2([]() -> void {});
860 
861         task<void> t3([]() -> void {});
862 
863         auto t4 = (t1 && t2 && t3).then([=]() {});
864 
865         ct.cancel();
866 
867         tce.set();
868         // this should not hang
869         task_status t4Status = t4.wait();
870         IsTrue(
871             t4Status == canceled, L"operator && did not properly cancel. Expected: %d, Actual: %d", canceled, t4Status);
872     }
873 
874     TEST(TestTaskOperators_cancellation_or)
875     {
876         task_completion_event<void> tce;
877         task<void> starter(tce);
878 
879         cancellation_token_source ct1;
880         cancellation_token_source ct2;
881         cancellation_token_source ct3;
882 
883         task<int> t1 = starter.then([]() -> int { return 47; }, ct1.get_token());
884 
885         task<int> t2 = starter.then([]() -> int { return 82; }, ct2.get_token());
886 
887         task<int> t3 = starter.then([]() -> int { return 147; }, ct3.get_token());
888 
889         auto t4 = (t1 || t2 || t3).then([=](int result) -> int { return result; });
890 
891         ct1.cancel();
892         ct2.cancel();
893         ct3.cancel();
894 
895         tce.set();
896         // this should not hang
897         task_status t4Status = t4.wait();
898         IsTrue(
899             t4Status == canceled, L"operator || did not properly cancel. Expected: %d, Actual: %d", canceled, t4Status);
900     }
901     TEST(TestTaskOperators_cancellation_or2)
902     {
903         task_completion_event<void> tce;
904         task<void> starter(tce);
905 
906         cancellation_token_source ct1;
907         cancellation_token_source ct2;
908         cancellation_token_source ct3;
909 
910         task<void> t1 = starter.then([]() -> void {}, ct1.get_token());
911 
912         task<void> t2 = starter.then([]() -> void {}, ct2.get_token());
913 
914         task<void> t3 = starter.then([]() -> void {}, ct3.get_token());
915 
916         auto t4 = (t1 || t2 || t3).then([=]() {});
917 
918         ct1.cancel();
919         ct2.cancel();
920         ct3.cancel();
921 
922         tce.set();
923         // this should not hang
924         task_status t4Status = t4.wait();
925         IsTrue(
926             t4Status == canceled, L"operator || did not properly cancel. Expected: %d, Actual: %d", canceled, t4Status);
927     }
928 
929     TEST(TestTaskOperators_cancellation_complex)
930     {
931         extensibility::event_t evt1, evt2;
932         pplx::details::atomic_long n(0);
933 
934         cancellation_token_source ct;
935 
936         task<void> t1(
937             [&n, &evt1, &evt2]() {
938                 pplx::details::atomic_add(n, 1L); // this should execute
939                 evt2.set();
940                 evt1.wait();
941             },
942             ct.get_token());
943 
944         task<void> t2 = t1.then([&n]() {
945             pplx::details::atomic_add(n, 10L); // this should NOT execute
946         });
947 
948         task<void> t3 = t1.then([&n]() {
949             pplx::details::atomic_add(n, 100L); // this should NOT execute
950         });
951 
952         task<void> t4 = t1.then([&n](task<void> taskResult) {
953             pplx::details::atomic_add(n, 1000L); // this should execute
954         });
955 
956         task<void> t5 = t1.then([&n](task<void> taskResult) {
957             try
958             {
959                 taskResult.get();
960                 pplx::details::atomic_add(n, 10000L); // this should execute
961             }
962             catch (task_canceled&)
963             {
964                 pplx::details::atomic_add(n, 100000L); // this should NOT execute
965             }
966         });
967 
968         evt2.wait();
969         ct.cancel();
970         evt1.set();
971 
972         IsTrue((t2 && t3).wait() == canceled, L"(t1 && t2) was not canceled");
973         IsTrue((t2 || t3 || t4 || t5).wait() == completed, L"(t2 || t3 || t4 || t5) did not complete");
974         IsTrue((t4 && t5).wait() == completed, L"(t4 && t5) did not complete");
975 
976         try
977         {
978             t1.get();
979         }
980         catch (task_canceled&)
981         {
982             LogFailure(L"get() on canceled task t1 should not throw a task_canceled exception.");
983         }
984 
985         try
986         {
987             t2.get();
988             LogFailure(L"get() on canceled task t2 should throw a task_canceled exception.");
989         }
990         catch (task_canceled&)
991         {
992         }
993 
994         try
995         {
996             t3.get();
997             LogFailure(L"get() on canceled task t3 should throw a task_canceled exception.");
998         }
999         catch (task_canceled&)
1000         {
1001         }
1002 
1003         try
1004         {
1005             t4.get();
1006             t5.get();
1007         }
1008         catch (...)
1009         {
1010             LogFailure(L"get() on completed tasks threw an exception.");
1011         }
1012         IsTrue(
1013             n == 11001L,
1014             L"The right result was not obtained from the sequence of tasks that executed. Expected: 11001, Actual: %d",
1015             static_cast<long>(n));
1016     }
1017 
1018     TEST(TestTaskOperators_cancellation_exception)
1019     {
1020         extensibility::event_t evt1, evt2;
1021         pplx::details::atomic_long n(0);
1022 
1023         cancellation_token_source ct;
1024 
1025         task<void> t1(
1026             [&n, &evt1, &evt2]() {
1027                 evt2.set();
1028                 evt1.wait();
1029             },
1030             ct.get_token());
1031 
1032         task<void> t2([&n]() { throw 42; });
1033 
1034         for (int i = 0; i < 5; ++i)
1035         {
1036             try
1037             {
1038                 t2.get();
1039                 LogFailure(L"Exception was not received from t2.get()");
1040             }
1041             catch (int x)
1042             {
1043                 IsTrue(x == 42, L"Incorrect integer was thrown from t2.get(). Expected: 42, Actual: %d", x);
1044             }
1045             catch (task_canceled&)
1046             {
1047                 LogFailure(L"task_canceled was thrown from t2.get() when an integer was expected");
1048             }
1049         }
1050 
1051         for (int i = 0; i < 5; ++i)
1052         {
1053             try
1054             {
1055                 t2.wait();
1056                 LogFailure(L"Exception was not received from t2.wait()");
1057             }
1058             catch (int x)
1059             {
1060                 IsTrue(x == 42, L"Incorrect integer was thrown from t2.wait(). Expected: 42, Actual: %d", x);
1061             }
1062             catch (task_canceled&)
1063             {
1064                 LogFailure(L"task_canceled was thrown from t2.wait() when an integer was expected");
1065             }
1066         }
1067 
1068         task<void> t3 = t1.then([&n]() {
1069             pplx::details::atomic_add(n, 1L); // this should NOT execute,
1070         });
1071 
1072         task<void> t4 = t1.then([&n](task<void> taskResult) {
1073             pplx::details::atomic_add(n, 10L); // this should execute
1074         });
1075 
1076         task<void> t5 = t2.then([&n]() {
1077             pplx::details::atomic_add(n, 100L); // this should NOT execute
1078         });
1079 
1080         task<void> t6 = t2.then([&n](task<void> taskResult) {
1081             pplx::details::atomic_add(n, 1000L);  // this should execute
1082             taskResult.get();                     // should throw 42
1083             pplx::details::atomic_add(n, 10000L); // this should NOT execute
1084         });
1085 
1086         task<void> t7 = t2.then([&n, this](task<void> taskResult) {
1087             try
1088             {
1089                 taskResult.get();
1090                 pplx::details::atomic_add(n, 100000L); // this should NOT execute
1091             }
1092             catch (int x)
1093             {
1094                 IsTrue(
1095                     x == 42,
1096                     L"Incorrect integer exception was received in t7 from taskresult.get(). Expected: 42, Actual: %d",
1097                     x);
1098                 pplx::details::atomic_add(n, 1000000L); // this should execute
1099             }
1100             catch (task_canceled)
1101             {
1102                 LogFailure(L"task_canceled was thrown by taskResult.get() in t7");
1103             }
1104             catch (...)
1105             {
1106                 LogFailure(L"A random exception was thrown by taskResult.get() in t7");
1107             }
1108 
1109             throw 96;
1110         });
1111 
1112         task<void> t8 = (t6 || t7).then([&n, this](task<void> taskResult) {
1113             try
1114             {
1115                 taskResult.get();
1116                 pplx::details::atomic_add(n, 1000000L); // this should NOT execute
1117             }
1118             catch (int x)
1119             {
1120                 IsTrue((x == 42 || x == 96),
1121                        L"Incorrect integer exception was received in t7 from taskresult.get(). Expected: 42 or 96, "
1122                        L"Actual: %d",
1123                        x);
1124                 pplx::details::atomic_add(n, 100000000L); // this should execute
1125             }
1126             catch (task_canceled)
1127             {
1128                 LogFailure(L"(t6 || t7) was canceled without an exception");
1129             }
1130             catch (...)
1131             {
1132                 LogFailure(L"(t6 || t7) was canceled with an unexpected exception");
1133             }
1134         });
1135 
1136         // Cancel t1 now that t2 is guaranteed canceled with an exception
1137         evt2.wait();
1138         ct.cancel();
1139         evt1.set();
1140 
1141         try
1142         {
1143             task_status status = (t1 && t2).wait();
1144             IsTrue((status == canceled),
1145                    L"(t1 && t2).wait() did not return canceled. Expected: %d, Actual %d",
1146                    canceled,
1147                    status);
1148         }
1149         catch (int x)
1150         {
1151             IsTrue(x == 42,
1152                    L"Incorrect integer exception was received from (t1 && t2).wait(). Expected: 42, Actual: %d",
1153                    x);
1154         }
1155 
1156         try
1157         {
1158             task_status status = t3.wait();
1159             IsTrue((status == canceled),
1160                    L"t3.wait() did not returned canceled. Expected: %d, Actual %d",
1161                    canceled,
1162                    status);
1163         }
1164         catch (task_canceled&)
1165         {
1166             LogFailure(L"t3.wait() threw task_canceled instead of returning canceled");
1167         }
1168         catch (...)
1169         {
1170             LogFailure(L"t3.wait() threw an unexpected exception");
1171         }
1172 
1173         try
1174         {
1175             task_status status = t4.wait();
1176             IsTrue((status == completed),
1177                    L"t4.wait() did not returned completed. Expected: %d, Actual %d",
1178                    completed,
1179                    status);
1180         }
1181         catch (...)
1182         {
1183             LogFailure(L"t4.wait() threw an unexpected exception");
1184         }
1185 
1186         try
1187         {
1188             t5.wait();
1189             LogFailure(L"t5.wait() did not throw an exception");
1190         }
1191         catch (int x)
1192         {
1193             IsTrue(x == 42, L"Incorrect integer exception was received from t5.wait(). Expected: 42, Actual: %d", x);
1194         }
1195 
1196         // Observe the exceptions from t5, t6 and t7
1197         helpers::ObserveException(t5);
1198         helpers::ObserveException(t6);
1199         helpers::ObserveException(t7);
1200 
1201         try
1202         {
1203             (t1 || t6).get();
1204             LogFailure(L"(t1 || t6).get() should throw an exception.");
1205         }
1206         catch (task_canceled&)
1207         {
1208             LogFailure(L"(t1 || t6).get() threw task_canceled when an int was expected.");
1209         }
1210         catch (int x)
1211         {
1212             IsTrue(
1213                 (x == 42 || x == 96),
1214                 L"Incorrect integer exception was received from (t1 || t6 || t7).get(). Expected: 42 or 96, Actual: %d",
1215                 x);
1216         }
1217 
1218         t8.wait();
1219 
1220         IsTrue(n == 101001010L,
1221                L"The right result was not obtained from the sequence of tasks that executed. Expected 101001010, "
1222                L"actual %d",
1223                101001010,
1224                static_cast<long>(n));
1225     }
1226 
1227     TEST(TestTaskOperators_when_all_cancellation)
1228     {
1229         // A task that participates in a 'when all' operation is canceled and then throws an exception. Verify that
1230         // value and task based continuations of the when all task see the exception.
1231         extensibility::event_t evt1, evt2;
1232 
1233         cancellation_token_source ct;
1234 
1235         task<void> t1(
1236             [&evt1, &evt2]() {
1237                 evt2.set();
1238                 evt1.wait();
1239                 os_utilities::sleep(100);
1240                 throw 42;
1241             },
1242             ct.get_token());
1243 
1244         task<void> t2([]() { helpers::DoRandomParallelWork(); });
1245 
1246         task<void> t3([]() { helpers::DoRandomParallelWork(); });
1247 
1248         task<void> whenAllTask = t1 && t2 && t3;
1249 
1250         task<void> t4 = whenAllTask.then([this](task<void> t) {
1251             IsFalse(helpers::VerifyCanceled(t), L"%ws:%u:t should be canceled by token", __FILE__, __LINE__);
1252             IsTrue(helpers::VerifyException<int>(t), L"%ws:%u:exception from t is unexpected", __FILE__, __LINE__);
1253         });
1254 
1255         task<void> t5 =
1256             whenAllTask.then([this]() { LogFailure(L"%ws:%u:t5 was unexpectedly executed", __FILE__, __LINE__); });
1257 
1258         evt2.wait();
1259         ct.cancel();
1260         evt1.set();
1261 
1262         IsFalse(helpers::VerifyCanceled(t5), L"%ws:%u:t5 should be canceled", __FILE__, __LINE__);
1263     }
1264 
1265     TEST(TestTaskOperators_when_all_cancellation_sequence)
1266     {
1267         // A task that participates in a 'when all' operation throws an exception, but a continuation of the when all
1268         // task is canceled before this point. Ensure that continuation does not get the exception but others do.
1269         extensibility::event_t evt1, evt2;
1270 
1271         cancellation_token_source ct;
1272 
1273         task<void> t1([&evt1, &evt2]() {
1274             evt2.set();
1275             evt1.wait();
1276             os_utilities::sleep(100);
1277             throw 42;
1278         });
1279 
1280         task<void> t2([]() { helpers::DoRandomParallelWork(); });
1281 
1282         task<void> t3([]() { helpers::DoRandomParallelWork(); });
1283 
1284         task<void> whenAllTask = t1 && t2 && t3;
1285 
1286         task<void> t4 = whenAllTask.then([this](task<void> t) {
1287             IsFalse(helpers::VerifyCanceled(t), L"%ws:%u:t was unexpectedly canceled", __FILE__, __LINE__);
1288             IsTrue(helpers::VerifyException<int>(t),
1289                    L"%ws:%u:Did not receive the correct exception from t",
1290                    __FILE__,
1291                    __LINE__);
1292         });
1293 
1294         task<void> t5 =
1295             whenAllTask.then([this]() { LogFailure(L"%ws:%u:t5 was unexpectedly executed", __FILE__, __LINE__); });
1296 
1297         task<void> t6 = whenAllTask.then(
1298             [this](task<void> t) {
1299                 IsTrue(helpers::VerifyCanceled(t), L"%ws:%u:t was not canceled as expected", __FILE__, __LINE__);
1300             },
1301             ct.get_token());
1302 
1303         evt2.wait();
1304         ct.cancel();
1305         evt1.set();
1306 
1307         IsTrue(helpers::VerifyException<int>(t5),
1308                L"%ws:%u:Did not receive the correct exception from t5",
1309                __FILE__,
1310                __LINE__);
1311     }
1312 
1313     TEST(TestTaskOperators_and_cancellation_multiple_tokens)
1314     //
1315     // operator&& with differing tokens:
1316     //
1317     {
1318         cancellation_token_source ct1;
1319         cancellation_token_source ct2;
1320         cancellation_token_source ct3;
1321         cancellation_token_source ct4;
1322 
1323         task<int> t1([]() -> int { return 42; }, ct1.get_token());
1324 
1325         task<int> t2([]() -> int { return 77; }, ct2.get_token());
1326 
1327         task<int> t3([]() -> int { return 92; }, ct3.get_token());
1328 
1329         task<int> t4([]() -> int { return 147; }, ct4.get_token());
1330 
1331         auto t5 = t1 && t2 && t3 && t4;
1332 
1333         extensibility::event_t ev1, ev2;
1334 
1335         auto t6 = t5.then([&ev1, &ev2](std::vector<int> iVec) -> int {
1336             ev2.set();
1337             ev1.wait();
1338             return iVec[0] + iVec[1] + iVec[2] + iVec[3];
1339         });
1340 
1341         auto t7 = t6.then([](int val) -> int { return val; });
1342 
1343         ev2.wait();
1344         ct3.cancel();
1345         ev1.set();
1346         t6.wait();
1347         t7.wait();
1348 
1349         bool caughtCanceled = false;
1350 
1351         try
1352         {
1353             t7.get();
1354         }
1355         catch (task_canceled&)
1356         {
1357             caughtCanceled = true;
1358         }
1359 
1360         IsTrue(caughtCanceled, L"Cancellation token was not joined/inherited on operator&&");
1361     }
1362 
1363     struct TestException1
1364     {
1365     };
1366 
1367     struct TestException2
1368     {
1369     };
1370 
1371     // CodePlex 292
1372     static int ThrowFunc() { throw 42; }
1373 
1374     TEST(TestContinuationsWithTask1)
1375     {
1376         int n2 = 0;
1377 
1378         task<int> t([&]() -> int { return 10; });
1379 
1380         t.then([&](task<int> ti) { n2 = ti.get(); }).wait();
1381 
1382         VERIFY_IS_TRUE(n2 == 10);
1383     }
1384 
1385     TEST(TestContinuationsWithTask2)
1386     {
1387         int n = 0;
1388 
1389         task<void> tt1([]() {});
1390         auto tt2 = tt1.then([&]() -> task<void> {
1391             task<void> tt3([&]() { n = 1; });
1392             return tt3;
1393         });
1394 
1395         tt2.get();
1396         VERIFY_IS_TRUE(n == 1);
1397 
1398         task<void> tt4 = tt2.then([&]() -> task<void> {
1399             task<void> tt5([&]() { n = 2; });
1400             return tt5;
1401         });
1402         tt4.get();
1403         VERIFY_IS_TRUE(n == 2);
1404     }
1405 
1406     TEST(TestContinuationsWithTask3)
1407     {
1408         bool gotException = true;
1409         int n2 = 0;
1410         task<int> t(ThrowFunc);
1411         t.then([&](task<int> ti) {
1412              try
1413              {
1414                  ti.get();
1415                  gotException = false;
1416              }
1417              catch (int)
1418              {
1419                  n2 = 20;
1420              }
1421          })
1422             .wait();
1423 
1424         VERIFY_IS_TRUE(gotException);
1425         VERIFY_IS_TRUE(n2 == 20);
1426     }
1427 
1428     TEST(TestContinuationsWithTask4)
1429     {
1430         int n2 = 0;
1431 
1432         task<int> t([&]() -> int { return 10; });
1433 
1434         t.then([&](int n) -> task<int> {
1435              task<int> t2([n]() -> int { return n + 10; });
1436              return t2;
1437          })
1438             .then([&](int n) { n2 = n; })
1439             .wait();
1440 
1441         VERIFY_IS_TRUE(n2 == 20);
1442     }
1443 
1444     TEST(TestContinuationsWithTask5)
1445     {
1446         int n2 = 0;
1447 
1448         task<int> t([&]() -> int { return 10; });
1449 
1450         t.then([&](task<int> tn) -> task<int> {
1451              int n = tn.get();
1452              task<int> t2([n]() -> int { return n + 10; });
1453              return t2;
1454          })
1455             .then([&](task<int> n) { n2 = n.get(); })
1456             .wait();
1457 
1458         VERIFY_IS_TRUE(n2 == 20);
1459     }
1460 
1461     TEST(TestContinuationsWithTask6)
1462     {
1463         pplx::details::atomic_long hit(0);
1464         auto* hitptr = &hit;
1465         task<int> t([]() { return 10; });
1466 
1467         auto ot = t.then([hitptr](int n) -> task<int> {
1468             auto hitptr1 = hitptr;
1469             task<int> it([n, hitptr1]() -> int {
1470                 os_utilities::sleep(100);
1471                 pplx::details::atomic_exchange(*hitptr1, 1L);
1472                 return n * 2;
1473             });
1474 
1475             return it;
1476         });
1477 
1478         int value = ot.get();
1479         VERIFY_IS_TRUE(value == 20 && hit != 0);
1480     }
1481 
1482     TEST(TestContinuationsWithTask7)
1483     {
1484         volatile long hit = 0;
1485         volatile long* hitptr = &hit;
1486 
1487         task<int> t([]() { return 10; });
1488 
1489         auto ot = t.then([hitptr](int n) -> task<int> {
1490             task<int> it([n, hitptr]() -> int { throw TestException1(); });
1491 
1492             return it;
1493         });
1494 
1495         VERIFY_IS_TRUE(helpers::VerifyException<TestException1>(ot));
1496     }
1497 
1498     TEST(TestContinuationsWithTask8)
1499     {
1500         volatile long hit = 0;
1501         volatile long* hitptr = &hit;
1502 
1503         task<int> t([]() { return 10; });
1504 
1505         auto ot = t.then([hitptr](int n) -> task<int> {
1506             volatile long* hitptr1 = hitptr;
1507             task<int> it([n, hitptr1]() -> int {
1508                 os_utilities::sleep(100);
1509                 os_utilities::interlocked_exchange(hitptr1, 1);
1510 
1511                 // This test is needed to disable an optimizer dead-code check that
1512                 // winds up generating errors in VS 2010.
1513                 if (n == 10) throw TestException2();
1514 
1515                 return n * 3;
1516             });
1517 
1518             return it;
1519         });
1520 
1521         VERIFY_IS_TRUE(helpers::VerifyException<TestException2>(ot),
1522                        "(7) Inner task exception not propagated out of outer .get()");
1523         VERIFY_IS_TRUE(hit != 0, "(7) Expected inner task hit marker to be set!");
1524     }
1525 
1526     TEST(TestContinuationsWithTask9)
1527     {
1528         volatile long hit = 0;
1529         volatile long* hitptr = &hit;
1530         extensibility::event_t e;
1531         task<int> it;
1532 
1533         task<int> t([]() { return 10; });
1534 
1535         auto ot = t.then([hitptr, &it, &e](int n) -> task<int> {
1536             volatile long* hitptr1 = hitptr;
1537             it = task<int>([hitptr1, n]() -> int {
1538                 os_utilities::interlocked_exchange(hitptr1, 1);
1539                 // This test is needed to disable an optimizer dead-code check that
1540                 // winds up generating errors in VS 2010.
1541                 if (n == 10) throw TestException1();
1542                 return n * 5;
1543             });
1544 
1545             e.set();
1546             os_utilities::sleep(100);
1547             // This test is needed to disable an optimizer dead-code check that
1548             // winds up generating errors in VS 2010.
1549             if (n == 10) throw TestException2();
1550             return it;
1551         });
1552 
1553         e.wait();
1554 
1555         VERIFY_IS_TRUE(helpers::VerifyException<TestException2>(ot),
1556                        "(8) Outer task exception not propagated when inner task also throws");
1557         VERIFY_IS_TRUE(helpers::VerifyException<TestException1>(it),
1558                        "(8) Inner task exception not explicitly propgated on pass out / get");
1559         VERIFY_IS_TRUE(hit != 0, "(8) Inner hit marker expected!");
1560     }
1561 
1562     TEST(TestContinuationsWithTask10)
1563     {
1564         volatile long hit = 0;
1565 
1566         task<int> t([]() { return 10; });
1567 
1568         auto ot = t.then([&](int n) -> task<int> {
1569             task<int> it([&, n]() -> int {
1570                 os_utilities::sleep(100);
1571                 // This test is needed to disable an optimizer dead-code check that
1572                 // winds up generating errors in VS 2010.
1573                 if (n == 10) throw TestException1();
1574                 return n * 6;
1575             });
1576             return it;
1577         });
1578 
1579         auto otc = ot.then([&](task<int> itp) {
1580             os_utilities::interlocked_exchange(&hit, 1);
1581             VERIFY_IS_TRUE(helpers::VerifyException<TestException1>(itp),
1582                            "(9) Outer task exception handling continuation did not get plumbed inner exception");
1583         });
1584 
1585         VERIFY_IS_TRUE(helpers::VerifyException<TestException1>(ot),
1586                        "(9) Inner task exception not propagated correctly");
1587         helpers::ObserveException(otc);
1588         VERIFY_IS_TRUE(hit != 0, "(9) Outer task exception handling continuation did not run!");
1589     }
1590 
1591     TEST(TestUnwrappingCtors)
1592     {
1593         int res;
1594         {
1595             // take task<int> in the ctor
1596 
1597             task<int> ti([]() -> int { return 1; });
1598 
1599             // Must unwrap:
1600             task<int> t1(ti);
1601             res = t1.get();
1602             VERIFY_IS_TRUE(res == 1, "unexpected value in TestUnwrappingCtors, location 1");
1603         }
1604 
1605         {
1606             // take lambda returning task<int> in the ctor
1607 
1608             // Must NOT unwrap:
1609             task<task<int>> t1([]() -> task<int> {
1610                 task<int> ti([]() -> int { return 1; });
1611                 return ti;
1612             });
1613             res = t1.get().get();
1614             VERIFY_IS_TRUE(res == 1, "unexpected value in TestUnwrappingCtors, location 2");
1615 
1616             // Must unwrap:
1617             task<int> t2([]() -> task<int> {
1618                 task<int> ti([]() -> int { return 2; });
1619                 return ti;
1620             });
1621             res = t2.get();
1622             VERIFY_IS_TRUE(res == 2, "unexpected value in TestUnwrappingCtors, location 3");
1623 
1624             res = t2.then([](int n) { return n + 1; }).get();
1625             VERIFY_IS_TRUE(res == 3, "unexpected value in TestUnwrappingCtors, location 4");
1626         }
1627 
1628         {
1629             int executed = 0;
1630             // take task<void> in the ctor
1631             task<void> ti([&]() { executed = 1; });
1632 
1633             // Must unwrap:
1634             task<void> t1(ti);
1635             t1.wait();
1636             VERIFY_IS_TRUE(executed == 1, "unexpected value in TestUnwrappingCtors, location 5");
1637         }
1638 
1639         {
1640             // take lambda returning task<void> in the ctor
1641 
1642             int executed = 0;
1643             int* executedPtr = &executed;
1644 
1645             // Must NOT unwrap:
1646             task<task<void>> t1([executedPtr]() -> task<void> {
1647                 auto executedPtr1 = executedPtr;
1648                 task<void> ti([executedPtr1]() { *executedPtr1 = 1; });
1649                 return ti;
1650             });
1651             t1.get().get();
1652             VERIFY_IS_TRUE(executed == 1, "unexpected value in TestUnwrappingCtors, location 6");
1653 
1654             task<void> t2([]() {});
1655             // Must unwrap:
1656             task<void> t3 = t2.then([executedPtr]() -> task<void> {
1657                 auto executedPtr1 = executedPtr;
1658                 task<void> ti([executedPtr1]() { *executedPtr1 = 2; });
1659                 return ti;
1660             });
1661 
1662             t3.wait();
1663             VERIFY_IS_TRUE(executed == 2, "unexpected value in TestUnwrappingCtors, location 7");
1664 
1665             // Must unwrap:
1666             task<void> t4([executedPtr]() -> task<void> {
1667                 auto executedPtr1 = executedPtr;
1668                 task<void> ti([executedPtr1]() { *executedPtr1 = 3; });
1669                 return ti;
1670             });
1671             t4.wait();
1672             VERIFY_IS_TRUE(executed == 3, "unexpected value in TestUnwrappingCtors, location 8");
1673 
1674             t4.then([&]() { executed++; }).wait();
1675             VERIFY_IS_TRUE(executed == 4, "unexpected value in TestUnwrappingCtors, location 9");
1676         }
1677 
1678         {
1679             res = create_task([]() -> task<int> { return create_task([]() -> int { return 1; }); }).get();
1680             VERIFY_IS_TRUE(res == 1, "unexpected value in TestUnwrappingCtors, create_task, location 1");
1681 
1682             create_task([]() -> task<void> { return create_task([]() {}); }).wait();
1683         }
1684 
1685         {
1686             // BUG TFS: 344954
1687             cancellation_token_source cts, cts2;
1688             cts.cancel(); // Commenting this line out makes the program work!
1689             // Create a task that is always cancelled
1690             auto falseTask = create_task([]() {}, cts.get_token());
1691             cancellation_token ct2 = cts2.get_token();
1692             create_task(
1693                 [falseTask]() {
1694                     // Task unwrapping!
1695                     // This should not crash
1696                     return falseTask;
1697                 },
1698                 ct2)
1699                 .then([this, falseTask, ct2](task<void> t) -> task<void> {
1700                     VERIFY_IS_TRUE(t.wait() == canceled,
1701                                    "unexpected value in TestUnwrappingCtors, cancellation token, location 1");
1702                     VERIFY_IS_TRUE(!ct2.is_canceled(),
1703                                    "unexpected value in TestUnwrappingCtors, cancellation token, location 2");
1704                     // again, unwrapping in continuation
1705                     // this should not crash
1706                     return falseTask;
1707                 })
1708                 .then([this] {
1709                     VERIFY_IS_TRUE(false, "unexpected path in TestUnwrappingCtors, cancellation token, location 3");
1710                 });
1711         }
1712     }
1713 
1714     TEST(TestNestedTasks)
1715     {
1716         {
1717             task<int> rootTask([]() -> int { return 234; });
1718 
1719             task<task<int>> resultTask = rootTask.then([](int value) -> task<task<int>> {
1720                 return task<task<int>>([=]() -> task<int> {
1721                     auto val1 = value;
1722                     return task<int>([=]() -> int { return val1 + 22; });
1723                 });
1724             });
1725 
1726             int n = resultTask.get().get();
1727             VERIFY_IS_TRUE(n == 256, "TestNestedTasks_1");
1728         }
1729 
1730         {
1731             // Same for void task
1732             int flag = 1;
1733             int* flagptr = &flag;
1734             task<void> rootTask([&]() { flag++; });
1735 
1736             task<task<void>> resultTask = rootTask.then([flagptr]() -> task<task<void>> {
1737                 auto flag1 = flagptr;
1738                 return task<task<void>>([flag1]() -> task<void> {
1739                     auto flag2 = flag1;
1740                     return task<void>([flag2]() { ++(flag2[0]); });
1741                 });
1742             });
1743 
1744             resultTask.get().wait();
1745             VERIFY_IS_TRUE(flag == 3, "TestNestedTasks_2");
1746         }
1747 
1748         {
1749             task<int> rootTask([]() -> int { return 234; });
1750 
1751             task<task<task<int>>> resultTask = rootTask.then([](int value) -> task<task<task<int>>> {
1752                 return task<task<task<int>>>([=]() -> task<task<int>> {
1753                     auto v1 = value;
1754                     return task<task<int>>([=]() -> task<int> {
1755                         auto v2 = v1;
1756                         return task<int>([=]() -> int { return v2 + 22; });
1757                     });
1758                 });
1759             });
1760 
1761             int n = resultTask.get().get().get();
1762             VERIFY_IS_TRUE(n == 256, "TestNestedTasks_3");
1763         }
1764 
1765         {
1766             task<void> nestedTask;
1767             task<void> unwrap([&]() -> task<void> {
1768                 nestedTask = task<void>([]() { cancel_current_task(); });
1769                 return nestedTask;
1770             });
1771             task_status st = unwrap.wait();
1772             VERIFY_IS_TRUE(st == canceled, "TestNestedTasks_4");
1773             st = nestedTask.wait();
1774             VERIFY_IS_TRUE(st == canceled, "TestNestedTasks_5 ");
1775         }
1776     }
1777 
1778     template<typename Function>
1779     task<void> async_for(int start, int step, int end, Function func)
1780     {
1781         if (start < end)
1782         {
1783             return func(start).then([=]() -> task<void> { return async_for(start + step, step, end, func); });
1784         }
1785         else
1786         {
1787             return task<void>([] {});
1788         }
1789     }
1790 
1791     TEST(TestInlineChunker)
1792     {
1793         const int numiter = 1000;
1794         volatile int sum = 0;
1795         async_for(0,
1796                   1,
1797                   numiter,
1798                   [&](int) -> task<void> {
1799                       sum++;
1800                       return create_task([]() {});
1801                   })
1802             .wait();
1803 
1804         VERIFY_IS_TRUE(sum == numiter, "TestInlineChunker: async_for did not return correct result.");
1805     }
1806 
1807 #if defined(_WIN32) && (_MSC_VER >= 1700) && (_MSC_VER < 1800)
1808 
1809     TEST(PPL_Conversions_basic)
1810     {
1811         pplx::task<int> t1([] { return 1; });
1812         concurrency::task<int> t2 = pplx::pplx_task_to_concurrency_task(t1);
1813         int n = t2.get();
1814         VERIFY_ARE_EQUAL(n, 1);
1815 
1816         pplx::task<int> t3 = pplx::concurrency_task_to_pplx_task(t2);
1817         int n2 = t3.get();
1818         VERIFY_ARE_EQUAL(n2, 1);
1819     }
1820 
1821     TEST(PPL_Conversions_Nested)
1822     {
1823         pplx::task<int> t1([] { return 12; });
1824         pplx::task<int> t2 = pplx::concurrency_task_to_pplx_task(pplx::pplx_task_to_concurrency_task(
1825             pplx::concurrency_task_to_pplx_task(pplx::pplx_task_to_concurrency_task(t1))));
1826         int n = t2.get();
1827         VERIFY_ARE_EQUAL(n, 12);
1828     }
1829 
1830     TEST(PPL_Conversions_Exceptions)
1831     {
1832         pplx::task<int> t1(ThrowFunc);
1833         concurrency::task<int> t2 = pplx::pplx_task_to_concurrency_task(t1);
1834         try
1835         {
1836             t2.get();
1837             VERIFY_IS_TRUE(false);
1838         }
1839         catch (int m)
1840         {
1841             VERIFY_ARE_EQUAL(m, 42);
1842         }
1843 
1844         pplx::task<int> t3 = pplx::concurrency_task_to_pplx_task(t2);
1845         try
1846         {
1847             t3.get();
1848             VERIFY_IS_TRUE(false);
1849         }
1850         catch (int m)
1851         {
1852             VERIFY_ARE_EQUAL(m, 42);
1853         }
1854     }
1855 
1856     TEST(PPL_Conversions_Basic_void)
1857     {
1858         pplx::task<void> t1([] {});
1859         concurrency::task<void> t2 = pplx::pplx_task_to_concurrency_task(t1);
1860         t2.get();
1861 
1862         pplx::task<void> t3 = pplx::concurrency_task_to_pplx_task(t2);
1863         t3.get();
1864     }
1865 
1866     TEST(PPL_Conversions_Exceptions_void)
1867     {
1868         pplx::task<void> t1([]() { throw 3; });
1869         concurrency::task<void> t2 = pplx::pplx_task_to_concurrency_task(t1);
1870         try
1871         {
1872             t2.get();
1873             VERIFY_IS_TRUE(false);
1874         }
1875         catch (int m)
1876         {
1877             VERIFY_ARE_EQUAL(m, 3);
1878         }
1879 
1880         pplx::task<void> t3 = pplx::concurrency_task_to_pplx_task(t2);
1881         try
1882         {
1883             t3.get();
1884             VERIFY_IS_TRUE(false);
1885         }
1886         catch (int m)
1887         {
1888             VERIFY_ARE_EQUAL(m, 3);
1889         }
1890     }
1891 
1892 #endif
1893 
1894 } // SUITE(pplxtask_tests)
1895 
1896 } // namespace PPLX
1897 } // namespace functional
1898 } // namespace tests
1899