public static EventWithTarget GetEventWithTarget <TMock>(this Action <TMock> eventExpression, TMock mock) where TMock : class { Guard.NotNull(eventExpression, nameof(eventExpression)); MethodBase addRemove; Mock target; using (var observer = AmbientObserver.Activate()) { eventExpression(mock); if (!observer.LastIsInvocation(out target, out var invocation, out _)) { throw new ArgumentException(Resources.ExpressionIsNotEventAttachOrDetachOrIsNotVirtual); } addRemove = invocation.Method; } var ev = addRemove.DeclaringType.GetEvent( addRemove.Name.Replace("add_", string.Empty).Replace("remove_", string.Empty)); if (ev == null) { throw new ArgumentException(string.Format( CultureInfo.CurrentCulture, Resources.EventNotFound, addRemove)); } return(new EventWithTarget(ev, target)); }
public static bool IsMatch(this Expression expression, out Match match) { using (var observer = AmbientObserver.Activate()) { Expression.Lambda <Action>(expression).CompileUsingExpressionCompiler().Invoke(); return(observer.LastIsMatch(out match)); } }
private static SetupSetImplResult SetupSetImpl(Mock mock, Delegate setterExpression) { Mock target; Invocation invocation; AmbientObserver.Matches matches; using (var observer = AmbientObserver.Activate()) { setterExpression.DynamicInvoke(mock.Object); if (!observer.LastIsInvocation(out target, out invocation, out matches)) { throw new ArgumentException(string.Format( CultureInfo.InvariantCulture, Resources.SetupOnNonVirtualMember, string.Empty)); } } var setter = invocation.Method; if (!setter.IsPropertySetter()) { throw new ArgumentException(Resources.SetupNotSetter); } // No need to call ThrowIfCantOverride as non-overridable would have thrown above already. // Get the variable name as used in the actual delegate :) // because of delegate currying, look at the last parameter for the Action's backing method, not the first var setterExpressionParameters = setterExpression.GetMethodInfo().GetParameters(); var parameterName = setterExpressionParameters[setterExpressionParameters.Length - 1].Name; var x = Expression.Parameter(invocation.Method.DeclaringType, parameterName); var arguments = invocation.Arguments; var parameters = setter.GetParameters(); var values = new Expression[arguments.Length]; if (matches.Count == 0) { // Length == 1 || Length == 2 (Indexer property) for (int i = 0; i < arguments.Length; i++) { values[i] = GetValueExpression(arguments[i], parameters[i].ParameterType); } var lambda = Expression.Lambda( typeof(Action <>).MakeGenericType(x.Type), Expression.Call(x, invocation.Method, values), x); return(new SetupSetImplResult(target, lambda, invocation.Method, values)); } else { // TODO: Use all observed matchers, not just the last one! var lastMatch = matches[matches.Count - 1]; var matchers = new Expression[arguments.Length]; var valueIndex = arguments.Length - 1; var propertyType = setter.GetParameters()[valueIndex].ParameterType; // If the value matcher is not equal to the property // type (i.e. prop is int?, but you use It.IsAny<int>()) // add a cast. if (lastMatch.RenderExpression.Type != propertyType) { values[valueIndex] = Expression.Convert(lastMatch.RenderExpression, propertyType); } else { values[valueIndex] = lastMatch.RenderExpression; } matchers[valueIndex] = new MatchExpression(lastMatch); for (int i = 0; i < arguments.Length - 1; i++) { // Add the index value for the property indexer values[i] = GetValueExpression(arguments[i], parameters[i].ParameterType); // TODO: No matcher supported now for the index matchers[i] = values[i]; } var lambda = Expression.Lambda( typeof(Action <>).MakeGenericType(x.Type), Expression.Call(x, invocation.Method, values), x); return(new SetupSetImplResult(target, lambda, invocation.Method, matchers)); } }