Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Retire FluentMockVisitor #978

Merged
merged 6 commits into from
Mar 22, 2020
Merged

Conversation

stakx
Copy link
Contributor

@stakx stakx commented Mar 22, 2020

FluentMockVisitor was the original component used to automatically set up inner mocks for multi-dot setup/verification expressions. For the regular new Mock<T>, mock.Setup, mock.Verify APIs, we began replacing this component with new infrastructure based on Mock.SetupRecursive and expression.Split() — see approx. #765. However, FluentMockVisitor has continued to be used for LINQ to Mocks.

This PR converts LINQ to Mocks to use the new infrastructure so we don't have to maintain two parallel mechanisms for dealing with multi-dot expressions.

(This will also simplify things over in #976.)

The pattern used for setting properties--that is, using a non-generic
helper method (`Mocks.SetProperty`) instead of Moq's generic public
API methods--can be applied again to get rid of more reflection code.
For this to work, `Mocks.SetupReturns` needs to be extended so it will
allow setting non-interceptable properties. (Accessing such a property
cannot be represented using `InvocationShape`, which guards against
non-interceptable members, so they must be removed from setup expr's
and set manually.)

These changes conclude the conversion of LINQ to Mocks from `Fluent-
MockVisitor` to the infrastructure provided by `Mock.SetupRecursive`
and `expression.Split()`, which throws different exceptions when en-
countering unsupported members. Adjust some tests to reflect this.
@stakx stakx added this to the 4.14.0 milestone Mar 22, 2020
// in this parameter...
//
// Therefore, for the nested (quoted) expression, we short-circuit:
return node.NodeType == ExpressionType.Quote ? node : base.VisitUnary(node);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It may be safer to replace this guard with a different algorithm:

  1. Implement a new visitor that travels along the "left spine" of an expression until it arrives at the root ParameterExpression, then it stores a reference to it.

  2. Run that visitor on the left expression and make the identified ParameterExpression available to the present visitor.

  3. Add checks in the present visitor so it only transforms expressions involving the same ParameterExpression that was identified in the earlier steps.

@@ -116,33 +116,10 @@ private static Expression ConvertToSetup(Expression left, Expression right)
{
switch (left.NodeType)
{
case ExpressionType.MemberAccess:
var member = (MemberExpression)left;
Guard.NotField(member);
Copy link
Contributor Author

@stakx stakx Mar 22, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This check (and the few ones further down) are removed because expression.Split and InvocationShape should already perform their own checks.

@stakx stakx merged commit 0d913b9 into devlooped:master Mar 22, 2020
@stakx stakx deleted the retire-fluentmockvisitor branch March 22, 2020 11:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

1 participant