Skip to content

Commit 74d2528

Browse files
mock.Protected().Setup<int>("Foo") fails base implementation of Foo is hidden in the derived class (#1341)
1 parent 1c4c723 commit 74d2528

File tree

3 files changed

+88
-4
lines changed

3 files changed

+88
-4
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ The format is loosely based on [Keep a Changelog](http://keepachangelog.com/en/1
77

88
## Unreleased
99

10+
#### Fixed
11+
12+
* mock.Protected().Setup<int>("Foo") fails base implementation of Foo is hidden in the derived class (#1341)
13+
1014
#### Added
1115

1216
* `Mock<T>.RaiseAsync` method for raising "async" events, i.e. events that use a `Func<..., Task>` or `Func<..., ValueTask>` delegate. (@stakx, #1313)

src/Moq/Protected/ProtectedMock.cs

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -326,8 +326,24 @@ private static MethodInfo GetMethod(string methodName, Type[] genericTypeArgumen
326326
.Select(m => m.MakeGenericMethod(genericTypeArguments));
327327
}
328328

329-
return methods
330-
.SingleOrDefault(m => m.GetParameterTypes().CompareTo(argTypes, exact, considerTypeMatchers: false));
329+
methods = methods.Where(m => m.GetParameterTypes().CompareTo(argTypes, exact, considerTypeMatchers: false));
330+
331+
if (methods.Count() < 2)
332+
{
333+
return methods.FirstOrDefault();
334+
}
335+
336+
for (Type type = typeof(T); type != typeof(object); type = type.BaseType)
337+
{
338+
var method = methods.SingleOrDefault(m => m.DeclaringType == typeof(T));
339+
340+
if (method != null)
341+
{
342+
return method;
343+
}
344+
}
345+
346+
return null;
331347
}
332348

333349
private static Expression<Func<T, TResult>> GetMethodCall<TResult>(MethodInfo method, object[] args)
@@ -543,7 +559,7 @@ private static Expression ToExpressionArg(Type type, object arg)
543559
}
544560
return expression;
545561
}
546-
562+
547563
if (IsItRefAny(expression))
548564
{
549565
return expression;

tests/Moq.Tests/ProtectedMockFixture.cs

Lines changed: 65 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -475,6 +475,39 @@ public void SetupResultAllowsProtectedMethodInBaseClass()
475475
Assert.Equal(5, mock.Object.DoProtectedReturnGeneric<int>());
476476
}
477477

478+
[Fact]
479+
public void SetupResultAllowsHiddenVirtualMethods()
480+
{
481+
var mock = new Mock<FooDerived>();
482+
mock.Protected()
483+
.Setup<int>("ProtectedHiddenInt")
484+
.Returns(5);
485+
486+
Assert.Equal(5, mock.Object.DoProtectedHiddenInt());
487+
Assert.Equal(2, ((FooBase)mock.Object).DoProtectedHiddenInt());
488+
489+
mock.Protected()
490+
.Setup<int>("ProtectedHiddenWithGenericParam", new[] { typeof(int) }, false)
491+
.Returns(5);
492+
Assert.Equal(5, mock.Object.DoProtectedHiddenWithGenericParam<int>());
493+
494+
mock.Protected()
495+
.Setup<int>("ProtectedHiddenSum", genericTypeArguments: Array.Empty<Type>(), exactParameterMatch: true, 1, 2)
496+
.Returns(3);
497+
498+
Assert.Equal(3, mock.Object.DoProtectedHiddenSum(1, 2));
499+
500+
mock.Protected()
501+
.Setup<int>("ProtectedHiddenSum", genericTypeArguments: Array.Empty<Type>(), exactParameterMatch: true, 1, 2, 3)
502+
.Returns(6);
503+
Assert.Equal(6, mock.Object.DoProtectedHiddenSum(1, 2, 3));
504+
505+
mock.Protected()
506+
.Setup<int>("ProtectedHiddenSum", genericTypeArguments: Array.Empty<Type>(), exactParameterMatch: true, 1, 2, 3, 4)
507+
.Returns(10);
508+
Assert.Equal(10, mock.Object.DoProtectedHiddenSum(1, 2, 3, 4));
509+
}
510+
478511
[Fact]
479512
public void SetupResultDefaulTwoOverloadsWithDerivedClassThrowsInvalidOperationException()
480513
{
@@ -1041,7 +1074,7 @@ public void SetMatcherExpressionProperty(MethodCallExpression expression)
10411074
}
10421075

10431076
protected virtual LambdaExpression LambdaExpressionProperty { get; set; }
1044-
1077+
10451078
public void SetLambdaExpressionProperty(LambdaExpression expression)
10461079
{
10471080
LambdaExpressionProperty = expression;
@@ -1111,6 +1144,14 @@ public string DoTwoArgs(string arg, int arg1)
11111144
return this.TwoArgs(arg, arg1);
11121145
}
11131146

1147+
public int DoProtectedHiddenInt() => this.ProtectedHiddenInt();
1148+
1149+
public T DoProtectedHiddenWithGenericParam<T>() => this.ProtectedHiddenWithGenericParam<T>();
1150+
1151+
public int DoProtectedHiddenSum(int op1, int op2) => this.ProtectedHiddenSum(op1, op2);
1152+
1153+
public int DoProtectedHiddenSum(int op1, int op2, int op3) => this.ProtectedHiddenSum(op1, op2, op3);
1154+
11141155
public string GetProtectedValue()
11151156
{
11161157
return this.ProtectedValue;
@@ -1194,10 +1235,33 @@ protected virtual string TwoArgs(string arg, int arg1)
11941235
{
11951236
return arg;
11961237
}
1238+
1239+
protected virtual int ProtectedHiddenInt() => 2;
1240+
1241+
protected virtual T ProtectedHiddenWithGenericParam<T>() => default(T);
1242+
1243+
protected new virtual int ProtectedHiddenSum(int op1, int op2) => throw new NotImplementedException();
1244+
1245+
protected new virtual int ProtectedHiddenSum(int op1, int op2, int op3) => throw new NotImplementedException();
11971246
}
11981247

11991248
public class FooDerived : FooBase
12001249
{
1250+
protected new virtual int ProtectedHiddenInt() => 22;
1251+
1252+
protected new virtual T ProtectedHiddenWithGenericParam<T>() => default(T);
1253+
1254+
protected new virtual int ProtectedHiddenSum(int op1, int op2) => throw new NotImplementedException();
1255+
1256+
protected virtual int ProtectedHiddenSum(int op1, int op2, int op3, int op4) => throw new NotImplementedException();
1257+
1258+
public new int DoProtectedHiddenInt() => this.ProtectedHiddenInt();
1259+
1260+
public new T DoProtectedHiddenWithGenericParam<T>() => this.ProtectedHiddenWithGenericParam<T>();
1261+
1262+
public new int DoProtectedHiddenSum(int op1, int op2) => this.ProtectedHiddenSum(op1, op2);
1263+
1264+
public int DoProtectedHiddenSum(int op1, int op2, int op3, int op4) => this.ProtectedHiddenSum(op1, op2, op3, op4);
12011265
}
12021266

12031267
public class MyBase { }

0 commit comments

Comments
 (0)