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

Returns(null) requires explicit typecast in Strict mocks #600

Closed
Caraul opened this issue Mar 5, 2018 · 4 comments
Closed

Returns(null) requires explicit typecast in Strict mocks #600

Caraul opened this issue Mar 5, 2018 · 4 comments
Labels

Comments

@Caraul
Copy link
Contributor

Caraul commented Mar 5, 2018

Hi,

Returns(null) doesn't compile due to ambiguous invocation.
Returns((SomeType)null) is "inferred" to Returns(SomeType value) which has no problems.
Returns<SomeType>(null) is "inferred" to Returns(Func<SomeType> valueFunction) which is simply set null delegate with ReturnValueKind.Explicit. For MockBehavior.Strict in MethodCallReturn.Execute it throws with ExceptionReason.ReturnValueRequired (despite of set ReturnValueKind.Explicit). Is it correct? I'd suppose (this.valueDel != null) should be replaced with (this.returnValueKind == ReturnValueKind.Explicit) and either calls delegate or invocation.Return(default(TResult)) for explicit null values. Or maybe should Returns(Func<SomeType>) behave the same as Returns(Delegate valueFunction) which has special treatment for nulls "because Moq has been very forgiving with incorrect Returns in the past."?

@Caraul Caraul changed the title Returns(null) requires explicit typecast Returns(null) requires explicit typecast in Strict mocks Mar 5, 2018
@stakx
Copy link
Contributor

stakx commented Mar 5, 2018

@Caraul: I've noticed before that Returns has a few inconsistencies. The way how it deals with null might be one of them. That being said, I'm not sure whether I understand what your issue is about.

Is it about this:

Returns(null) doesn't compile due to ambiguous invocation.

There's probably very little that we can do about this. Changing this would likely require changing the method overloads' definitions, which would be likely to cause breaking changes.

Or is the issue about this:

For MockBehavior.Strict in MethodCallReturn.Execute it throws with ExceptionReason.ReturnValueRequired [...].

If so, then please confirm and I'll take a closer look at it.

@stakx
Copy link
Contributor

stakx commented Mar 5, 2018

Please forget the above question, I misunderstood.

This appears to be a regression introduced in Moq 4.8.0. Before that, it appears to have been legal to call Returns(Func<TResult>) with null. I'll try to find out what went wrong and get back to you.

@stakx stakx added the bug label Mar 5, 2018
@stakx
Copy link
Contributor

stakx commented Mar 5, 2018

Looks like the problem is here in 4.8.0:

https://github.com/moq/moq4/blob/f6a8be6f7fd0baf6f57eba714e591d6274ae0f67/Source/MethodCallReturn.cs#L154-L163

which used to be (in 4.7.145):

https://github.com/moq/moq4/blob/2d06029206558f8fc1571da52a062e192ac83ff7/Source/MethodCallReturn.cs#L124-L136

Note that the null special case that used to be there in 4.7.145 has been removed in 4.8.0. This bug probably crept in while we improved Moq's support for by-ref parameters.

We should probably restore it, something along these lines:

if  (value == null)
{
    this.valueDel = (Func<TResult>)(() => default(TResult));
    // though I wonder why Moq used `default(TResult)` instead of `null` previously...?
}
else
{
    ValidateReturnDelegate(value);
    this.valueDel = value;
}
...

Would you like to work on this?

@Caraul
Copy link
Contributor Author

Caraul commented Mar 6, 2018

Of course yes, I'll fix it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants