Imported Upstream version 5.0.0.42

Former-commit-id: fd56571888259555122d8a0f58c68838229cea2b
This commit is contained in:
Xamarin Public Jenkins (auto-signing)
2017-04-10 11:41:01 +00:00
parent 1190d13a04
commit 6bdd276d05
19939 changed files with 3099680 additions and 93811 deletions

View 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);
}
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View 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>

View 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();
}
}
}

View 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);
}
}
}

View 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();
}
}
}

View File

@ -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
}
}

View 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>

View 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>

View 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
}
}
}

View 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;
}
}
}

View 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;
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1 @@
d0848664b34f24dceeff57468988e52aa486b0a1

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

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