internal static Exception Intercept(object invocation) { var invocationDescriptor = GetInvocationDescriptor(invocation); #if ASYNC if (AsyncToSyncAdapter.IsAsyncOperation(invocationDescriptor.Delegate)) { try { AsyncToSyncAdapter.Await(invocationDescriptor.Invoke); return(null); } catch (Exception ex) { return(ex); } } #endif { using (new TestExecutionContext.IsolatedContext()) { try { invocationDescriptor.Invoke(); return(null); } catch (Exception ex) { return(ex); } } } }
public override ConstraintResult ApplyTo <TActual>(TActual actual) { var @delegate = ConstraintUtils.RequireActual <Delegate>(actual, nameof(actual)); var invokeMethod = @delegate.GetType().GetTypeInfo().GetMethod("Invoke"); if (invokeMethod.GetParameters().Length != 0) { throw new ArgumentException("Delegate must be parameterless.", nameof(actual)); } var stopwatch = new System.Diagnostics.Stopwatch(); if (AsyncToSyncAdapter.IsAsyncOperation(@delegate)) { stopwatch.Start(); AsyncToSyncAdapter.Await(() => @delegate.DynamicInvoke()); stopwatch.Stop(); } else { stopwatch.Start(); @delegate.DynamicInvoke(); stopwatch.Stop(); } return(new Result(this, stopwatch.ElapsedMilliseconds)); }
private static object InvokeDelegate <T>(ActualValueDelegate <T> del) { if (AsyncToSyncAdapter.IsAsyncOperation(del)) { return(AsyncToSyncAdapter.Await(() => del.Invoke())); } return(del()); }
/// <summary> /// Applies the constraint to an ActualValueDelegate that returns /// the value to be tested. The default implementation simply evaluates /// the delegate but derived classes may override it to provide for /// delayed processing. /// </summary> /// <param name="del">An ActualValueDelegate</param> /// <returns>A ConstraintResult</returns> public virtual ConstraintResult ApplyTo <TActual>(ActualValueDelegate <TActual> del) { if (AsyncToSyncAdapter.IsAsyncOperation(del)) { return(ApplyTo(AsyncToSyncAdapter.Await(() => del.Invoke()))); } return(ApplyTo(GetTestObject(del))); }
private object RunTestMethod(TestExecutionContext context) { if (AsyncToSyncAdapter.IsAsyncOperation(testMethod.Method.MethodInfo)) { return(AsyncToSyncAdapter.Await(() => InvokeTestMethod(context))); } return(InvokeTestMethod(context)); }
/// <summary> /// Applies the constraint to an ActualValueDelegate that returns /// the value to be tested. The default implementation simply evaluates /// the delegate but derived classes may override it to provide for /// delayed processing. /// </summary> /// <param name="del">An ActualValueDelegate</param> /// <returns>A ConstraintResult</returns> /// <remarks> /// The value has already been validated when this method is called. /// </remarks> protected virtual ConstraintResult ApplyConstraint <T>(ActualValueDelegate <T> del) { #if NYI // async if (AsyncToSyncAdapter.IsAsyncOperation(del)) { return(ApplyConstraint(AsyncToSyncAdapter.Await(() => del.Invoke()))); } #endif return(ApplyConstraint(del())); }
private static void RunSetUpOrTearDownMethod(TestExecutionContext context, MethodInfo method) { Guard.ArgumentNotAsyncVoid(method, nameof(method)); #if ASYNC if (AsyncToSyncAdapter.IsAsyncOperation(method)) { AsyncToSyncAdapter.Await(() => InvokeMethod(method, context)); } else #endif InvokeMethod(method, context); }
/// <summary> /// Throws an <see cref="ArgumentException"/> if the specified delegate is <c>async void</c>. /// </summary> public static void ArgumentNotAsyncVoid(MethodInfo method, string paramName) { if (method.ReturnType != typeof(void)) { return; } if (!AsyncToSyncAdapter.IsAsyncOperation(method)) { return; } throw new ArgumentException("Async void methods are not supported. Please use 'async Task' instead.", paramName); }
private void RunSetUpOrTearDownMethod(TestExecutionContext context, IMethodInfo method) { Guard.ArgumentNotAsyncVoid(method.MethodInfo, nameof(method)); _methodValidator?.Validate(method.MethodInfo); if (AsyncToSyncAdapter.IsAsyncOperation(method.MethodInfo)) { AsyncToSyncAdapter.Await(() => InvokeMethod(method, context)); } else { InvokeMethod(method, context); } }
public static Exception?ThrowsAsync(IResolveConstraint expression, AsyncTestDelegate code, string?message, params object?[]?args) { Exception?caughtException = null; try { AsyncToSyncAdapter.Await(code.Invoke); } catch (Exception e) { caughtException = e; } Assert.That(caughtException, expression, message, args); return(caughtException); }
private object RunTestMethod(TestExecutionContext context) { #if ASYNC if (AsyncToSyncAdapter.IsAsyncOperation(testMethod.Method.MethodInfo)) { try { return(AsyncToSyncAdapter.Await(() => InvokeTestMethod(context))); } catch (Exception e) { throw new NUnitException("Rethrown", e); } } #endif return(InvokeTestMethod(context)); }
/// <summary> /// Executes the code and returns success if an exception is thrown. /// </summary> /// <param name="actual">A delegate representing the code to be tested</param> /// <returns>True if an exception is thrown, otherwise false</returns> public override ConstraintResult ApplyTo <TActual>(TActual actual) { TestDelegate code = actual as TestDelegate; Exception caughtException = null; if (code != null) { try { code(); } catch (Exception ex) { caughtException = ex; } } #if ASYNC AsyncTestDelegate asyncCode = actual as AsyncTestDelegate; if (asyncCode != null) { try { AsyncToSyncAdapter.Await(asyncCode.Invoke); } catch (Exception ex) { caughtException = ex; } } if (code == null && asyncCode == null) #else else #endif { throw new ArgumentException(string.Format("The actual value must be a TestDelegate or AsyncTestDelegate but was {0}", actual.GetType().Name), nameof(actual)); } return(new ThrowsExceptionConstraintResult(this, caughtException)); }
public static void Multiple(AsyncTestDelegate testDelegate) { TestExecutionContext context = TestExecutionContext.CurrentContext; Guard.OperationValid(context != null, "There is no current test execution context."); context.MultipleAssertLevel++; try { AsyncToSyncAdapter.Await(testDelegate.Invoke); } finally { context.MultipleAssertLevel--; } if (context.MultipleAssertLevel == 0 && context.CurrentResult.PendingFailures > 0) { context.CurrentResult.RecordTestCompletion(); throw new MultipleAssertException(context.CurrentResult); } }
private static bool CheckTestMethodSignature(TestMethod testMethod, TestCaseParameters?parms) { if (testMethod.Method.IsAbstract) { return(MarkAsNotRunnable(testMethod, "Method is abstract")); } if (!testMethod.Method.IsPublic) { return(MarkAsNotRunnable(testMethod, "Method is not public")); } IParameterInfo[] parameters; parameters = testMethod.Method.GetParameters(); int minArgsNeeded = 0; foreach (var parameter in parameters) { // IsOptional is supported since .NET 1.1 if (!parameter.IsOptional) { minArgsNeeded++; } } int maxArgsNeeded = parameters.Length; object?[]? arglist = null; int argsProvided = 0; if (parms != null) { testMethod.parms = parms; testMethod.RunState = parms.RunState; arglist = parms.Arguments; if (arglist != null) { argsProvided = arglist.Length; } if (testMethod.RunState != RunState.Runnable) { return(false); } } var returnType = testMethod.Method.ReturnType.Type; if (AsyncToSyncAdapter.IsAsyncOperation(testMethod.Method.MethodInfo)) { if (returnType == typeof(void)) { return(MarkAsNotRunnable(testMethod, "Async test method must have non-void return type")); } var voidResult = Reflect.IsVoidOrUnit(AwaitAdapter.GetResultType(returnType)); if (!voidResult && (parms == null || !parms.HasExpectedResult)) { return(MarkAsNotRunnable(testMethod, "Async test method must return an awaitable with a void result when no result is expected")); } if (voidResult && parms != null && parms.HasExpectedResult) { return(MarkAsNotRunnable(testMethod, "Async test method must return an awaitable with a non-void result when a result is expected")); } } else if (Reflect.IsVoidOrUnit(returnType)) { if (parms != null && parms.HasExpectedResult) { return(MarkAsNotRunnable(testMethod, "Method returning void cannot have an expected result")); } } else if (parms == null || !parms.HasExpectedResult) { return(MarkAsNotRunnable(testMethod, "Method has non-void return value, but no result is expected")); } if (argsProvided > 0 && maxArgsNeeded == 0) { return(MarkAsNotRunnable(testMethod, "Arguments provided for method with no parameters")); } if (argsProvided == 0 && minArgsNeeded > 0) { return(MarkAsNotRunnable(testMethod, "No arguments were provided")); } if (argsProvided < minArgsNeeded) { return(MarkAsNotRunnable(testMethod, string.Format("Not enough arguments provided, provide at least {0} arguments.", minArgsNeeded))); } if (argsProvided > maxArgsNeeded) { return(MarkAsNotRunnable(testMethod, string.Format("Too many arguments provided, provide at most {0} arguments.", maxArgsNeeded))); } if (testMethod.Method.IsGenericMethodDefinition && arglist != null) { if (!new GenericMethodHelper(testMethod.Method.MethodInfo).TryGetTypeArguments(arglist, out var typeArguments)) { return(MarkAsNotRunnable(testMethod, "Unable to determine type arguments for method")); } testMethod.Method = testMethod.Method.MakeGenericMethod(typeArguments); parameters = testMethod.Method.GetParameters(); } if (parms != null && parms.TestName != null && parms.TestName.Trim() == "") { return(MarkAsNotRunnable(testMethod, "Test name cannot be all white-space or empty.")); } if (arglist != null && parameters != null) { TypeHelper.ConvertArgumentList(arglist, parameters); } return(true); }
/// <summary> /// Helper method that checks the signature of a TestMethod and /// any supplied parameters to determine if the test is valid. /// /// Currently, NUnitTestMethods are required to be public, /// non-abstract methods, either static or instance, /// returning void. They may take arguments but the values must /// be provided or the TestMethod is not considered runnable. /// /// Methods not meeting these criteria will be marked as /// non-runnable and the method will return false in that case. /// </summary> /// <param name="testMethod">The TestMethod to be checked. If it /// is found to be non-runnable, it will be modified.</param> /// <param name="parms">Parameters to be used for this test, or null</param> /// <returns>True if the method signature is valid, false if not</returns> /// <remarks> /// The return value is no longer used internally, but is retained /// for testing purposes. /// </remarks> private static bool CheckTestMethodSignature(TestMethod testMethod, TestCaseParameters parms) { if (testMethod.Method.IsAbstract) { return(MarkAsNotRunnable(testMethod, "Method is abstract")); } if (!testMethod.Method.IsPublic) { return(MarkAsNotRunnable(testMethod, "Method is not public")); } IParameterInfo[] parameters; parameters = testMethod.Method.GetParameters(); int minArgsNeeded = 0; foreach (var parameter in parameters) { // IsOptional is supported since .NET 1.1 if (!parameter.IsOptional) { minArgsNeeded++; } } int maxArgsNeeded = parameters.Length; object[] arglist = null; int argsProvided = 0; if (parms != null) { testMethod.parms = parms; testMethod.RunState = parms.RunState; arglist = parms.Arguments; if (arglist != null) { argsProvided = arglist.Length; } if (testMethod.RunState != RunState.Runnable) { return(false); } } ITypeInfo returnType = testMethod.Method.ReturnType; #if ASYNC if (AsyncToSyncAdapter.IsAsyncOperation(testMethod.Method.MethodInfo)) { if (returnType.IsType(typeof(void))) { return(MarkAsNotRunnable(testMethod, "Async test method must have non-void return type")); } var returnsGenericTask = returnType.IsGenericType && returnType.GetGenericTypeDefinition() == typeof(System.Threading.Tasks.Task <>); if (returnsGenericTask && (parms == null || !parms.HasExpectedResult)) { return(MarkAsNotRunnable(testMethod, "Async test method must have non-generic Task return type when no result is expected")); } if (!returnsGenericTask && parms != null && parms.HasExpectedResult) { return(MarkAsNotRunnable(testMethod, "Async test method must have Task<T> return type when a result is expected")); } } else #endif if (returnType.IsType(typeof(void))) { if (parms != null && parms.HasExpectedResult) { return(MarkAsNotRunnable(testMethod, "Method returning void cannot have an expected result")); } } else if (parms == null || !parms.HasExpectedResult) { return(MarkAsNotRunnable(testMethod, "Method has non-void return value, but no result is expected")); } if (argsProvided > 0 && maxArgsNeeded == 0) { return(MarkAsNotRunnable(testMethod, "Arguments provided for method with no parameters")); } if (argsProvided == 0 && minArgsNeeded > 0) { return(MarkAsNotRunnable(testMethod, "No arguments were provided")); } if (argsProvided < minArgsNeeded) { return(MarkAsNotRunnable(testMethod, string.Format("Not enough arguments provided, provide at least {0} arguments.", minArgsNeeded))); } if (argsProvided > maxArgsNeeded) { return(MarkAsNotRunnable(testMethod, string.Format("Too many arguments provided, provide at most {0} arguments.", maxArgsNeeded))); } if (testMethod.Method.IsGenericMethodDefinition && arglist != null) { Type[] typeArguments; if (!new GenericMethodHelper(testMethod.Method.MethodInfo).TryGetTypeArguments(arglist, out typeArguments)) { return(MarkAsNotRunnable(testMethod, "Unable to determine type arguments for method")); } testMethod.Method = testMethod.Method.MakeGenericMethod(typeArguments); parameters = testMethod.Method.GetParameters(); } if (arglist != null && parameters != null) { TypeHelper.ConvertArgumentList(arglist, parameters); } return(true); }