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

Failure when parameterized Mock.Of<> is used in query comprehension from clause #982

Closed
stakx opened this issue Mar 27, 2020 · 0 comments · Fixed by #1085
Closed

Failure when parameterized Mock.Of<> is used in query comprehension from clause #982

stakx opened this issue Mar 27, 2020 · 0 comments · Fixed by #1085
Assignees
Labels
Milestone

Comments

@stakx
Copy link
Contributor

stakx commented Mar 27, 2020

Reproduction code:

public interface IX
{
    int N { get; }
}

(from x1 in Mocks.Of<IX>(_ => _.N == 1)
 from __ in Mocks.Of<IX>(_ => _.N == 2)
 select x1)
.First()

Actual behavior:

In current master (71d66d0), query execution produces an assertion failure at this line of code:

   at Moq.ExpressionExtensions.<Split>g__Split|5_0(Expression e, Expression& r, InvocationShape& p) in …\src\Moq\ExpressionExtensions.cs:line 234
   at Moq.ExpressionExtensions.Split(LambdaExpression expression) in …\src\Moq\ExpressionExtensions.cs:line 148
   at Moq.Mock.SetupRecursive[TSetup](Mock mock, LambdaExpression expression, Func`3 setupLast) in …\src\Moq\Mock.cs:line 591
   at Moq.Mock.Setup(Mock mock, LambdaExpression expression, Condition condition) in …\src\Moq\Mock.cs:line 528
   at Moq.Mocks.SetupReturns(Mock mock, LambdaExpression expression, Object value) in …\src\Moq\Linq\Mocks.cs:line 194
   at System.Linq.Enumerable.WhereEnumerableIterator`1.MoveNext()
   at System.Linq.Enumerable.SelectManyIterator[TSource,TCollection,TResult](IEnumerable`1 source, Func`2 collectionSelector, Func`3 resultSelector)+MoveNext()
   at System.Linq.Enumerable.TryGetFirst[TSource](IEnumerable`1 source, Boolean& found)
   at System.Linq.Enumerable.First[TSource](IEnumerable`1 source)
   at System.Linq.EnumerableExecutor`1.Execute()
   at System.Linq.EnumerableQuery`1.System.Linq.IQueryProvider.Execute[TElement](Expression expression)
   at System.Linq.Queryable.First[TSource](IQueryable`1 source)
   at Moq.Linq.MockQueryable`1.Execute[TResult](Expression expression) in …\src\Moq\Linq\MockQuery.cs:line 79
   at System.Linq.Queryable.First[TSource](IQueryable`1 source)
   at …

Or, in a release build (where these assertions are disabled), this exception gets thrown:

System.NotSupportedException: Unsupported expression: ... => Mocks.SetupReturns(..., x => x.N, (object)2)
Static members (here: Mocks.SetupReturns) may not be used in setup / verification expressions.
   at Moq.Guard.IsOverridable(MethodInfo method, Expression expression) in …\src\Moq\Guard.cs:line 89
   at Moq.InvocationShape..ctor(LambdaExpression expression, MethodInfo method, IReadOnlyList`1 arguments, Boolean exactGenericTypeArguments) in …\src\Moq\InvocationShape.cs:line 45
   at Moq.ExpressionExtensions.<Split>g__Split|5_0(Expression e, Expression& r, InvocationShape& p) in …\src\Moq\ExpressionExtensions.cs:line 241
   at Moq.ExpressionExtensions.Split(LambdaExpression expression) in …\src\Moq\ExpressionExtensions.cs:line 149
   at Moq.Mock.Setup(Mock mock, LambdaExpression expression, Condition condition) in …\src\Moq\Mock.cs:line 528
   at Moq.Mocks.SetupReturns(Mock mock, LambdaExpression expression, Object value) in …\src\Moq\Linq\Mocks.cs:line 205
   at System.Linq.Enumerable.WhereEnumerableIterator`1.MoveNext()
   at System.Linq.Enumerable.SelectManyIterator[TSource,TCollection,TResult](IEnumerable`1 source, Func`2 collectionSelector, Func`3 resultSelector)+MoveNext()
   at System.Linq.Enumerable.TryGetFirst[TSource](IEnumerable`1 source, Boolean& found)
   at System.Linq.Enumerable.First[TSource](IEnumerable`1 source)
   at System.Linq.EnumerableExecutor`1.Execute()
   at System.Linq.EnumerableQuery`1.System.Linq.IQueryProvider.Execute[TElement](Expression expression)
   at System.Linq.Queryable.First[TSource](IQueryable`1 source)
   at System.Linq.Queryable.First[TSource](IQueryable`1 source)
   at …

Or, using the most recent NuGet package (version 4.13.1), :

System.NotSupportedException: The equals ("==" or "=" in VB) and the conditional 'and' ("&&" or "AndAlso" in VB) operators are the only ones supported in the query specification expression. Unsupported expression: Mock.Get<IX>(x).Setup<int>(mock => mock.N).Returns(2) != null
   at Moq.Linq.MockSetupsBuilder.VisitBinary(BinaryExpression node)
   at System.Linq.Expressions.BinaryExpression.Accept(ExpressionVisitor visitor)
   at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
   at System.Linq.Expressions.ExpressionVisitor.VisitLambda[T](Expression`1 node)
   at System.Linq.Expressions.Expression`1.Accept(ExpressionVisitor visitor)
   at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
   at System.Linq.Expressions.ExpressionVisitor.VisitUnary(UnaryExpression node)
   at System.Linq.Expressions.UnaryExpression.Accept(ExpressionVisitor visitor)
   at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
   at System.Dynamic.Utils.ExpressionVisitorUtils.VisitArguments(ExpressionVisitor visitor, IArgumentProvider nodes)
   at System.Linq.Expressions.ExpressionVisitor.VisitMethodCall(MethodCallExpression node)
   at Moq.Linq.MockSetupsBuilder.VisitMethodCall(MethodCallExpression node)
   at System.Linq.Expressions.MethodCallExpression.Accept(ExpressionVisitor visitor)
   at Moq.Linq.MockQueryable`1.Execute[TResult](Expression expression)
   at Moq.Linq.MockQueryable`1.GetEnumerator()
   at System.Linq.Enumerable.SelectManyIterator[TSource,TCollection,TResult](IEnumerable`1 source, Func`2 collectionSelector, Func`3 resultSelector)+MoveNext()
   at System.Linq.Enumerable.TryGetFirst[TSource](IEnumerable`1 source, Boolean& found)
   at System.Linq.Enumerable.First[TSource](IEnumerable`1 source)
   at System.Linq.EnumerableExecutor`1.Execute()
   at System.Linq.EnumerableQuery`1.System.Linq.IQueryProvider.Execute[TElement](Expression expression)
   at System.Linq.Queryable.First[TSource](IQueryable`1 source)
   at System.Linq.Queryable.First[TSource](IQueryable`1 source)
   at …

