Skip to content

Commit d3128ef

Browse files
committed
Merge branch 'superfluous-vb-conversion-exprs' into hotfix-release
2 parents 1465ca7 + b0346de commit d3128ef

File tree

3 files changed

+62
-5
lines changed

3 files changed

+62
-5
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,12 @@ All notable changes to this project will be documented in this file.
44

55
The format is loosely based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/).
66

7+
## Unreleased
8+
9+
#### Fixed
10+
11+
* Setup not triggered due to VB.NET transparently inserting superfluous type conversions into a setup expression (@InteXX, #1067)
12+
713

814
## 4.14.6 (2020-09-30)
915

src/Moq/MatcherFactory.cs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -120,8 +120,13 @@ public static Pair<IMatcher, Expression> CreateMatcher(Expression expression)
120120
// the values are ints, but if the method to call
121121
// expects, say, a double, a Convert node will be on
122122
// the expression.
123+
//
124+
// Another case is VB.NET explicitly upcasting generic type parameters to the type they're constrained to,
125+
// in places where the constrained-to type is expected. Say you have a parameter with static type `TBase`,
126+
// and you're passing `It.IsAny<T>()` where `T : TBase`. VB.NET will then transform this call to
127+
// `(TBase)(object)It.IsAny<T>()`.
123128
var originalExpression = expression;
124-
if (expression.NodeType == ExpressionType.Convert)
129+
while (expression.NodeType == ExpressionType.Convert)
125130
{
126131
expression = ((UnaryExpression)expression).Operand;
127132
}
@@ -173,7 +178,7 @@ public static Pair<IMatcher, Expression> CreateMatcher(Expression expression)
173178
}
174179

175180
throw new NotSupportedException(
176-
string.Format(CultureInfo.CurrentCulture, Resources.UnsupportedExpression, expression));
181+
string.Format(CultureInfo.CurrentCulture, Resources.UnsupportedExpression, originalExpression));
177182
}
178183
}
179184
}

tests/Moq.Tests.VisualBasic/IssueReports.vb

Lines changed: 49 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
' Copyright (c) 2007, Clarius Consulting, Manas Technology Solutions, InSTEDD, and Contributors.
22
' All rights reserved. Licensed under the BSD 3-Clause License; see License.txt.
33

4-
Imports Moq
5-
Imports Xunit
6-
4+
Imports System.Linq.Expressions
75

6+
Imports Xunit
87

98
Public Class IssueReports
109

@@ -29,4 +28,51 @@ Public Class IssueReports
2928
End Interface
3029
End Class
3130

31+
Public Class Issue1067
32+
33+
<Fact>
34+
Public Sub Test_NonGeneric()
35+
Dim userManagerMock = New Mock(Of IUserManager)()
36+
Setup_NonGeneric(userManagerMock, 42)
37+
38+
Dim user As New User()
39+
userManagerMock.Object.Create(user)
40+
41+
Assert.Equal(42, user.Id)
42+
End Sub
43+
44+
<Fact>
45+
Public Sub Test_Generic()
46+
Dim userManagerMock = New Mock(Of IUserManager)()
47+
Setup_Generic(Of User)(userManagerMock, 42)
48+
49+
Dim user As New User()
50+
userManagerMock.Object.Create(user)
51+
52+
Assert.Equal(42, user.Id)
53+
End Sub
54+
55+
Public Class User
56+
Property Id As Integer
57+
End Class
58+
59+
Public Interface IUserManager
60+
Sub Create(User As User)
61+
End Interface
62+
63+
Protected Sub Setup_NonGeneric(userManagerMock As Mock(Of IUserManager), expectedId As Integer)
64+
userManagerMock.Setup(Sub(manager) manager.Create(It.IsAny(Of User))).Callback(Sub(user) user.Id = expectedId)
65+
End Sub
66+
67+
Protected Sub Setup_Generic(Of TUser As User)(userManagerMock As Mock(Of IUserManager), expectedId As Integer)
68+
userManagerMock.Setup(Sub(manager) manager.Create(It.IsAny(Of TUser))).Callback(Sub(user) user.Id = expectedId)
69+
' ^
70+
' The use of generics will cause the VB.NET compiler to wrap the `It.IsAny<>` call with two `Convert` nodes.
71+
' The inner conversion will convert to `Object`, and the outer conversion will convert to `User` (i.e. the type that
72+
' `TUser` is constrained to). `MatcherFactory` needs to be able to recognize the `It.IsAny<>` matcher even if it
73+
' is doubly wrapped!
74+
End Sub
75+
76+
End Class
77+
3278
End Class

0 commit comments

Comments
 (0)