You've already forked linux-packaging-mono
Imported Upstream version 5.0.0.42
Former-commit-id: fd56571888259555122d8a0f58c68838229cea2b
This commit is contained in:
parent
1190d13a04
commit
6bdd276d05
131
external/corefx/src/System.Threading.Tasks/tests/AggregateExceptionTests.cs
vendored
Normal file
131
external/corefx/src/System.Threading.Tasks/tests/AggregateExceptionTests.cs
vendored
Normal file
@ -0,0 +1,131 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using Xunit;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace System.Threading.Tasks.Tests
|
||||
{
|
||||
public class AggregateExceptionTests
|
||||
{
|
||||
[Fact]
|
||||
public static void ConstructorBasic()
|
||||
{
|
||||
AggregateException ex = new AggregateException();
|
||||
Assert.Equal(ex.InnerExceptions.Count, 0);
|
||||
Assert.True(ex.Message != null, "RunAggregateException_Constructor: FAILED. Message property is null when the default constructor is used, expected a default message");
|
||||
|
||||
ex = new AggregateException("message");
|
||||
Assert.Equal(ex.InnerExceptions.Count, 0);
|
||||
Assert.True(ex.Message != null, "RunAggregateException_Constructor: FAILED. Message property is null when the default constructor(string) is used");
|
||||
|
||||
ex = new AggregateException("message", new Exception());
|
||||
Assert.Equal(ex.InnerExceptions.Count, 1);
|
||||
Assert.True(ex.Message != null, "RunAggregateException_Constructor: FAILED. Message property is null when the default constructor(string, Exception) is used");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public static void ConstructorInvalidArguments()
|
||||
{
|
||||
AggregateException ex = new AggregateException();
|
||||
Assert.Throws<ArgumentNullException>(
|
||||
() => ex = new AggregateException("message", (Exception)null));
|
||||
|
||||
Assert.Throws<ArgumentNullException>(
|
||||
() => ex = new AggregateException("message", (IEnumerable<Exception>)null));
|
||||
|
||||
Assert.Throws<ArgumentException>(
|
||||
() => ex = new AggregateException("message", new[] { new Exception(), null }));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public static void BaseExceptions()
|
||||
{
|
||||
AggregateException ex = new AggregateException();
|
||||
Assert.Equal(ex.GetBaseException(), ex);
|
||||
|
||||
Exception[] innerExceptions = new Exception[0];
|
||||
ex = new AggregateException(innerExceptions);
|
||||
Assert.Equal(ex.GetBaseException(), ex);
|
||||
|
||||
innerExceptions = new Exception[1] { new AggregateException() };
|
||||
ex = new AggregateException(innerExceptions);
|
||||
Assert.Equal(ex.GetBaseException(), innerExceptions[0]);
|
||||
|
||||
innerExceptions = new Exception[2] { new AggregateException(), new AggregateException() };
|
||||
ex = new AggregateException(innerExceptions);
|
||||
Assert.Equal(ex.GetBaseException(), ex);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public static void Handle()
|
||||
{
|
||||
AggregateException ex = new AggregateException();
|
||||
ex = new AggregateException(new[] { new ArgumentException(), new ArgumentException(), new ArgumentException() });
|
||||
int handledCount = 0;
|
||||
ex.Handle((e) =>
|
||||
{
|
||||
if (e is ArgumentException)
|
||||
{
|
||||
handledCount++;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
Assert.Equal(handledCount, ex.InnerExceptions.Count);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public static void HandleInvalidCases()
|
||||
{
|
||||
AggregateException ex = new AggregateException();
|
||||
Assert.Throws<ArgumentNullException>(() => ex.Handle(null));
|
||||
|
||||
ex = new AggregateException(new[] { new Exception(), new ArgumentException(), new ArgumentException() });
|
||||
int handledCount = 0;
|
||||
Assert.Throws<AggregateException>(
|
||||
() => ex.Handle((e) =>
|
||||
{
|
||||
if (e is ArgumentException)
|
||||
{
|
||||
handledCount++;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}));
|
||||
}
|
||||
|
||||
// Validates that flattening (including recursive) works.
|
||||
[Fact]
|
||||
public static void Flatten()
|
||||
{
|
||||
Exception exceptionA = new Exception("A");
|
||||
Exception exceptionB = new Exception("B");
|
||||
Exception exceptionC = new Exception("C");
|
||||
|
||||
AggregateException aggExceptionBase = new AggregateException(exceptionA, exceptionB, exceptionC);
|
||||
|
||||
// Verify flattening one with another.
|
||||
// > Flattening (no recursion)...
|
||||
|
||||
AggregateException flattened1 = aggExceptionBase.Flatten();
|
||||
Exception[] expected1 = new Exception[] {
|
||||
exceptionA, exceptionB, exceptionC
|
||||
};
|
||||
|
||||
Assert.Equal(expected1, flattened1.InnerExceptions);
|
||||
|
||||
// Verify flattening one with another, accounting for recursion.
|
||||
AggregateException aggExceptionRecurse = new AggregateException(aggExceptionBase, aggExceptionBase);
|
||||
AggregateException flattened2 = aggExceptionRecurse.Flatten();
|
||||
Exception[] expected2 = new Exception[] {
|
||||
exceptionA, exceptionB, exceptionC, exceptionA, exceptionB, exceptionC,
|
||||
};
|
||||
|
||||
Assert.Equal(expected2, flattened2.InnerExceptions);
|
||||
}
|
||||
}
|
||||
}
|
624
external/corefx/src/System.Threading.Tasks/tests/CESchedulerPairTests.cs
vendored
Normal file
624
external/corefx/src/System.Threading.Tasks/tests/CESchedulerPairTests.cs
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1342
external/corefx/src/System.Threading.Tasks/tests/CancellationTokenTests.cs
vendored
Normal file
1342
external/corefx/src/System.Threading.Tasks/tests/CancellationTokenTests.cs
vendored
Normal file
File diff suppressed because it is too large
Load Diff
9
external/corefx/src/System.Threading.Tasks/tests/Configurations.props
vendored
Normal file
9
external/corefx/src/System.Threading.Tasks/tests/Configurations.props
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<BuildConfigurations>
|
||||
netstandard1.5;
|
||||
netstandard;
|
||||
</BuildConfigurations>
|
||||
</PropertyGroup>
|
||||
</Project>
|
255
external/corefx/src/System.Threading.Tasks/tests/MethodCoverage.cs
vendored
Normal file
255
external/corefx/src/System.Threading.Tasks/tests/MethodCoverage.cs
vendored
Normal file
@ -0,0 +1,255 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using System.Threading;
|
||||
using Xunit;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace TaskCoverage
|
||||
{
|
||||
public class Coverage
|
||||
{
|
||||
// Regression test: Validates that tasks can wait on int.MaxValue without assertion.
|
||||
[Fact]
|
||||
public static void TaskWait_MaxInt32()
|
||||
{
|
||||
Task t = Task.Delay(1);
|
||||
Debug.WriteLine("Wait with int.Maxvalue");
|
||||
Task.WaitAll(new Task[] { t }, int.MaxValue);
|
||||
}
|
||||
|
||||
//EH
|
||||
[Fact]
|
||||
[OuterLoop]
|
||||
public static void TaskContinuation()
|
||||
{
|
||||
int taskCount = Environment.ProcessorCount;
|
||||
int maxDOP = Int32.MaxValue;
|
||||
int maxNumberExecutionsPerTask = 1;
|
||||
int data = 0;
|
||||
|
||||
Task[] allTasks = new Task[taskCount + 1];
|
||||
|
||||
CancellationTokenSource[] cts = new CancellationTokenSource[taskCount + 1];
|
||||
for (int i = 0; i <= taskCount; i++)
|
||||
{
|
||||
cts[i] = new CancellationTokenSource();
|
||||
}
|
||||
|
||||
CancellationTokenSource cts2 = new CancellationTokenSource();
|
||||
ConcurrentExclusiveSchedulerPair scheduler = new ConcurrentExclusiveSchedulerPair(TaskScheduler.Default, maxDOP, maxNumberExecutionsPerTask);
|
||||
for (int i = 0; i <= taskCount; i++)
|
||||
{
|
||||
int j = i;
|
||||
allTasks[i] = new Task(() =>
|
||||
{
|
||||
new TaskFactory(TaskScheduler.Current).StartNew(() => { }).
|
||||
ContinueWith((task, o) =>
|
||||
{
|
||||
int d = (int)o;
|
||||
Interlocked.Add(ref data, d);
|
||||
}, j).
|
||||
ContinueWith((task, o) =>
|
||||
{
|
||||
int d = (int)o;
|
||||
Interlocked.Add(ref data, d);
|
||||
cts[d].Cancel();
|
||||
if (d <= taskCount)
|
||||
{
|
||||
throw new OperationCanceledException(cts[d].Token);
|
||||
}
|
||||
return "Done";
|
||||
}, j, cts[j].Token).
|
||||
ContinueWith((task, o) =>
|
||||
{
|
||||
int d = (int)o;
|
||||
Interlocked.Add(ref data, d);
|
||||
}, j, CancellationToken.None, TaskContinuationOptions.OnlyOnCanceled, TaskScheduler.Default).Wait(Int32.MaxValue - 1, cts2.Token);
|
||||
});
|
||||
|
||||
allTasks[i].Start(scheduler.ConcurrentScheduler);
|
||||
}
|
||||
|
||||
Task.WaitAll(allTasks, int.MaxValue - 1, CancellationToken.None);
|
||||
Debug.WriteLine("Tasks ended: result {0}", data);
|
||||
Task completion = scheduler.Completion;
|
||||
scheduler.Complete();
|
||||
completion.Wait();
|
||||
|
||||
int expectedResult = 3 * taskCount * (taskCount + 1) / 2;
|
||||
Assert.Equal(expectedResult, data);
|
||||
|
||||
Assert.NotEqual(TaskScheduler.Default.Id, scheduler.ConcurrentScheduler.Id);
|
||||
Assert.NotEqual(TaskScheduler.Default.Id, scheduler.ExclusiveScheduler.Id);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test various Task.WhenAll and Wait overloads - EH
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public static void TaskWaitWithCTS()
|
||||
{
|
||||
ManualResetEvent mre = new ManualResetEvent(false);
|
||||
ManualResetEvent mreCont = new ManualResetEvent(false);
|
||||
CancellationTokenSource cts = new CancellationTokenSource();
|
||||
|
||||
int? taskId1 = 0; int? taskId2 = 0;
|
||||
int? taskId12 = 0; int? taskId22 = 0;
|
||||
|
||||
Task t1 = Task.Factory.StartNew(() => { mre.WaitOne(); taskId1 = Task.CurrentId; });
|
||||
Task t2 = Task.Factory.StartNew(() => { mre.WaitOne(); taskId2 = Task.CurrentId; cts.Cancel(); });
|
||||
|
||||
List<Task<int?>> whenAllTaskResult = new List<Task<int?>>();
|
||||
List<Task> whenAllTask = new List<Task>();
|
||||
whenAllTask.Add(t1); whenAllTask.Add(t2);
|
||||
Task<int> contTask = Task.WhenAll(whenAllTask).ContinueWith<int>(
|
||||
(task) =>
|
||||
{
|
||||
// when task1 ends, the token will be cancelled
|
||||
// move the continuation task in cancellation state
|
||||
if (cts.IsCancellationRequested) { throw new OperationCanceledException(cts.Token); }
|
||||
return 0;
|
||||
}, cts.Token);
|
||||
contTask.ContinueWith((task) => { mreCont.Set(); });
|
||||
|
||||
whenAllTaskResult.Add(Task<int?>.Factory.StartNew((o) => { mre.WaitOne((int)o); return Task.CurrentId; }, 10));
|
||||
whenAllTaskResult.Add(Task<int?>.Factory.StartNew((o) => { mre.WaitOne((int)o); return Task.CurrentId; }, 10));
|
||||
|
||||
t1.Wait(5, cts.Token);
|
||||
Task.WhenAll(whenAllTaskResult).ContinueWith((task) => { taskId12 = task.Result[0]; taskId22 = task.Result[1]; mre.Set(); });
|
||||
// Task 2 calls CancellationTokenSource.Cancel. Thus, expect and not fail for System.OperationCanceledException being thrown.
|
||||
try
|
||||
{
|
||||
t2.Wait(cts.Token);
|
||||
}
|
||||
catch (System.OperationCanceledException) { } // expected, do nothing
|
||||
|
||||
Assert.NotEqual<int?>(taskId1, taskId2);
|
||||
Assert.NotEqual<int?>(taskId12, taskId22);
|
||||
|
||||
Debug.WriteLine("Waiting on continuation task that should move into the cancelled state.");
|
||||
mreCont.WaitOne();
|
||||
Assert.True(contTask.Status == TaskStatus.Canceled, "Task status is not correct");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// test WaitAny and when Any overloads
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public static void TaskWaitAny_WhenAny()
|
||||
{
|
||||
ManualResetEvent mre = new ManualResetEvent(false);
|
||||
ManualResetEvent mre2 = new ManualResetEvent(false);
|
||||
|
||||
CancellationTokenSource cts = new CancellationTokenSource();
|
||||
|
||||
Task t1 = Task.Factory.StartNew(() => { mre.WaitOne(); });
|
||||
Task t2 = Task.Factory.StartNew(() => { mre.WaitOne(); });
|
||||
|
||||
Task<int?> t11 = Task.Factory.StartNew(() => { mre2.WaitOne(); return Task.CurrentId; });
|
||||
Task<int?> t21 = Task.Factory.StartNew(() => { mre2.WaitOne(); return Task.CurrentId; });
|
||||
|
||||
|
||||
//waitAny with token and timeout
|
||||
Task[] waitAny = new Task[] { t1, t2 };
|
||||
int timeout = Task.WaitAny(waitAny, 1, cts.Token);
|
||||
|
||||
//task whenany
|
||||
Task.Factory.StartNew(() => { Task.Delay(20); mre.Set(); });
|
||||
List<Task> whenAnyTask = new List<Task>(); whenAnyTask.Add(t1); whenAnyTask.Add(t2);
|
||||
List<Task<int?>> whenAnyTaskResult = new List<Task<int?>>(); whenAnyTaskResult.Add(t11); whenAnyTaskResult.Add(t21);
|
||||
|
||||
//task<tresult> whenany
|
||||
int? taskId = 0; //this will be set to the first task<int?> ID that ends
|
||||
Task waitOnIt = Task.WhenAny(whenAnyTaskResult).ContinueWith((task) => { taskId = task.Result.Result; });
|
||||
Task.WhenAny(whenAnyTask).ContinueWith((task) => { mre2.Set(); });
|
||||
|
||||
Debug.WriteLine("Wait on the scenario to finish");
|
||||
waitOnIt.Wait();
|
||||
Assert.Equal<int>(-1, timeout);
|
||||
Assert.Equal<int>(t11.Id, t11.Result.Value);
|
||||
Assert.Equal<int>(t21.Id, t21.Result.Value);
|
||||
|
||||
bool whenAnyVerification = taskId == t11.Id || taskId == t21.Id;
|
||||
|
||||
Assert.True(whenAnyVerification, string.Format("The id for whenAny is not correct expected to be {0} or {1} and it is {2}", t11.Id, t21.Id, taskId));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public static void CancellationTokenRegitration()
|
||||
{
|
||||
ManualResetEvent mre = new ManualResetEvent(false);
|
||||
ManualResetEvent mre2 = new ManualResetEvent(false);
|
||||
|
||||
CancellationTokenSource cts = new CancellationTokenSource();
|
||||
cts.Token.Register((o) => { mre.Set(); }, 1, true);
|
||||
|
||||
cts.CancelAfter(5);
|
||||
Debug.WriteLine("Wait on the scenario to finish");
|
||||
mre.WaitOne();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// verify that the taskawaiter.UnsafeOnCompleted is invoked
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public static void TaskAwaiter()
|
||||
{
|
||||
ManualResetEvent mre = new ManualResetEvent(false);
|
||||
ManualResetEvent mre2 = new ManualResetEvent(false);
|
||||
ManualResetEvent mre3 = new ManualResetEvent(false);
|
||||
|
||||
Task t1 = Task.Factory.StartNew(() => { mre.WaitOne(); });
|
||||
Task<int> t11 = Task.Factory.StartNew(() => { mre.WaitOne(); return 1; });
|
||||
t1.GetAwaiter().UnsafeOnCompleted(() => { mre2.Set(); });
|
||||
t11.GetAwaiter().UnsafeOnCompleted(() => { mre3.Set(); });
|
||||
mre.Set();
|
||||
|
||||
Debug.WriteLine("Wait on the scenario to finish");
|
||||
mre2.WaitOne(); mre3.WaitOne();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// verify that the taskawaiter.UnsafeOnCompleted is invoked
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public static void TaskConfigurableAwaiter()
|
||||
{
|
||||
ManualResetEvent mre = new ManualResetEvent(false);
|
||||
ManualResetEvent mre2 = new ManualResetEvent(false);
|
||||
ManualResetEvent mre3 = new ManualResetEvent(false);
|
||||
|
||||
Task t1 = Task.Factory.StartNew(() => { mre.WaitOne(); });
|
||||
Task<int> t11 = Task.Factory.StartNew(() => { mre.WaitOne(); return 1; });
|
||||
t1.ConfigureAwait(false).GetAwaiter().UnsafeOnCompleted(() => { mre2.Set(); });
|
||||
t11.ConfigureAwait(false).GetAwaiter().UnsafeOnCompleted(() => { mre3.Set(); });
|
||||
mre.Set();
|
||||
|
||||
Debug.WriteLine("Wait on the scenario to finish");
|
||||
mre2.WaitOne(); mre3.WaitOne();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// FromAsync testing: Not supported in .NET Native
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public static void FromAsync()
|
||||
{
|
||||
Task emptyTask = new Task(() => { });
|
||||
ManualResetEvent mre1 = new ManualResetEvent(false);
|
||||
ManualResetEvent mre2 = new ManualResetEvent(false);
|
||||
|
||||
Task.Factory.FromAsync(emptyTask, (iar) => { mre1.Set(); }, TaskCreationOptions.None, TaskScheduler.Current);
|
||||
Task<int>.Factory.FromAsync(emptyTask, (iar) => { mre2.Set(); return 1; }, TaskCreationOptions.None, TaskScheduler.Current);
|
||||
emptyTask.Start();
|
||||
|
||||
Debug.WriteLine("Wait on the scenario to finish");
|
||||
mre1.WaitOne();
|
||||
mre2.WaitOne();
|
||||
}
|
||||
}
|
||||
}
|
29
external/corefx/src/System.Threading.Tasks/tests/OperationCanceledExceptionTests.cs
vendored
Normal file
29
external/corefx/src/System.Threading.Tasks/tests/OperationCanceledExceptionTests.cs
vendored
Normal file
@ -0,0 +1,29 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using Xunit;
|
||||
using System;
|
||||
using System.Threading;
|
||||
|
||||
namespace System.Threading.Tasks.Tests
|
||||
{
|
||||
public static class OperationCanceledExceptionTests
|
||||
{
|
||||
[Fact]
|
||||
public static void BasicConstructors()
|
||||
{
|
||||
CancellationToken ct1 = new CancellationTokenSource().Token;
|
||||
OperationCanceledException ex1 = new OperationCanceledException(ct1);
|
||||
Assert.Equal(ct1, ex1.CancellationToken);
|
||||
|
||||
CancellationToken ct2 = new CancellationTokenSource().Token;
|
||||
OperationCanceledException ex2 = new OperationCanceledException("message", ct2);
|
||||
Assert.Equal(ct2, ex2.CancellationToken);
|
||||
|
||||
CancellationToken ct3 = new CancellationTokenSource().Token;
|
||||
OperationCanceledException ex3 = new OperationCanceledException("message", new Exception("inner"), ct3);
|
||||
Assert.Equal(ct3, ex3.CancellationToken);
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
394
external/corefx/src/System.Threading.Tasks/tests/System.Runtime.CompilerServices/TaskAwaiterTests.cs
vendored
Normal file
394
external/corefx/src/System.Threading.Tasks/tests/System.Runtime.CompilerServices/TaskAwaiterTests.cs
vendored
Normal file
@ -0,0 +1,394 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.CompilerServices;
|
||||
using Xunit;
|
||||
|
||||
namespace System.Threading.Tasks.Tests
|
||||
{
|
||||
public class TaskAwaiterTests
|
||||
{
|
||||
[Theory]
|
||||
[InlineData(false, false)]
|
||||
[InlineData(false, true)]
|
||||
[InlineData(false, null)]
|
||||
[InlineData(true, false)]
|
||||
[InlineData(true, true)]
|
||||
[InlineData(true, null)]
|
||||
public static void OnCompleted_CompletesInAnotherSynchronizationContext(bool generic, bool? continueOnCapturedContext)
|
||||
{
|
||||
SynchronizationContext origCtx = SynchronizationContext.Current;
|
||||
try
|
||||
{
|
||||
// Create a context that tracks operations, and set it as current
|
||||
var validateCtx = new ValidateCorrectContextSynchronizationContext();
|
||||
Assert.Equal(0, validateCtx.PostCount);
|
||||
SynchronizationContext.SetSynchronizationContext(validateCtx);
|
||||
|
||||
// Create a not-completed task and get an awaiter for it
|
||||
var mres = new ManualResetEventSlim();
|
||||
var tcs = new TaskCompletionSource<object>();
|
||||
|
||||
// Hook up a callback
|
||||
bool postedInContext = false;
|
||||
Action callback = () =>
|
||||
{
|
||||
postedInContext = ValidateCorrectContextSynchronizationContext.IsPostedInContext;
|
||||
mres.Set();
|
||||
};
|
||||
if (generic)
|
||||
{
|
||||
if (continueOnCapturedContext.HasValue) tcs.Task.ConfigureAwait(continueOnCapturedContext.Value).GetAwaiter().OnCompleted(callback);
|
||||
else tcs.Task.GetAwaiter().OnCompleted(callback);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (continueOnCapturedContext.HasValue) ((Task)tcs.Task).ConfigureAwait(continueOnCapturedContext.Value).GetAwaiter().OnCompleted(callback);
|
||||
else ((Task)tcs.Task).GetAwaiter().OnCompleted(callback);
|
||||
}
|
||||
Assert.False(mres.IsSet, "Callback should not yet have run.");
|
||||
|
||||
// Complete the task in another context and wait for the callback to run
|
||||
Task.Run(() => tcs.SetResult(null));
|
||||
mres.Wait();
|
||||
|
||||
// Validate the callback ran and in the correct context
|
||||
bool shouldHavePosted = !continueOnCapturedContext.HasValue || continueOnCapturedContext.Value;
|
||||
Assert.Equal(shouldHavePosted ? 1 : 0, validateCtx.PostCount);
|
||||
Assert.Equal(shouldHavePosted, postedInContext);
|
||||
}
|
||||
finally
|
||||
{
|
||||
// Reset back to the original context
|
||||
SynchronizationContext.SetSynchronizationContext(origCtx);
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(false, false)]
|
||||
[InlineData(false, true)]
|
||||
[InlineData(false, null)]
|
||||
[InlineData(true, false)]
|
||||
[InlineData(true, true)]
|
||||
[InlineData(true, null)]
|
||||
public static void OnCompleted_CompletesInAnotherTaskScheduler(bool generic, bool? continueOnCapturedContext)
|
||||
{
|
||||
SynchronizationContext origCtx = SynchronizationContext.Current;
|
||||
try
|
||||
{
|
||||
SynchronizationContext.SetSynchronizationContext(null); // get off xunit's SynchronizationContext to avoid interactions with await
|
||||
|
||||
var quwi = new QUWITaskScheduler();
|
||||
RunWithSchedulerAsCurrent(quwi, delegate
|
||||
{
|
||||
Assert.True(TaskScheduler.Current == quwi, "Expected to be on target scheduler");
|
||||
|
||||
// Create the not completed task and get its awaiter
|
||||
var mres = new ManualResetEventSlim();
|
||||
var tcs = new TaskCompletionSource<object>();
|
||||
|
||||
// Hook up the callback
|
||||
bool ranOnScheduler = false;
|
||||
Action callback = () =>
|
||||
{
|
||||
ranOnScheduler = (TaskScheduler.Current == quwi);
|
||||
mres.Set();
|
||||
};
|
||||
if (generic)
|
||||
{
|
||||
if (continueOnCapturedContext.HasValue) tcs.Task.ConfigureAwait(continueOnCapturedContext.Value).GetAwaiter().OnCompleted(callback);
|
||||
else tcs.Task.GetAwaiter().OnCompleted(callback);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (continueOnCapturedContext.HasValue) ((Task)tcs.Task).ConfigureAwait(continueOnCapturedContext.Value).GetAwaiter().OnCompleted(callback);
|
||||
else ((Task)tcs.Task).GetAwaiter().OnCompleted(callback);
|
||||
}
|
||||
Assert.False(mres.IsSet, "Callback should not yet have run.");
|
||||
|
||||
// Complete the task in another scheduler and wait for the callback to run
|
||||
Task.Run(delegate { tcs.SetResult(null); });
|
||||
mres.Wait();
|
||||
|
||||
// Validate the callback ran on the right scheduler
|
||||
bool shouldHaveRunOnScheduler = !continueOnCapturedContext.HasValue || continueOnCapturedContext.Value;
|
||||
Assert.Equal(shouldHaveRunOnScheduler, ranOnScheduler);
|
||||
});
|
||||
}
|
||||
finally
|
||||
{
|
||||
SynchronizationContext.SetSynchronizationContext(origCtx);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public static void GetResult_Completed_Success()
|
||||
{
|
||||
Task task = Task.CompletedTask;
|
||||
task.GetAwaiter().GetResult();
|
||||
task.ConfigureAwait(false).GetAwaiter().GetResult();
|
||||
task.ConfigureAwait(true).GetAwaiter().GetResult();
|
||||
|
||||
const string expectedResult = "42";
|
||||
Task<string> taskOfString = Task.FromResult(expectedResult);
|
||||
Assert.Equal(expectedResult, taskOfString.GetAwaiter().GetResult());
|
||||
Assert.Equal(expectedResult, taskOfString.ConfigureAwait(false).GetAwaiter().GetResult());
|
||||
Assert.Equal(expectedResult, taskOfString.ConfigureAwait(true).GetAwaiter().GetResult());
|
||||
}
|
||||
|
||||
[OuterLoop]
|
||||
[Fact]
|
||||
public static void GetResult_NotCompleted_BlocksUntilCompletion()
|
||||
{
|
||||
var tcs = new TaskCompletionSource<bool>();
|
||||
|
||||
// Kick off tasks that should all block
|
||||
var tasks = new[] {
|
||||
Task.Run(() => tcs.Task.GetAwaiter().GetResult()),
|
||||
Task.Run(() => ((Task)tcs.Task).GetAwaiter().GetResult()),
|
||||
Task.Run(() => tcs.Task.ConfigureAwait(false).GetAwaiter().GetResult()),
|
||||
Task.Run(() => ((Task)tcs.Task).ConfigureAwait(false).GetAwaiter().GetResult())
|
||||
};
|
||||
Assert.Equal(-1, Task.WaitAny(tasks, 100)); // "Tasks should not have completed"
|
||||
|
||||
// Now complete the tasks, after which all the tasks should complete successfully.
|
||||
tcs.SetResult(true);
|
||||
Task.WaitAll(tasks);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public static void GetResult_CanceledTask_ThrowsCancellationException()
|
||||
{
|
||||
// Validate cancellation
|
||||
Task<string> canceled = Task.FromCanceled<string>(new CancellationToken(true));
|
||||
|
||||
// Task.GetAwaiter and Task<T>.GetAwaiter
|
||||
Assert.Throws<TaskCanceledException>(() => ((Task)canceled).GetAwaiter().GetResult());
|
||||
Assert.Throws<TaskCanceledException>(() => canceled.GetAwaiter().GetResult());
|
||||
|
||||
// w/ ConfigureAwait false and true
|
||||
Assert.Throws<TaskCanceledException>(() => ((Task)canceled).ConfigureAwait(false).GetAwaiter().GetResult());
|
||||
Assert.Throws<TaskCanceledException>(() => ((Task)canceled).ConfigureAwait(true).GetAwaiter().GetResult());
|
||||
Assert.Throws<TaskCanceledException>(() => canceled.ConfigureAwait(false).GetAwaiter().GetResult());
|
||||
Assert.Throws<TaskCanceledException>(() => canceled.ConfigureAwait(true).GetAwaiter().GetResult());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public static void GetResult_FaultedTask_OneException_ThrowsOriginalException()
|
||||
{
|
||||
var exception = new ArgumentException("uh oh");
|
||||
Task<string> task = Task.FromException<string>(exception);
|
||||
|
||||
// Task.GetAwaiter and Task<T>.GetAwaiter
|
||||
Assert.Same(exception, Assert.Throws<ArgumentException>(() => ((Task)task).GetAwaiter().GetResult()));
|
||||
Assert.Same(exception, Assert.Throws<ArgumentException>(() => task.GetAwaiter().GetResult()));
|
||||
|
||||
// w/ ConfigureAwait false and true
|
||||
Assert.Same(exception, Assert.Throws<ArgumentException>(() => ((Task)task).ConfigureAwait(false).GetAwaiter().GetResult()));
|
||||
Assert.Same(exception, Assert.Throws<ArgumentException>(() => ((Task)task).ConfigureAwait(true).GetAwaiter().GetResult()));
|
||||
Assert.Same(exception, Assert.Throws<ArgumentException>(() => task.ConfigureAwait(false).GetAwaiter().GetResult()));
|
||||
Assert.Same(exception, Assert.Throws<ArgumentException>(() => task.ConfigureAwait(true).GetAwaiter().GetResult()));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public static void GetResult_FaultedTask_MultipleExceptions_ThrowsFirstException()
|
||||
{
|
||||
var exception = new ArgumentException("uh oh");
|
||||
var tcs = new TaskCompletionSource<string>();
|
||||
tcs.SetException(new Exception[] { exception, new InvalidOperationException("uh oh") });
|
||||
Task<string> task = tcs.Task;
|
||||
|
||||
// Task.GetAwaiter and Task<T>.GetAwaiter
|
||||
Assert.Same(exception, Assert.Throws<ArgumentException>(() => ((Task)task).GetAwaiter().GetResult()));
|
||||
Assert.Same(exception, Assert.Throws<ArgumentException>(() => task.GetAwaiter().GetResult()));
|
||||
|
||||
// w/ ConfigureAwait false and true
|
||||
Assert.Same(exception, Assert.Throws<ArgumentException>(() => ((Task)task).ConfigureAwait(false).GetAwaiter().GetResult()));
|
||||
Assert.Same(exception, Assert.Throws<ArgumentException>(() => ((Task)task).ConfigureAwait(true).GetAwaiter().GetResult()));
|
||||
Assert.Same(exception, Assert.Throws<ArgumentException>(() => task.ConfigureAwait(false).GetAwaiter().GetResult()));
|
||||
Assert.Same(exception, Assert.Throws<ArgumentException>(() => task.ConfigureAwait(true).GetAwaiter().GetResult()));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public static void AwaiterAndAwaitableEquality()
|
||||
{
|
||||
var completed = new TaskCompletionSource<string>();
|
||||
Task task = completed.Task;
|
||||
|
||||
// TaskAwaiter
|
||||
task.GetAwaiter().Equals(task.GetAwaiter());
|
||||
|
||||
// ConfiguredTaskAwaitable
|
||||
Assert.Equal(task.ConfigureAwait(false), task.ConfigureAwait(false));
|
||||
Assert.NotEqual(task.ConfigureAwait(false), task.ConfigureAwait(true));
|
||||
Assert.NotEqual(task.ConfigureAwait(true), task.ConfigureAwait(false));
|
||||
|
||||
// ConfiguredTaskAwaitable<T>
|
||||
Assert.Equal(task.ConfigureAwait(false), task.ConfigureAwait(false));
|
||||
Assert.NotEqual(task.ConfigureAwait(false), task.ConfigureAwait(true));
|
||||
Assert.NotEqual(task.ConfigureAwait(true), task.ConfigureAwait(false));
|
||||
|
||||
// ConfiguredTaskAwaitable.ConfiguredTaskAwaiter
|
||||
Assert.Equal(task.ConfigureAwait(false).GetAwaiter(), task.ConfigureAwait(false).GetAwaiter());
|
||||
Assert.NotEqual(task.ConfigureAwait(false).GetAwaiter(), task.ConfigureAwait(true).GetAwaiter());
|
||||
Assert.NotEqual(task.ConfigureAwait(true).GetAwaiter(), task.ConfigureAwait(false).GetAwaiter());
|
||||
|
||||
// ConfiguredTaskAwaitable<T>.ConfiguredTaskAwaiter
|
||||
Assert.Equal(task.ConfigureAwait(false).GetAwaiter(), task.ConfigureAwait(false).GetAwaiter());
|
||||
Assert.NotEqual(task.ConfigureAwait(false).GetAwaiter(), task.ConfigureAwait(true).GetAwaiter());
|
||||
Assert.NotEqual(task.ConfigureAwait(true).GetAwaiter(), task.ConfigureAwait(false).GetAwaiter());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public static void BaseSynchronizationContext_SameAsNoSynchronizationContext()
|
||||
{
|
||||
var quwi = new QUWITaskScheduler();
|
||||
SynchronizationContext origCtx = SynchronizationContext.Current;
|
||||
try
|
||||
{
|
||||
SynchronizationContext.SetSynchronizationContext(new SynchronizationContext());
|
||||
RunWithSchedulerAsCurrent(quwi, delegate
|
||||
{
|
||||
ManualResetEventSlim mres = new ManualResetEventSlim();
|
||||
var tcs = new TaskCompletionSource<object>();
|
||||
var awaiter = ((Task)tcs.Task).GetAwaiter();
|
||||
|
||||
bool ranOnScheduler = false;
|
||||
bool ranWithoutSyncCtx = false;
|
||||
awaiter.OnCompleted(() =>
|
||||
{
|
||||
ranOnScheduler = (TaskScheduler.Current == quwi);
|
||||
ranWithoutSyncCtx = SynchronizationContext.Current == null;
|
||||
mres.Set();
|
||||
});
|
||||
Assert.False(mres.IsSet, "Callback should not yet have run.");
|
||||
|
||||
Task.Run(delegate { tcs.SetResult(null); });
|
||||
mres.Wait();
|
||||
|
||||
Assert.True(ranOnScheduler, "Should have run on scheduler");
|
||||
Assert.True(ranWithoutSyncCtx, "Should have run with a null sync ctx");
|
||||
});
|
||||
}
|
||||
finally
|
||||
{
|
||||
SynchronizationContext.SetSynchronizationContext(origCtx);
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(CanceledTasksAndExpectedCancellationExceptions))]
|
||||
public static void OperationCanceledException_PropagatesThroughCanceledTask(int lineNumber, Task task, OperationCanceledException expected)
|
||||
{
|
||||
var caught = Assert.ThrowsAny<OperationCanceledException>(() => task.GetAwaiter().GetResult());
|
||||
Assert.Same(expected, caught);
|
||||
}
|
||||
|
||||
public static IEnumerable<object[]> CanceledTasksAndExpectedCancellationExceptions()
|
||||
{
|
||||
var cts = new CancellationTokenSource();
|
||||
var oce = new OperationCanceledException(cts.Token);
|
||||
|
||||
// Scheduled Task
|
||||
Task<int> generic = Task.Run<int>(new Func<int>(() =>
|
||||
{
|
||||
cts.Cancel();
|
||||
throw oce;
|
||||
}), cts.Token);
|
||||
yield return new object[] { LineNumber(), generic, oce };
|
||||
|
||||
Task nonGeneric = generic;
|
||||
|
||||
// WhenAll Task and Task<int>
|
||||
yield return new object[] { LineNumber(), Task.WhenAll(generic), oce };
|
||||
yield return new object[] { LineNumber(), Task.WhenAll(generic, Task.FromResult(42)), oce };
|
||||
yield return new object[] { LineNumber(), Task.WhenAll(Task.FromResult(42), generic), oce };
|
||||
yield return new object[] { LineNumber(), Task.WhenAll(generic, generic, generic), oce };
|
||||
yield return new object[] { LineNumber(), Task.WhenAll(nonGeneric), oce };
|
||||
yield return new object[] { LineNumber(), Task.WhenAll(nonGeneric, Task.FromResult(42)), oce };
|
||||
yield return new object[] { LineNumber(), Task.WhenAll(Task.FromResult(42), nonGeneric), oce };
|
||||
yield return new object[] { LineNumber(), Task.WhenAll(nonGeneric, nonGeneric, nonGeneric), oce };
|
||||
|
||||
// Task.Run Task and Task<int> with unwrapping
|
||||
yield return new object[] { LineNumber(), Task.Run(() => generic), oce };
|
||||
yield return new object[] { LineNumber(), Task.Run(() => nonGeneric), oce };
|
||||
|
||||
// A FromAsync Task and Task<int>
|
||||
yield return new object[] { LineNumber(), Task.Factory.FromAsync(generic, new Action<IAsyncResult>(ar => { throw oce; })), oce };
|
||||
yield return new object[] { LineNumber(), Task<int>.Factory.FromAsync(nonGeneric, new Func<IAsyncResult, int>(ar => { throw oce; })), oce };
|
||||
|
||||
// AsyncTaskMethodBuilder
|
||||
var atmb = new AsyncTaskMethodBuilder();
|
||||
atmb.SetException(oce);
|
||||
yield return new object[] { LineNumber(), atmb.Task, oce };
|
||||
}
|
||||
|
||||
private static int LineNumber([CallerLineNumber]int lineNumber = 0) => lineNumber;
|
||||
|
||||
private class ValidateCorrectContextSynchronizationContext : SynchronizationContext
|
||||
{
|
||||
[ThreadStatic]
|
||||
internal static bool IsPostedInContext;
|
||||
|
||||
internal int PostCount;
|
||||
internal int SendCount;
|
||||
|
||||
public override void Post(SendOrPostCallback d, object state)
|
||||
{
|
||||
Interlocked.Increment(ref PostCount);
|
||||
Task.Run(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
IsPostedInContext = true;
|
||||
d(state);
|
||||
}
|
||||
finally
|
||||
{
|
||||
IsPostedInContext = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public override void Send(SendOrPostCallback d, object state)
|
||||
{
|
||||
Interlocked.Increment(ref SendCount);
|
||||
d(state);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>A scheduler that queues to the TP and tracks the number of times QueueTask and TryExecuteTaskInline are invoked.</summary>
|
||||
private class QUWITaskScheduler : TaskScheduler
|
||||
{
|
||||
private int _queueTaskCount;
|
||||
private int _tryExecuteTaskInlineCount;
|
||||
|
||||
public int QueueTaskCount { get { return _queueTaskCount; } }
|
||||
public int TryExecuteTaskInlineCount { get { return _tryExecuteTaskInlineCount; } }
|
||||
|
||||
protected override IEnumerable<Task> GetScheduledTasks() { return null; }
|
||||
|
||||
protected override void QueueTask(Task task)
|
||||
{
|
||||
Interlocked.Increment(ref _queueTaskCount);
|
||||
Task.Run(() => TryExecuteTask(task));
|
||||
}
|
||||
|
||||
protected override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued)
|
||||
{
|
||||
Interlocked.Increment(ref _tryExecuteTaskInlineCount);
|
||||
return TryExecuteTask(task);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Runs the action with TaskScheduler.Current equal to the specified scheduler.</summary>
|
||||
private static void RunWithSchedulerAsCurrent(TaskScheduler scheduler, Action action)
|
||||
{
|
||||
var t = new Task(action);
|
||||
t.RunSynchronously(scheduler);
|
||||
t.GetAwaiter().GetResult();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,202 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using Xunit;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace System.Threading.Tasks.Tests
|
||||
{
|
||||
public class YieldAwaitableTests
|
||||
{
|
||||
// awaiting Task.Yield
|
||||
[Fact]
|
||||
public static void RunAsyncYieldAwaiterTests()
|
||||
{
|
||||
// Test direct usage works even though it's not encouraged
|
||||
{
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
SynchronizationContext.SetSynchronizationContext(new ValidateCorrectContextSynchronizationContext());
|
||||
var ya = i == 0 ? new YieldAwaitable.YieldAwaiter() : new YieldAwaitable().GetAwaiter();
|
||||
var mres = new ManualResetEventSlim();
|
||||
Assert.False(ya.IsCompleted, "RunAsyncYieldAwaiterTests > FAILURE. YieldAwaiter.IsCompleted should always be false.");
|
||||
ya.OnCompleted(() =>
|
||||
{
|
||||
Assert.True(ValidateCorrectContextSynchronizationContext.IsPostedInContext, "RunAsyncYieldAwaiterTests > FAILURE. Expected to post in target context.");
|
||||
mres.Set();
|
||||
});
|
||||
mres.Wait();
|
||||
ya.GetResult();
|
||||
SynchronizationContext.SetSynchronizationContext(null);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
// Yield when there's a current sync context
|
||||
SynchronizationContext.SetSynchronizationContext(new ValidateCorrectContextSynchronizationContext());
|
||||
var ya = Task.Yield().GetAwaiter();
|
||||
try { ya.GetResult(); }
|
||||
catch
|
||||
{
|
||||
Assert.True(false, string.Format("RunAsyncYieldAwaiterTests > FAILURE. YieldAwaiter.GetResult threw inappropriately"));
|
||||
}
|
||||
var mres = new ManualResetEventSlim();
|
||||
Assert.False(ya.IsCompleted, "RunAsyncYieldAwaiterTests > FAILURE. YieldAwaiter.IsCompleted should always be false.");
|
||||
ya.OnCompleted(() =>
|
||||
{
|
||||
Assert.True(ValidateCorrectContextSynchronizationContext.IsPostedInContext, " > FAILURE. Expected to post in target context.");
|
||||
mres.Set();
|
||||
});
|
||||
mres.Wait();
|
||||
ya.GetResult();
|
||||
SynchronizationContext.SetSynchronizationContext(null);
|
||||
}
|
||||
|
||||
{
|
||||
// Yield when there's a current TaskScheduler
|
||||
Task.Factory.StartNew(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var ya = Task.Yield().GetAwaiter();
|
||||
try { ya.GetResult(); }
|
||||
catch
|
||||
{
|
||||
Assert.True(false, string.Format(" > FAILURE. YieldAwaiter.GetResult threw inappropriately"));
|
||||
}
|
||||
var mres = new ManualResetEventSlim();
|
||||
Assert.False(ya.IsCompleted, " > FAILURE. YieldAwaiter.IsCompleted should always be false.");
|
||||
ya.OnCompleted(() =>
|
||||
{
|
||||
Assert.True(TaskScheduler.Current is QUWITaskScheduler, " > FAILURE. Expected to queue into target scheduler.");
|
||||
mres.Set();
|
||||
});
|
||||
mres.Wait();
|
||||
ya.GetResult();
|
||||
}
|
||||
catch { Assert.True(false, string.Format(" > FAILURE. Unexpected exception from Yield")); }
|
||||
}, CancellationToken.None, TaskCreationOptions.None, new QUWITaskScheduler()).Wait();
|
||||
}
|
||||
|
||||
{
|
||||
// Yield when there's a current TaskScheduler and SynchronizationContext.Current is the base SynchronizationContext
|
||||
Task.Factory.StartNew(() =>
|
||||
{
|
||||
SynchronizationContext.SetSynchronizationContext(new SynchronizationContext());
|
||||
try
|
||||
{
|
||||
var ya = Task.Yield().GetAwaiter();
|
||||
try { ya.GetResult(); }
|
||||
catch
|
||||
{
|
||||
Assert.True(false, string.Format(" > FAILURE. YieldAwaiter.GetResult threw inappropriately"));
|
||||
}
|
||||
var mres = new ManualResetEventSlim();
|
||||
Assert.False(ya.IsCompleted, " > FAILURE. YieldAwaiter.IsCompleted should always be false.");
|
||||
ya.OnCompleted(() =>
|
||||
{
|
||||
Assert.True(TaskScheduler.Current is QUWITaskScheduler, " > FAILURE. Expected to queue into target scheduler.");
|
||||
mres.Set();
|
||||
});
|
||||
mres.Wait();
|
||||
ya.GetResult();
|
||||
}
|
||||
catch { Assert.True(false, string.Format(" > FAILURE. Unexpected exception from Yield")); }
|
||||
SynchronizationContext.SetSynchronizationContext(null);
|
||||
}, CancellationToken.None, TaskCreationOptions.None, new QUWITaskScheduler()).Wait();
|
||||
}
|
||||
|
||||
{
|
||||
// OnCompleted grabs the current context, not Task.Yield nor GetAwaiter
|
||||
SynchronizationContext.SetSynchronizationContext(new SynchronizationContext());
|
||||
var ya = Task.Yield().GetAwaiter();
|
||||
SynchronizationContext.SetSynchronizationContext(new ValidateCorrectContextSynchronizationContext());
|
||||
try { ya.GetResult(); }
|
||||
catch
|
||||
{
|
||||
Assert.True(false, string.Format(" > FAILURE. YieldAwaiter.GetResult threw inappropriately"));
|
||||
}
|
||||
var mres = new ManualResetEventSlim();
|
||||
Assert.False(ya.IsCompleted, " > FAILURE. YieldAwaiter.IsCompleted should always be false.");
|
||||
ya.OnCompleted(() =>
|
||||
{
|
||||
Assert.True(ValidateCorrectContextSynchronizationContext.IsPostedInContext, " > FAILURE. Expected to post in target context.");
|
||||
mres.Set();
|
||||
});
|
||||
mres.Wait();
|
||||
ya.GetResult();
|
||||
SynchronizationContext.SetSynchronizationContext(null);
|
||||
}
|
||||
}
|
||||
|
||||
// awaiting Task.Yield
|
||||
[Fact]
|
||||
public static void RunAsyncYieldAwaiterTests_Negative()
|
||||
{
|
||||
// Yield when there's a current sync context
|
||||
SynchronizationContext.SetSynchronizationContext(new ValidateCorrectContextSynchronizationContext());
|
||||
var ya = Task.Yield().GetAwaiter();
|
||||
Assert.Throws<ArgumentNullException>(() => { ya.OnCompleted(null); });
|
||||
}
|
||||
|
||||
#region Helper Methods / Classes
|
||||
|
||||
private class ValidateCorrectContextSynchronizationContext : SynchronizationContext
|
||||
{
|
||||
[ThreadStatic]
|
||||
internal static bool IsPostedInContext;
|
||||
|
||||
internal int PostCount;
|
||||
internal int SendCount;
|
||||
|
||||
public override void Post(SendOrPostCallback d, object state)
|
||||
{
|
||||
Interlocked.Increment(ref PostCount);
|
||||
Task.Run(() =>
|
||||
{
|
||||
IsPostedInContext = true;
|
||||
d(state);
|
||||
IsPostedInContext = false;
|
||||
});
|
||||
}
|
||||
|
||||
public override void Send(SendOrPostCallback d, object state)
|
||||
{
|
||||
Interlocked.Increment(ref SendCount);
|
||||
d(state);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>A scheduler that queues to the TP and tracks the number of times QueueTask and TryExecuteTaskInline are invoked.</summary>
|
||||
private class QUWITaskScheduler : TaskScheduler
|
||||
{
|
||||
private int _queueTaskCount;
|
||||
private int _tryExecuteTaskInlineCount;
|
||||
|
||||
public int QueueTaskCount { get { return _queueTaskCount; } }
|
||||
public int TryExecuteTaskInlineCount { get { return _tryExecuteTaskInlineCount; } }
|
||||
|
||||
protected override IEnumerable<Task> GetScheduledTasks() { return null; }
|
||||
|
||||
protected override void QueueTask(Task task)
|
||||
{
|
||||
Interlocked.Increment(ref _queueTaskCount);
|
||||
Task.Run(() => TryExecuteTask(task));
|
||||
}
|
||||
|
||||
protected override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued)
|
||||
{
|
||||
Interlocked.Increment(ref _tryExecuteTaskInlineCount);
|
||||
return TryExecuteTask(task);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
17
external/corefx/src/System.Threading.Tasks/tests/System.Threading.Tasks.Tests.builds
vendored
Normal file
17
external/corefx/src/System.Threading.Tasks/tests/System.Threading.Tasks.Tests.builds
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
|
||||
<ItemGroup>
|
||||
<Project Include="System.Threading.Tasks.Tests.csproj" />
|
||||
<Project Include="System.Threading.Tasks.Tests.csproj">
|
||||
<TargetGroup>netstandard1.5</TargetGroup>
|
||||
<TestTFMs>netcoreapp1.0</TestTFMs>
|
||||
</Project>
|
||||
<Project Include="System.Threading.Tasks.Tests.csproj">
|
||||
<TargetGroup>netstandard1.5</TargetGroup>
|
||||
<OSGroup>Windows_NT</OSGroup>
|
||||
<TestTFMs>net462</TestTFMs>
|
||||
</Project>
|
||||
</ItemGroup>
|
||||
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.traversal.targets))\dir.traversal.targets" />
|
||||
</Project>
|
58
external/corefx/src/System.Threading.Tasks/tests/System.Threading.Tasks.Tests.csproj
vendored
Normal file
58
external/corefx/src/System.Threading.Tasks/tests/System.Threading.Tasks.Tests.csproj
vendored
Normal file
@ -0,0 +1,58 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
|
||||
<PropertyGroup>
|
||||
<ProjectGuid>{B6C09633-D161-499A-8FE1-46B2D53A16E7}</ProjectGuid>
|
||||
</PropertyGroup>
|
||||
<!-- Default configurations to help VS understand the configurations -->
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='netstandard1.5-Debug|AnyCPU'" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='netstandard1.5-Release|AnyCPU'" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='netstandard-Debug|AnyCPU'" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='netstandard-Release|AnyCPU'" />
|
||||
<ItemGroup>
|
||||
<Compile Include="XunitAssemblyAttributes.cs" />
|
||||
<Compile Include="UnwrapTests.cs" />
|
||||
<Compile Include="AggregateExceptionTests.cs" />
|
||||
<Compile Include="OperationCanceledExceptionTests.cs" />
|
||||
<Compile Include="CancellationTokenTests.cs" />
|
||||
<Compile Include="MethodCoverage.cs" />
|
||||
<Compile Include="CESchedulerPairTests.cs" />
|
||||
<!-- Task -->
|
||||
<Compile Include="Task\RunContinuationsAsynchronouslyTests.cs" />
|
||||
<Compile Include="Task\TPLTestException.cs" />
|
||||
<Compile Include="Task\TaskRunSyncTests.cs" />
|
||||
<Compile Include="Task\TaskStatusTest.cs" />
|
||||
<Compile Include="Task\TaskPropertiesTests.cs" />
|
||||
<Compile Include="Task\TaskCreateTest.cs" />
|
||||
<Compile Include="Task\TaskWaitAllAnyTest.cs" />
|
||||
<Compile Include="Task\TaskContinueWithTests.cs" />
|
||||
<Compile Include="Task\TaskContinueWithAllAnyTests.cs" />
|
||||
<Compile Include="Task\TaskContinueWith_ContFuncAndActionWithArgsTests.cs" />
|
||||
<Compile Include="Task\TaskContinueWith_ContFuncAndActionTests.cs" />
|
||||
<Compile Include="Task\TaskContinueWhenAnyTests.cs" />
|
||||
<Compile Include="Task\TaskContinueWhenAllTests.cs" />
|
||||
<Compile Include="Task\TaskFromAsyncWork.cs" />
|
||||
<Compile Include="Task\TaskFromAsyncTest.cs" />
|
||||
<Compile Include="Task\TaskCancelWaitTests.cs" />
|
||||
<Compile Include="Task\TaskCancelWaitTest.cs" />
|
||||
<Compile Include="Task\TaskRtTests.cs" />
|
||||
<Compile Include="Task\TaskRtTests_Core.cs" />
|
||||
<Compile Include="Task\TaskAPMTest.cs" />
|
||||
<!-- TaskFactory -->
|
||||
<Compile Include="TaskFactory\TaskFactory_FromAsyncTests.cs" />
|
||||
<Compile Include="TaskFactory\TaskFactoryTests.cs" />
|
||||
<!-- TaskScheduler -->
|
||||
<Compile Include="TaskScheduler\TaskSchedulerTests.cs" />
|
||||
<!-- System.Runtime.CompilerServices -->
|
||||
<Compile Include="System.Runtime.CompilerServices\TaskAwaiterTests.cs" />
|
||||
<Compile Include="System.Runtime.CompilerServices\YieldAwaitableTests.cs" />
|
||||
<Compile Include="System.Runtime.CompilerServices\AsyncTaskMethodBuilderTests.cs" />
|
||||
<Compile Include="$(CommonTestPath)\System\Threading\ThreadPoolHelpers.cs">
|
||||
<Link>CommonTest\System\Threading\ThreadPoolHelpers.cs</Link>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
<ItemGroup Condition="'$(TargetGroup)' == 'netstandard'">
|
||||
<Compile Include="Task\TaskDisposeTests.netstandard.cs" />
|
||||
</ItemGroup>
|
||||
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
|
||||
</Project>
|
67
external/corefx/src/System.Threading.Tasks/tests/Task/RunContinuationsAsynchronouslyTests.cs
vendored
Normal file
67
external/corefx/src/System.Threading.Tasks/tests/Task/RunContinuationsAsynchronouslyTests.cs
vendored
Normal file
@ -0,0 +1,67 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using Xunit;
|
||||
|
||||
namespace System.Threading.Tasks.Tests
|
||||
{
|
||||
public class RunContinuationsAsynchronouslyTests
|
||||
{
|
||||
[Theory]
|
||||
[InlineData(false)]
|
||||
[InlineData(true)]
|
||||
public void Direct(bool useRunContinuationsAsynchronously)
|
||||
{
|
||||
Run(useRunContinuationsAsynchronously, t => t);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(false)]
|
||||
[InlineData(true)]
|
||||
public void ViaUnwrap(bool useRunContinuationsAsynchronously)
|
||||
{
|
||||
Run(useRunContinuationsAsynchronously, t => ((Task<Task>)t).Unwrap());
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(false)]
|
||||
[InlineData(true)]
|
||||
public void ViaWhenAll(bool useRunContinuationsAsynchronously)
|
||||
{
|
||||
Run(useRunContinuationsAsynchronously, t => Task.WhenAll(t));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(false)]
|
||||
[InlineData(true)]
|
||||
public void ViaWhenAny(bool useRunContinuationsAsynchronously)
|
||||
{
|
||||
Run(useRunContinuationsAsynchronously, t => Task.WhenAny(t));
|
||||
}
|
||||
|
||||
private static void Run(bool useRunContinuationsAsynchronously, Func<Task,Task> getIntermediateContinuation)
|
||||
{
|
||||
Task t = Task.Run(() => // run test off of xunit's thread so as not to be confused by its TaskScheduler or SynchronizationContext
|
||||
{
|
||||
int callingThreadId = Environment.CurrentManagedThreadId;
|
||||
|
||||
var tcs = new TaskCompletionSource<Task>(useRunContinuationsAsynchronously ?
|
||||
TaskCreationOptions.RunContinuationsAsynchronously :
|
||||
TaskCreationOptions.None);
|
||||
|
||||
Task cont = getIntermediateContinuation(tcs.Task).ContinueWith(
|
||||
_ => Assert.NotEqual(useRunContinuationsAsynchronously, callingThreadId == Environment.CurrentManagedThreadId),
|
||||
TaskContinuationOptions.ExecuteSynchronously);
|
||||
|
||||
tcs.SetResult(Task.CompletedTask);
|
||||
|
||||
((IAsyncResult)cont).AsyncWaitHandle.WaitOne(); // ensure we don't inline as part of waiting
|
||||
cont.GetAwaiter().GetResult(); // propagate any errors
|
||||
});
|
||||
((IAsyncResult)t).AsyncWaitHandle.WaitOne(); // ensure we don't inline as part of waiting
|
||||
t.GetAwaiter().GetResult(); // propagate any errors
|
||||
}
|
||||
|
||||
}
|
||||
}
|
25
external/corefx/src/System.Threading.Tasks/tests/Task/TPLTestException.cs
vendored
Normal file
25
external/corefx/src/System.Threading.Tasks/tests/Task/TPLTestException.cs
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace System.Threading.Tasks.Tests
|
||||
{
|
||||
/// <summary>
|
||||
/// Whenever we need to simulate an user exception or an unhandled exception, we use this class
|
||||
/// </summary>
|
||||
internal class TPLTestException : Exception
|
||||
{
|
||||
public readonly int FromTaskId;
|
||||
|
||||
public TPLTestException()
|
||||
: base("Throwing an exception")
|
||||
{
|
||||
FromTaskId = Task.CurrentId ?? -1;
|
||||
}
|
||||
}
|
||||
}
|
274
external/corefx/src/System.Threading.Tasks/tests/Task/TaskAPMTest.cs
vendored
Normal file
274
external/corefx/src/System.Threading.Tasks/tests/Task/TaskAPMTest.cs
vendored
Normal file
@ -0,0 +1,274 @@
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
// =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
|
||||
//
|
||||
// Test class that verifies the integration with APM (Task => APM) section 2.5.11 in the TPL spec
|
||||
// "Asynchronous Programming Model", or the "Begin/End" pattern
|
||||
//
|
||||
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
||||
|
||||
using Xunit;
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace System.Threading.Tasks.Tests
|
||||
{
|
||||
/// <summary>
|
||||
/// A class that implements the APM pattern to ensure that TPL can support APM patttern
|
||||
/// </summary>
|
||||
public sealed class TaskAPMTests : IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// Used to indicate whether to test TPL's Task or Future functionality for the APM pattern
|
||||
/// </summary>
|
||||
private bool _hasReturnType;
|
||||
|
||||
/// <summary>
|
||||
/// Used to synchornize between Main thread and async thread, by blocking the main thread until
|
||||
/// the thread that invokes the TaskCompleted method via AsyncCallback finishes
|
||||
/// </summary>
|
||||
private ManualResetEvent _mre = new ManualResetEvent(false);
|
||||
|
||||
/// <summary>
|
||||
/// The input value to LongTask<int>.DoTask/BeginDoTask
|
||||
/// </summary>
|
||||
private const int IntInput = 1000;
|
||||
|
||||
/// <summary>
|
||||
/// The constant that defines the number of milliseconds to spinwait (to simulate work) in the LongTask class
|
||||
/// </summary>
|
||||
private const int LongTaskMilliseconds = 100;
|
||||
|
||||
[Theory]
|
||||
[OuterLoop]
|
||||
[InlineData(true)]
|
||||
[InlineData(false)]
|
||||
public void WaitUntilCompleteTechnique(bool hasReturnType)
|
||||
{
|
||||
_hasReturnType = hasReturnType;
|
||||
|
||||
LongTask longTask;
|
||||
if (_hasReturnType)
|
||||
longTask = new LongTask<int>(LongTaskMilliseconds);
|
||||
else
|
||||
longTask = new LongTask(LongTaskMilliseconds);
|
||||
|
||||
// Prove that the Wait-until-done technique works
|
||||
IAsyncResult asyncResult = longTask.BeginDoTask(null, null);
|
||||
longTask.EndDoTask(asyncResult);
|
||||
|
||||
AssertTaskCompleted(asyncResult);
|
||||
Assert.False(asyncResult.CompletedSynchronously, "Should not have completed synchronously.");
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[OuterLoop]
|
||||
[InlineData(true)]
|
||||
[InlineData(false)]
|
||||
public void PollUntilCompleteTechnique(bool hasReturnType)
|
||||
{
|
||||
_hasReturnType = hasReturnType;
|
||||
|
||||
LongTask longTask;
|
||||
if (_hasReturnType)
|
||||
longTask = new LongTask<int>(LongTaskMilliseconds);
|
||||
else
|
||||
longTask = new LongTask(LongTaskMilliseconds);
|
||||
|
||||
IAsyncResult asyncResult = longTask.BeginDoTask(null, null);
|
||||
var mres = new ManualResetEventSlim();
|
||||
while (!asyncResult.IsCompleted)
|
||||
{
|
||||
mres.Wait(1);
|
||||
}
|
||||
|
||||
AssertTaskCompleted(asyncResult);
|
||||
Assert.False(asyncResult.CompletedSynchronously, "Should not have completed synchronously.");
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[OuterLoop]
|
||||
[InlineData(true)]
|
||||
[InlineData(false)]
|
||||
public void WaitOnAsyncWaitHandleTechnique(bool hasReturnType)
|
||||
{
|
||||
_hasReturnType = hasReturnType;
|
||||
|
||||
LongTask longTask;
|
||||
if (_hasReturnType)
|
||||
longTask = new LongTask<int>(LongTaskMilliseconds);
|
||||
else
|
||||
longTask = new LongTask(LongTaskMilliseconds);
|
||||
|
||||
IAsyncResult asyncResult = longTask.BeginDoTask(null, null);
|
||||
asyncResult.AsyncWaitHandle.WaitOne();
|
||||
|
||||
AssertTaskCompleted(asyncResult);
|
||||
Assert.False(asyncResult.CompletedSynchronously, "Should not have completed synchronously.");
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[OuterLoop]
|
||||
[InlineData(true)]
|
||||
[InlineData(false)]
|
||||
public void CallbackTechnique(bool hasReturnType)
|
||||
{
|
||||
_hasReturnType = hasReturnType;
|
||||
|
||||
LongTask longTask;
|
||||
if (_hasReturnType)
|
||||
longTask = new LongTask<int>(LongTaskMilliseconds);
|
||||
else
|
||||
longTask = new LongTask(LongTaskMilliseconds);
|
||||
|
||||
IAsyncResult asyncResult;
|
||||
if (_hasReturnType)
|
||||
asyncResult = ((LongTask<int>)longTask).BeginDoTask(IntInput, TaskCompleted, longTask);
|
||||
else
|
||||
asyncResult = longTask.BeginDoTask(TaskCompleted, longTask);
|
||||
|
||||
_mre.WaitOne(); //Block the main thread until async thread finishes executing the call back
|
||||
|
||||
AssertTaskCompleted(asyncResult);
|
||||
Assert.False(asyncResult.CompletedSynchronously, "Should not have completed synchronously.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Method used by the callback implementation by the APM
|
||||
/// </summary>
|
||||
/// <param name="ar"></param>
|
||||
private void TaskCompleted(IAsyncResult ar)
|
||||
{
|
||||
if (_hasReturnType)
|
||||
{
|
||||
LongTask<int> lt = (LongTask<int>)ar.AsyncState;
|
||||
int retValue = lt.EndDoTask(ar);
|
||||
if (retValue != IntInput)
|
||||
Assert.True(false, string.Format("Mismatch: Return = {0} vs Expect = {1}", retValue, IntInput));
|
||||
}
|
||||
else
|
||||
{
|
||||
LongTask lt = (LongTask)ar.AsyncState;
|
||||
lt.EndDoTask(ar);
|
||||
}
|
||||
|
||||
_mre.Set();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Assert that the IAsyncResult represent a completed Task
|
||||
/// </summary>
|
||||
private void AssertTaskCompleted(IAsyncResult ar)
|
||||
{
|
||||
Assert.True(ar.IsCompleted);
|
||||
Assert.Equal(TaskStatus.RanToCompletion, ((Task)ar).Status);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_mre.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A dummy class that simulates a long running task that implements IAsyncResult methods
|
||||
/// </summary>
|
||||
public class LongTask
|
||||
{
|
||||
// Amount of time to SpinWait, in milliseconds.
|
||||
protected readonly Int32 _msWaitDuration;
|
||||
|
||||
public LongTask(Int32 milliseconds)
|
||||
{
|
||||
_msWaitDuration = milliseconds;
|
||||
}
|
||||
|
||||
// Synchronous version of time-consuming method
|
||||
public void DoTask()
|
||||
{
|
||||
// Simulate time-consuming task
|
||||
SpinWait.SpinUntil(() => false, _msWaitDuration);
|
||||
}
|
||||
|
||||
// Asynchronous version of time-consuming method (Begin part)
|
||||
public IAsyncResult BeginDoTask(AsyncCallback callback, Object state)
|
||||
{
|
||||
// Create IAsyncResult object identifying the asynchronous operation
|
||||
Task task = Task.Factory.StartNew(
|
||||
delegate
|
||||
{
|
||||
DoTask(); //simulates workload
|
||||
},
|
||||
state);
|
||||
|
||||
if (callback != null)
|
||||
{
|
||||
task.ContinueWith(delegate
|
||||
{
|
||||
callback(task);
|
||||
});
|
||||
}
|
||||
|
||||
return task; // Return the IAsyncResult to the caller
|
||||
}
|
||||
|
||||
// Asynchronous version of time-consuming method (End part)
|
||||
public void EndDoTask(IAsyncResult asyncResult)
|
||||
{
|
||||
// We know that the IAsyncResult is really a Task object
|
||||
Task task = (Task)asyncResult;
|
||||
// Wait for operation to complete
|
||||
task.Wait();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A dummy class that simulates a long running Future that implements IAsyncResult methods
|
||||
/// </summary>
|
||||
public sealed class LongTask<T> : LongTask
|
||||
{
|
||||
public LongTask(Int32 milliseconds)
|
||||
: base(milliseconds)
|
||||
{
|
||||
}
|
||||
|
||||
// Synchronous version of time-consuming method
|
||||
public T DoTask(T input)
|
||||
{
|
||||
SpinWait.SpinUntil(() => false, _msWaitDuration); // Simulate time-consuming task
|
||||
return input; // Return some result, for now, just return the input
|
||||
}
|
||||
|
||||
public IAsyncResult BeginDoTask(T input, AsyncCallback callback, Object state)
|
||||
{
|
||||
// Create IAsyncResult object identifying the asynchronous operation
|
||||
Task<T> task = Task<T>.Factory.StartNew(
|
||||
delegate
|
||||
{
|
||||
return DoTask(input);
|
||||
},
|
||||
state);
|
||||
|
||||
task.ContinueWith(delegate
|
||||
{
|
||||
callback(task);
|
||||
});
|
||||
|
||||
return task; // Return the IAsyncResult to the caller
|
||||
}
|
||||
|
||||
// Asynchronous version of time-consuming method (End part)
|
||||
new public T EndDoTask(IAsyncResult asyncResult)
|
||||
{
|
||||
// We know that the IAsyncResult is really a Task object
|
||||
Task<T> task = (Task<T>)asyncResult;
|
||||
|
||||
// Return the result
|
||||
return task.Result;
|
||||
}
|
||||
}
|
||||
}
|
688
external/corefx/src/System.Threading.Tasks/tests/Task/TaskCancelWaitTest.cs
vendored
Normal file
688
external/corefx/src/System.Threading.Tasks/tests/Task/TaskCancelWaitTest.cs
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1
external/corefx/src/System.Threading.Tasks/tests/Task/TaskCancelWaitTests.cs.REMOVED.git-id
vendored
Normal file
1
external/corefx/src/System.Threading.Tasks/tests/Task/TaskCancelWaitTests.cs.REMOVED.git-id
vendored
Normal file
@ -0,0 +1 @@
|
||||
d0848664b34f24dceeff57468988e52aa486b0a1
|
927
external/corefx/src/System.Threading.Tasks/tests/Task/TaskContinueWhenAllTests.cs
vendored
Normal file
927
external/corefx/src/System.Threading.Tasks/tests/Task/TaskContinueWhenAllTests.cs
vendored
Normal file
File diff suppressed because it is too large
Load Diff
526
external/corefx/src/System.Threading.Tasks/tests/Task/TaskContinueWhenAnyTests.cs
vendored
Normal file
526
external/corefx/src/System.Threading.Tasks/tests/Task/TaskContinueWhenAnyTests.cs
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1340
external/corefx/src/System.Threading.Tasks/tests/Task/TaskContinueWithAllAnyTests.cs
vendored
Normal file
1340
external/corefx/src/System.Threading.Tasks/tests/Task/TaskContinueWithAllAnyTests.cs
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1446
external/corefx/src/System.Threading.Tasks/tests/Task/TaskContinueWithTests.cs
vendored
Normal file
1446
external/corefx/src/System.Threading.Tasks/tests/Task/TaskContinueWithTests.cs
vendored
Normal file
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user