public void Dispose() { foreach (var invocation in invocations) { invocation.Dispose(); } current = null; }
public FluentMockContext() { current = this; }
public static IMatcher CreateMatcher(Expression expression, bool isParams) { // Type inference on the call might // do automatic conversion to the desired // method argument type, and a Convert expression type // might be the topmost instead. // i.e.: It.IsInRange(0, 100, Range.Inclusive) // the values are ints, but if the method to call // expects, say, a double, a Convert node will be on // the expression. if (isParams && (expression.NodeType == ExpressionType.NewArrayInit || !expression.Type.IsArray)) { return new ParamArrayMatcher((NewArrayExpression)expression); } var originalExpression = expression; if (expression.NodeType == ExpressionType.Convert) { expression = ((UnaryExpression)expression).Operand; } // SetupSet passes a custom expression. var matchExpression = expression as MatchExpression; if (matchExpression != null) { return new Matcher(matchExpression.Match); } if (expression.NodeType == ExpressionType.Call) { var call = (MethodCallExpression)expression; // Try to determine if invocation is to a matcher. using (var context = new FluentMockContext()) { Expression.Lambda<Action>(call).Compile().Invoke(); if (context.LastMatch != null) { return new Matcher(context.LastMatch); } } var attr = call.Method.GetCustomAttribute<AdvancedMatcherAttribute>(true); #pragma warning disable 618 var staticMatcherMethodAttr = call.Method.GetCustomAttribute<MatcherAttribute>(true); #pragma warning restore 618 if (attr != null) { var matcher = attr.CreateMatcher(); matcher.Initialize(expression); return matcher; } else if (staticMatcherMethodAttr != null) { var matcher = new MatcherAttributeMatcher(); matcher.Initialize(expression); return matcher; } else { var matcher = new LazyEvalMatcher(); matcher.Initialize(expression); return matcher; } } else if (expression.NodeType == ExpressionType.MemberAccess) { // Try to determine if invocation is to a matcher. using (var context = new FluentMockContext()) { Expression.Lambda<Action>((MemberExpression)expression).Compile().Invoke(); if (context.LastMatch != null) { return new Matcher(context.LastMatch); } } } // Try reducing locals to get a constant. var reduced = originalExpression.PartialEval(); if (reduced.NodeType == ExpressionType.Constant) { return new ConstantMatcher(((ConstantExpression)reduced).Value); } if (reduced.NodeType == ExpressionType.Quote) { return new ExpressionMatcher(((UnaryExpression)expression).Operand); } throw new NotSupportedException( string.Format(CultureInfo.CurrentCulture, Resources.UnsupportedExpression, expression)); }
private static TCall SetupSetImpl <T, TCall>( Mock <T> mock, Action <T> setterExpression, Func <Mock, LambdaExpression, MethodInfo, Expression[], TCall> callFactory) where T : class where TCall : MethodCall { using (var context = new FluentMockContext()) { setterExpression(mock.Object); var last = context.LastInvocation; if (last == null) { throw new ArgumentException(string.Format( CultureInfo.InvariantCulture, Resources.SetupOnNonVirtualMember, string.Empty)); } var setter = last.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(last.Invocation.Method.DeclaringType, parameterName); var arguments = last.Invocation.Arguments; var parameters = setter.GetParameters(); var values = new Expression[arguments.Length]; if (last.Match == null) { // 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, last.Invocation.Method, values), x); return(callFactory(last.Mock, lambda, last.Invocation.Method, values)); } else { 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 (last.Match.RenderExpression.Type != propertyType) { values[valueIndex] = Expression.Convert(last.Match.RenderExpression, propertyType); } else { values[valueIndex] = last.Match.RenderExpression; } matchers[valueIndex] = new MatchExpression(last.Match); if (arguments.Length == 2) { // TODO: what about multi-index setters? // Add the index value for the property indexer values[0] = GetValueExpression(arguments[0], parameters[0].ParameterType); // TODO: No matcher supported now for the index matchers[0] = values[0]; } var lambda = Expression.Lambda( typeof(Action <>).MakeGenericType(x.Type), Expression.Call(x, last.Invocation.Method, values), x); return(callFactory(last.Mock, lambda, last.Invocation.Method, matchers)); } } }
public static IMatcher CreateMatcher(Expression expression, bool isParams) { // Type inference on the call might // do automatic conversion to the desired // method argument type, and a Convert expression type // might be the topmost instead. // i.e.: It.IsInRange(0, 100, Range.Inclusive) // the values are ints, but if the method to call // expects, say, a double, a Convert node will be on // the expression. if (isParams && (expression.NodeType == ExpressionType.NewArrayInit || !expression.Type.IsArray)) { return(new ParamArrayMatcher((NewArrayExpression)expression)); } var originalExpression = expression; if (expression.NodeType == ExpressionType.Convert) { expression = ((UnaryExpression)expression).Operand; } // SetupSet passes a custom expression. var matchExpression = expression as MatchExpression; if (matchExpression != null) { return(new Matcher(matchExpression.Match)); } if (expression.NodeType == ExpressionType.Call) { var call = (MethodCallExpression)expression; // Try to determine if invocation is to a matcher. using (var context = new FluentMockContext()) { Expression.Lambda <Action>(call).Compile().Invoke(); if (context.LastMatch != null) { return(new Matcher(context.LastMatch)); } } var attr = call.Method.GetCustomAttribute <AdvancedMatcherAttribute>(true); #pragma warning disable 618 var staticMatcherMethodAttr = call.Method.GetCustomAttribute <MatcherAttribute>(true); #pragma warning restore 618 if (attr != null) { var matcher = attr.CreateMatcher(); matcher.Initialize(expression); return(matcher); } else if (staticMatcherMethodAttr != null) { var matcher = new MatcherAttributeMatcher(); matcher.Initialize(expression); return(matcher); } else { var matcher = new LazyEvalMatcher(); matcher.Initialize(expression); return(matcher); } } else if (expression.NodeType == ExpressionType.MemberAccess) { // Try to determine if invocation is to a matcher. using (var context = new FluentMockContext()) { Expression.Lambda <Action>((MemberExpression)expression).Compile().Invoke(); if (context.LastMatch != null) { return(new Matcher(context.LastMatch)); } } } // Try reducing locals to get a constant. var reduced = originalExpression.PartialEval(); if (reduced.NodeType == ExpressionType.Constant) { return(new ConstantMatcher(((ConstantExpression)reduced).Value)); } if (reduced.NodeType == ExpressionType.Quote) { return(new ExpressionMatcher(((UnaryExpression)expression).Operand)); } throw new NotSupportedException( string.Format(CultureInfo.CurrentCulture, Resources.UnsupportedExpression, expression)); }