private static void ContinueOnSameSynchronizationContext(AwaitAdapter awaiter, Action continuation) { if (awaiter == null) { throw new ArgumentNullException(nameof(awaiter)); } if (continuation == null) { throw new ArgumentNullException(nameof(continuation)); } var context = SynchronizationContext.Current; awaiter.OnCompleted(() => { if (SynchronizationContext.Current == context) { continuation.Invoke(); } else { context.Post(state => ((Action)state).Invoke(), state: continuation); } }); }
public override void WaitForCompletion(AwaitAdapter awaiter) { var context = SynchronizationContext.Current; if (!IsApplicable(context)) { throw new InvalidOperationException("This strategy must only be used from a WindowsFormsSynchronizationContext."); } if (awaiter.IsCompleted) { return; } // Wait for a post rather than scheduling the continuation now. If there has been a race condition // and it completed after the IsCompleted check, it will wait until the application runs *before* // shutting it down. Otherwise Application.Exit is a no-op and we would then proceed to do // Application.Run and never return. context.Post( state => ContinueOnSameSynchronizationContext((AwaitAdapter)state, _applicationExit), state: awaiter); try { _applicationRun.Invoke(); } finally { SynchronizationContext.SetSynchronizationContext(context); } }
public override object WaitForPendingOperationsToComplete(object invocationResult) { var awaitAdapter = AwaitAdapter.FromAwaitable(invocationResult); if (!awaitAdapter.IsCompleted) { var waitStrategy = MessagePumpStrategy.FromCurrentSynchronizationContext(); waitStrategy.WaitForCompletion(awaitAdapter); } // Future: instead of Wait(), use GetAwaiter() to check awaiter.IsCompleted above // and use awaiter.OnCompleted/awaiter.GetResult below. // (Implement a ReflectionAwaitAdapter) try { invocationResult.GetType().GetMethod(TaskWaitMethod, new Type[0]).Invoke(invocationResult, null); } catch (TargetInvocationException e) { IList <Exception> innerExceptions = GetAllExceptions(e.InnerException); ExceptionHelper.Rethrow(innerExceptions[0]); } var args = invocationResult.GetType().GetGenericArguments(); if (args != null && args.Length == 1 && args[0].Name == VoidTaskResultType) { return(null); } PropertyInfo taskResultProperty = invocationResult.GetType().GetProperty(TaskResultProperty, TaskResultPropertyBindingFlags); return(taskResultProperty != null?taskResultProperty.GetValue(invocationResult, null) : invocationResult); }
public static AwaitAdapter TryCreate(object awaitable) { if (awaitable == null) { return(null); } var info = GetAsyncInfo(awaitable.GetType()); if (info == null) { return(null); } if (_startImmediateAsTaskMethod == null) { var asyncHelperMethodsType = info.FSharpAsyncTypeDefinition.GetTypeInfo().Assembly.GetType("Microsoft.FSharp.Control.FSharpAsync"); if (asyncHelperMethodsType == null) { throw new InvalidOperationException("Cannot find non-generic FSharpAsync type in the same assembly as the generic one."); } _startImmediateAsTaskMethod = asyncHelperMethodsType .GetMethods(BindingFlags.Public | BindingFlags.Static) .Single(method => { if (method.Name != "StartImmediateAsTask") { return(false); } var typeArguments = method.GetGenericArguments(); if (typeArguments.Length != 1) { return(false); } var parameters = method.GetParameters(); if (parameters.Length != 2) { return(false); } if (parameters[0].ParameterType != info.FSharpAsyncTypeDefinition.MakeGenericType(typeArguments[0])) { return(false); } Type someType; return(parameters[1].ParameterType.IsFSharpOption(out someType) && someType.FullName == "System.Threading.CancellationToken"); }); } var task = _startImmediateAsTaskMethod .MakeGenericMethod(info.ResultType) .Invoke(null, new[] { awaitable, null }); return(AwaitAdapter.FromAwaitable(task)); }
public static object Await(Func <object> invoke) { Guard.ArgumentNotNull(invoke, nameof(invoke)); using (InitializeExecutionEnvironment()) { var awaitAdapter = AwaitAdapter.FromAwaitable(invoke.Invoke()); if (!awaitAdapter.IsCompleted) { var waitStrategy = MessagePumpStrategy.FromCurrentSynchronizationContext(); waitStrategy.WaitForCompletion(awaitAdapter); } return(awaitAdapter.GetResult()); } }
public static object Await(Func <object> invoke) { Guard.ArgumentNotNull(invoke, nameof(invoke)); object invocationResult; using (InitializeExecutionEnvironment()) { invocationResult = invoke.Invoke(); if (invocationResult == null || !IsTaskType(invocationResult.GetType())) { throw new InvalidOperationException("The delegate did not return a Task."); // General awaitable support coming soon. } var awaitAdapter = AwaitAdapter.FromAwaitable(invocationResult); if (!awaitAdapter.IsCompleted) { var waitStrategy = MessagePumpStrategy.FromCurrentSynchronizationContext(); waitStrategy.WaitForCompletion(awaitAdapter); } } // Future: instead of Wait(), use GetAwaiter() to check awaiter.IsCompleted above // and use awaiter.OnCompleted/awaiter.GetResult below. // (Implement a ReflectionAwaitAdapter) try { invocationResult.GetType().GetMethod(TaskWaitMethod, new Type[0]).Invoke(invocationResult, null); } catch (TargetInvocationException e) { IList <Exception> innerExceptions = GetAllExceptions(e.InnerException); ExceptionHelper.Rethrow(innerExceptions[0]); } var genericArguments = invocationResult.GetType().GetGenericArguments(); if (genericArguments.Length == 1 && genericArguments[0].Name == VoidTaskResultType) { return(null); } PropertyInfo taskResultProperty = invocationResult.GetType().GetProperty(TaskResultProperty, TaskResultPropertyBindingFlags); return(taskResultProperty != null?taskResultProperty.GetValue(invocationResult, null) : invocationResult); }
public override void WaitForCompletion(AwaitAdapter awaiter) { var context = SynchronizationContext.Current as SingleThreadedTestSynchronizationContext; if (context == null) { throw new InvalidOperationException("This strategy must only be used from a SingleThreadedTestSynchronizationContext."); } if (awaiter.IsCompleted) { return; } // Wait for a post rather than scheduling the continuation now. If there has been a race condition // and it completed after the IsCompleted check, it will wait until the message loop runs *before* // shutting it down. Otherwise context.ShutDown will throw. context.Post( state => ContinueOnSameSynchronizationContext((AwaitAdapter)state, context.ShutDown), state: awaiter); context.Run(); }
/// <summary> /// Check that setup and teardown methods marked by certain attributes /// meet NUnit's requirements and mark the tests not runnable otherwise. /// </summary> protected void CheckSetUpTearDownMethods(MethodInfo[] methods) { foreach (MethodInfo method in methods) { if (method.IsAbstract) { MakeInvalid("An abstract SetUp and TearDown methods cannot be run: " + method.Name); } else if (!(method.IsPublic || method.IsFamily)) { MakeInvalid("SetUp and TearDown methods must be public or protected: " + method.Name); } else if (method.GetParameters().Length != 0) { MakeInvalid("SetUp and TearDown methods must not have parameters: " + method.Name); } else if (AsyncToSyncAdapter.IsAsyncOperation(method)) { if (method.ReturnType == typeof(void)) { MakeInvalid("SetUp and TearDown methods must not be async void: " + method.Name); } else if (!Reflect.IsVoidOrUnit(AwaitAdapter.GetResultType(method.ReturnType))) { MakeInvalid("SetUp and TearDown methods must return void or an awaitable type with a void result: " + method.Name); } } else { if (!Reflect.IsVoidOrUnit(method.ReturnType)) { MakeInvalid("SetUp and TearDown methods must return void or an awaitable type with a void result: " + method.Name); } } } }
public override void WaitForCompletion(AwaitAdapter awaitable) { var context = SynchronizationContext.Current; if (!(context is DispatcherSynchronizationContext)) { throw new InvalidOperationException("This strategy must only be used from a DispatcherSynchronizationContext."); } if (awaitable.IsCompleted) { return; } // Wait for a post rather than scheduling the continuation now. If there has been a race condition // and it completed after the IsCompleted check, it will wait until the application runs *before* // shutting it down. Otherwise Dispatcher.ExitAllFrames is a no-op and we would then proceed to do // Dispatcher.Run and never return. context.Post( state => ContinueOnSameSynchronizationContext((AwaitAdapter)state, Dispatcher.ExitAllFrames), state: awaitable); Dispatcher.Run(); }
public override void WaitForCompletion(AwaitAdapter awaiter) { awaiter.BlockUntilCompleted(); }
public abstract void WaitForCompletion(AwaitAdapter awaiter);
public static bool IsAsyncOperation(MethodInfo method) { return(AwaitAdapter.IsAwaitable(method.ReturnType) || method.GetCustomAttributes(false).Any(attr => attr.GetType().FullName == "System.Runtime.CompilerServices.AsyncStateMachineAttribute")); }
public override Task WaitForCompletion(AwaitAdapter awaiter) { return(awaiter.BlockUntilCompleted()); }
public abstract Task WaitForCompletion(AwaitAdapter awaiter);