It looks like the expression tree gets analysed by Moq's expression splitting routine instead of simply being compiled and executed.

Expected behavior:

In analogy to a LINQ query expression of the general form:

(from x in xs
 from _ inselect x)
.First()

which would yield xs.First(), I'd expect the above query to yield an IX where .N == 1.

@stakx stakx added the bug label Mar 27, 2020
@stakx stakx self-assigned this Mar 27, 2020
@stakx stakx changed the title LINQ query with two from clauses and .First() rewritten/executed incorrectly Failure when parameterized Mock.Of<> is used in query comprehension from clause Oct 28, 2020
@stakx stakx added this to the 4.15.0 milestone Oct 28, 2020
mburumaxwell pushed a commit to faluapp/falu-dotnet that referenced this issue Jun 12, 2021
Bumps [Moq](https://github.com/moq/moq4) from 4.14.7 to 4.15.2.

#Changelog

*Sourced from [Moq's changelog](https://github.com/moq/moq4/blob/master/CHANGELOG.md).*

> ## 4.15.2 (2020-11-26)
>
> #### Changed
>
> * Upgraded `System.Threading.Tasks.Extensions` dependency to version 4.5.4 (@JeffAshton, [#1108](devlooped/moq#1108))
>
>
> ## 4.15.1 (2020-11-10)
>
> #### Added
>
> * New method overloads for `It.Is`, `It.IsIn`, and `It.IsNotIn` that compare values using a custom `IEqualityComparer<T>` (@weitzhandler, [#1064](devlooped/moq#1064))
> * New properties `ReturnValue` and `Exception` on `IInvocation` to query recorded invocations return values or exceptions (@MaStr11, [#921](devlooped/moq#921), [#1077](devlooped/moq#1077))
> * Support for "nested" type matchers, i.e. type matchers that appear as part of a composite type (such as `It.IsAnyType[]` or `Func<It.IsAnyType, bool>`). Argument match expressions like `It.IsAny<Func<It.IsAnyType, bool>>()` should now work as expected, whereas they previously didn't. In this particular example, you should no longer need a workaround like `(Func<It.IsAnyType, bool>)It.IsAny<object>()` as originally suggested in [#918](devlooped/moq#918). (@stakx, [#1092](devlooped/moq#1092))
>
> #### Changed
>
> * Event accessor calls (`+=` and `-=`) now get consistently recorded in `Mock.Invocations`. This previously wasn't the case for backwards compatibility with `VerifyNoOtherCalls` (which got implemented before it was possible to check them using `Verify{Add,Remove}`). You now need to explicitly verify expected calls to event accessors prior to `VerifyNoOtherCalls`. Verification of `+=` and `-=` now works regardless of whether or not you set those up (which makes it consistent with how verification usually works). (@80O, @stakx, [#1058](devlooped/moq#1058), [#1084](devlooped/moq#1084))
> * Portable PDB (debugging symbols) are now embedded in the main library instead of being published as a separate NuGet symbols package (`.snupkg) (@kzu, [#1098](devlooped/moq#1098))
>
> #### Fixed
>
> * `SetupProperty` fails if property getter and setter are not both defined in mocked type (@stakx, [#1017](devlooped/moq#1017))
> * Expression tree argument not matched when it contains a captured variable &ndash; evaluate all captures to their current values when comparing two expression trees (@QTom01, [#1054](devlooped/moq#1054))
> * Failure when parameterized `Mock.Of<>` is used in query comprehension `from` clause (@stakx, [#982](devlooped/moq#982))
>
>
> ## 4.15.0
>
> This version was accidentally published as 4.15.1 due to an intermittent problem with NuGet publishing.

#Commits

- [`f2aa090`](devlooped/moq@f2aa090) ...
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant