From c7df19ec3275eb3853a34666746d4e554de678e4 Mon Sep 17 00:00:00 2001 From: Tony Hallett Date: Sat, 29 May 2021 12:19:34 +0100 Subject: [PATCH 1/5] Add "set" methods to ProtectedAsMock --- src/Moq/Mock`1.cs | 2 +- src/Moq/Protected/DuckSetterReplacer.cs | 52 +++++++++++ src/Moq/Protected/IProtectedAsMock.cs | 46 +++++++++ src/Moq/Protected/ProtectedAsMock.cs | 26 ++++++ tests/Moq.Tests/ProtectedAsMockFixture.cs | 109 ++++++++++++++++++++++ 5 files changed, 234 insertions(+), 1 deletion(-) create mode 100644 src/Moq/Protected/DuckSetterReplacer.cs diff --git a/src/Moq/Mock`1.cs b/src/Moq/Mock`1.cs index 34dcb165b..3d25aef42 100644 --- a/src/Moq/Mock`1.cs +++ b/src/Moq/Mock`1.cs @@ -480,7 +480,7 @@ public ISetupGetter SetupGet(Expression /// The Lambda expression that sets a property to a value. - /// Type of the property. Typically omitted as it can be inferred from the expression. + /// Type of the property. /// /// If more than one setup is set for the same property setter, /// the latest one wins and is the one that will be executed. diff --git a/src/Moq/Protected/DuckSetterReplacer.cs b/src/Moq/Protected/DuckSetterReplacer.cs new file mode 100644 index 000000000..b7532e465 --- /dev/null +++ b/src/Moq/Protected/DuckSetterReplacer.cs @@ -0,0 +1,52 @@ +using System; +using System.Linq; +using System.Linq.Expressions; +using System.Reflection; + +namespace Moq.Protected +{ + internal sealed class DuckSetterReplacer : ExpressionVisitor + { + private ParameterExpression parameterToReplace; + private ParameterExpression mockParameter; + private Type mockType = typeof(TMock); + + private PropertyInfo GetMockProperty(PropertyInfo property) + { + return mockType.GetProperty( + property.Name, + BindingFlags.NonPublic | BindingFlags.Instance, + null, + property.PropertyType, + property.GetIndexParameters().Select(p => p.ParameterType).ToArray(), + new ParameterModifier[] { } + ); + } + + protected override Expression VisitIndex(IndexExpression node) + { + if (node.Object is ParameterExpression parameterExpression && parameterExpression == parameterToReplace) + { + return Expression.MakeIndex(mockParameter, GetMockProperty(node.Indexer), node.Arguments); + } + return base.VisitIndex(node); + } + + protected override Expression VisitMember(MemberExpression node) + { + if (node.Expression is ParameterExpression parameterExpression && parameterExpression == parameterToReplace) + { + return Expression.MakeMemberAccess(mockParameter, GetMockProperty(node.Member as PropertyInfo)); + } + return base.VisitMember(node); + } + + public Expression> Replace(Expression> expression) + { + parameterToReplace = expression.Parameters[0]; + mockParameter = Expression.Parameter(typeof(TMock), parameterToReplace.Name); + return Expression.Lambda>(expression.Body.Apply(this), mockParameter); + } + + } +} diff --git a/src/Moq/Protected/IProtectedAsMock.cs b/src/Moq/Protected/IProtectedAsMock.cs index 9539b9a16..9c8a02ba6 100644 --- a/src/Moq/Protected/IProtectedAsMock.cs +++ b/src/Moq/Protected/IProtectedAsMock.cs @@ -39,6 +39,41 @@ public interface IProtectedAsMock : IFluentInterface /// ISetup Setup(Expression> expression); + + /// + /// Specifies a setup on the mocked type for a call to a property setter. + /// + /// The Lambda expression that sets a property to a value. + /// Type of the property. + /// + /// If more than one setup is set for the same property setter, + /// the latest one wins and is the one that will be executed. + /// + /// This overloads allows the use of a callback already typed for the property type. + /// + /// + /// + /// + /// mock.SetupSet(x => x.Suspended = true); + /// + /// + ISetupSetter SetupSet(Action setterExpression); + + /// + /// Specifies a setup on the mocked type for a call to a property setter. + /// + /// Lambda expression that sets a property to a value. + /// + /// If more than one setup is set for the same property setter, + /// the latest one wins and is the one that will be executed. + /// + /// + /// + /// mock.SetupSet(x => x.Suspended = true); + /// + /// + ISetup SetupSet(Action setterExpression); + /// /// Specifies a setup on the mocked type for a call to a property getter. /// @@ -96,6 +131,17 @@ public interface IProtectedAsMock : IFluentInterface /// The specified invocation did not occur (or did not occur the specified number of times). void Verify(Expression> expression, Times? times = null, string failMessage = null); + /// + /// Verifies that a property was set on the mock, specifying a failure message. + /// + /// The number of times a method is expected to be called. Defaults to Times.AtLeastOnce + /// Expression to verify. + /// Message to show if verification fails. + /// + /// The invocation was not called the number of times specified by . + /// + void VerifySet(Action setterExpression, Times? times = null, string failMessage = null); + /// /// Verifies that a property was read on the mock. /// diff --git a/src/Moq/Protected/ProtectedAsMock.cs b/src/Moq/Protected/ProtectedAsMock.cs index 0cffd21bb..4dc9e4ad1 100644 --- a/src/Moq/Protected/ProtectedAsMock.cs +++ b/src/Moq/Protected/ProtectedAsMock.cs @@ -20,6 +20,7 @@ internal sealed class ProtectedAsMock : IProtectedAsMock private Mock mock; private static DuckReplacer DuckReplacerInstance = new DuckReplacer(typeof(TAnalog), typeof(T)); + private static DuckSetterReplacer DuckSetterReplacerInstance = new DuckSetterReplacer(); public ProtectedAsMock(Mock mock) { @@ -64,6 +65,18 @@ public ISetup Setup(Expression> expr return new NonVoidSetupPhrase(setup); } + public ISetupSetter SetupSet(Action setterExpression) + { + var setup = Mock.SetupSet(mock, ReplaceDuckSetter(setterExpression), condition: null); + return new SetterSetupPhrase(setup); + } + + public ISetup SetupSet(Action setterExpression) + { + var setup = Mock.SetupSet(mock, ReplaceDuckSetter(setterExpression), condition: null); + return new VoidSetupPhrase(setup); + } + public ISetupGetter SetupGet(Expression> expression) { Guard.NotNull(expression, nameof(expression)); @@ -169,6 +182,11 @@ public void Verify(Expression> expression, Times Mock.Verify(this.mock, rewrittenExpression, times ?? Times.AtLeastOnce(), failMessage); } + public void VerifySet(Action setterExpression, Times? times = null, string failMessage = null) + { + Mock.VerifySet(mock, ReplaceDuckSetter(setterExpression), times.HasValue ? times.Value : Times.AtLeastOnce(), failMessage); + } + public void VerifyGet(Expression> expression, Times? times = null, string failMessage = null) { Guard.NotNull(expression, nameof(expression)); @@ -186,6 +204,13 @@ public void VerifyGet(Expression> expression Mock.VerifyGet(this.mock, rewrittenExpression, times ?? Times.AtLeastOnce(), failMessage); } + private Expression> ReplaceDuckSetter(Action setterExpression) + { + Guard.NotNull(setterExpression, nameof(setterExpression)); + + var expression = ExpressionReconstructor.Instance.ReconstructExpression(setterExpression, mock.ConstructorArguments); + return DuckSetterReplacerInstance.Replace(expression); + } private static LambdaExpression ReplaceDuck(LambdaExpression expression) { Debug.Assert(expression.Parameters.Count == 1); @@ -363,5 +388,6 @@ private static bool IsCorrespondingProperty(PropertyInfo duckProperty, PropertyI // TODO: parameter lists should be compared, too, to properly support indexers. } } + } } diff --git a/tests/Moq.Tests/ProtectedAsMockFixture.cs b/tests/Moq.Tests/ProtectedAsMockFixture.cs index 677604b6f..ef518ae67 100644 --- a/tests/Moq.Tests/ProtectedAsMockFixture.cs +++ b/tests/Moq.Tests/ProtectedAsMockFixture.cs @@ -213,6 +213,89 @@ public void SetupSequence_can_setup_actions() Assert.IsType(exception); } + [Fact] + public void SetUpSet_should_setup_setters() + { + this.protectedMock.SetupSet(fish => fish.ReadWritePropertyImpl = 999).Throws(ExpectedException.Instance); + + mock.Object.ReadWriteProperty = 123; + + Assert.Throws(() => mock.Object.ReadWriteProperty = 999); + } + + [Fact] + public void SetUpSet_should_setup_setters_with_property_type() + { + int value = 0; + this.protectedMock.SetupSet(fish => fish.ReadWritePropertyImpl = 999).Callback(i => value = i); + + mock.Object.ReadWriteProperty = 123; + Assert.Equal(0, value); + + mock.Object.ReadWriteProperty = 999; + Assert.Equal(999, value); + } + + [Fact] + public void SetUpSet_should_work_recursively() + { + this.protectedMock.SetupSet(f => f.Nested.Value = 999).Throws(ExpectedException.Instance); + + mock.Object.GetNested().Value = 1; + + Assert.Throws(() => mock.Object.GetNested().Value = 999); + } + + [Fact] + public void SetUpSet_Should_Work_With_Indexers() + { + this.protectedMock.SetupSet( + o => o[ + It.IsInRange(0, 5, Range.Inclusive), + It.IsIn("Bad", "JustAsBad") + ] = It.Is(i => i > 10) + ).Throws(ExpectedException.Instance); + + mock.Object.SetMultipleIndexer(1, "Ok", 999); + + Assert.Throws(() => mock.Object.SetMultipleIndexer(1, "Bad", 999)); + + } + + [Fact] + public void VerifySet_Should_Work() + { + void VerifySet(Times? times = null,string failMessage = null) + { + this.protectedMock.VerifySet( + o => o[ + It.IsInRange(0, 5, Moq.Range.Inclusive), + It.IsIn("Bad", "JustAsBad") + ] = It.Is(i => i > 10), + times, + failMessage + ); + } + VerifySet(Times.Never()); + + mock.Object.SetMultipleIndexer(1, "Ok", 1); + VerifySet(Times.Never()); + + Assert.Throws(() => VerifySet()); // AtLeastOnce + + mock.Object.SetMultipleIndexer(1, "Bad", 999); + VerifySet(); // AtLeastOnce + + mock.Object.SetMultipleIndexer(1, "JustAsBad", 12); + VerifySet(Times.Exactly(2)); + + Assert.Throws(() => VerifySet(Times.AtMostOnce())); + + var mockException = Assert.Throws(() => VerifySet(Times.AtMostOnce(),"custom fail message")); + Assert.StartsWith("custom fail message", mockException.Message); + + } + [Fact] public void Verify_can_verify_method_invocations() { @@ -298,6 +381,10 @@ public void VerifyGet_includes_failure_message_in_exception() Assert.Contains("Was not queried.", exception.Message); } + public interface INested + { + int Value { get; set; } + } public abstract class Foo { protected Foo() @@ -336,6 +423,20 @@ public int GetSomething() protected abstract void DoSomethingImpl(int arg); protected abstract int GetSomethingImpl(); + + protected abstract INested Nested { get; set; } + + public INested GetNested() + { + return Nested; + } + + protected abstract int this[int i, string s] { get; set; } + + public void SetMultipleIndexer(int index, string sIndex, int value) + { + this[index, sIndex] = value; + } } public interface Fooish @@ -347,6 +448,8 @@ public interface Fooish void DoSomethingImpl(int arg); int GetSomethingImpl(); void NonExistentMethod(); + INested Nested { get; set; } + int this[int i, string s] { get; set; } } public abstract class MessageHandlerBase @@ -366,5 +469,11 @@ public interface MessageHandlerBaseish { void HandleImpl(TMessage message); } + + public class ExpectedException : Exception + { + private static ExpectedException expectedException = new ExpectedException(); + public static ExpectedException Instance => expectedException; + } } } From 2f6a7623e5a66d46af20aebcc5f4a4dd8ff79187 Mon Sep 17 00:00:00 2001 From: Tony Hallett Date: Wed, 23 Jun 2021 10:48:46 +0100 Subject: [PATCH 2/5] code review and fix #1162 --- CHANGELOG.md | 5 ++ src/Moq/Protected/DuckSetterReplacer.cs | 52 -------------- src/Moq/Protected/IProtectedAsMock.cs | 9 ++- src/Moq/Protected/ProtectedAsMock.cs | 42 ++++++++---- tests/Moq.Tests/ProtectedAsMockFixture.cs | 82 ++++++++++++++++++++++- 5 files changed, 121 insertions(+), 69 deletions(-) delete mode 100644 src/Moq/Protected/DuckSetterReplacer.cs diff --git a/CHANGELOG.md b/CHANGELOG.md index 936deb043..37b969ad0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,8 +7,13 @@ The format is loosely based on [Keep a Changelog](http://keepachangelog.com/en/1 ## Unreleased +#### Added + +* `SetupSet`, `VerifySet` methods for `mock.Protected().As<>()` (@tonyhallett, #1165) + #### Fixed +* Virtual properties and automocking not working for `mock.Protected().As<>()` (@tonyhallett, #1165) * Issue mocking VB.NET class with overloaded property/indexer in base class (@myurashchyk, #1153) diff --git a/src/Moq/Protected/DuckSetterReplacer.cs b/src/Moq/Protected/DuckSetterReplacer.cs deleted file mode 100644 index b7532e465..000000000 --- a/src/Moq/Protected/DuckSetterReplacer.cs +++ /dev/null @@ -1,52 +0,0 @@ -using System; -using System.Linq; -using System.Linq.Expressions; -using System.Reflection; - -namespace Moq.Protected -{ - internal sealed class DuckSetterReplacer : ExpressionVisitor - { - private ParameterExpression parameterToReplace; - private ParameterExpression mockParameter; - private Type mockType = typeof(TMock); - - private PropertyInfo GetMockProperty(PropertyInfo property) - { - return mockType.GetProperty( - property.Name, - BindingFlags.NonPublic | BindingFlags.Instance, - null, - property.PropertyType, - property.GetIndexParameters().Select(p => p.ParameterType).ToArray(), - new ParameterModifier[] { } - ); - } - - protected override Expression VisitIndex(IndexExpression node) - { - if (node.Object is ParameterExpression parameterExpression && parameterExpression == parameterToReplace) - { - return Expression.MakeIndex(mockParameter, GetMockProperty(node.Indexer), node.Arguments); - } - return base.VisitIndex(node); - } - - protected override Expression VisitMember(MemberExpression node) - { - if (node.Expression is ParameterExpression parameterExpression && parameterExpression == parameterToReplace) - { - return Expression.MakeMemberAccess(mockParameter, GetMockProperty(node.Member as PropertyInfo)); - } - return base.VisitMember(node); - } - - public Expression> Replace(Expression> expression) - { - parameterToReplace = expression.Parameters[0]; - mockParameter = Expression.Parameter(typeof(TMock), parameterToReplace.Name); - return Expression.Lambda>(expression.Body.Apply(this), mockParameter); - } - - } -} diff --git a/src/Moq/Protected/IProtectedAsMock.cs b/src/Moq/Protected/IProtectedAsMock.cs index 9c8a02ba6..354351ffc 100644 --- a/src/Moq/Protected/IProtectedAsMock.cs +++ b/src/Moq/Protected/IProtectedAsMock.cs @@ -54,7 +54,7 @@ public interface IProtectedAsMock : IFluentInterface /// /// /// - /// mock.SetupSet(x => x.Suspended = true); + /// mock.SetupSet<bool>(x => x.Suspended = true); /// /// ISetupSetter SetupSet(Action setterExpression); @@ -132,10 +132,13 @@ public interface IProtectedAsMock : IFluentInterface void Verify(Expression> expression, Times? times = null, string failMessage = null); /// - /// Verifies that a property was set on the mock, specifying a failure message. + /// Verifies that a property was set on the mock. /// - /// The number of times a method is expected to be called. Defaults to Times.AtLeastOnce /// Expression to verify. + /// + /// Number of times that the setter is expected to have occurred. + /// If omitted, assumed to be . + /// /// Message to show if verification fails. /// /// The invocation was not called the number of times specified by . diff --git a/src/Moq/Protected/ProtectedAsMock.cs b/src/Moq/Protected/ProtectedAsMock.cs index 4dc9e4ad1..b82718ec9 100644 --- a/src/Moq/Protected/ProtectedAsMock.cs +++ b/src/Moq/Protected/ProtectedAsMock.cs @@ -20,7 +20,6 @@ internal sealed class ProtectedAsMock : IProtectedAsMock private Mock mock; private static DuckReplacer DuckReplacerInstance = new DuckReplacer(typeof(TAnalog), typeof(T)); - private static DuckSetterReplacer DuckSetterReplacerInstance = new DuckSetterReplacer(); public ProtectedAsMock(Mock mock) { @@ -67,13 +66,19 @@ public ISetup Setup(Expression> expr public ISetupSetter SetupSet(Action setterExpression) { - var setup = Mock.SetupSet(mock, ReplaceDuckSetter(setterExpression), condition: null); + Guard.NotNull(setterExpression, nameof(setterExpression)); + + var rewrittenExpression = ReconstructAndReplaceSetter(setterExpression); + var setup = Mock.SetupSet(mock, rewrittenExpression, condition: null); return new SetterSetupPhrase(setup); } public ISetup SetupSet(Action setterExpression) { - var setup = Mock.SetupSet(mock, ReplaceDuckSetter(setterExpression), condition: null); + Guard.NotNull(setterExpression, nameof(setterExpression)); + + var rewrittenExpression = ReconstructAndReplaceSetter(setterExpression); + var setup = Mock.SetupSet(mock, rewrittenExpression, condition: null); return new VoidSetupPhrase(setup); } @@ -184,7 +189,10 @@ public void Verify(Expression> expression, Times public void VerifySet(Action setterExpression, Times? times = null, string failMessage = null) { - Mock.VerifySet(mock, ReplaceDuckSetter(setterExpression), times.HasValue ? times.Value : Times.AtLeastOnce(), failMessage); + Guard.NotNull(setterExpression, nameof(setterExpression)); + + var rewrittenExpression = ReconstructAndReplaceSetter(setterExpression); + Mock.VerifySet(mock, rewrittenExpression, times.HasValue ? times.Value : Times.AtLeastOnce(), failMessage); } public void VerifyGet(Expression> expression, Times? times = null, string failMessage = null) @@ -204,13 +212,12 @@ public void VerifyGet(Expression> expression Mock.VerifyGet(this.mock, rewrittenExpression, times ?? Times.AtLeastOnce(), failMessage); } - private Expression> ReplaceDuckSetter(Action setterExpression) + private LambdaExpression ReconstructAndReplaceSetter(Action setterExpression) { - Guard.NotNull(setterExpression, nameof(setterExpression)); - var expression = ExpressionReconstructor.Instance.ReconstructExpression(setterExpression, mock.ConstructorArguments); - return DuckSetterReplacerInstance.Replace(expression); + return ReplaceDuck(expression); } + private static LambdaExpression ReplaceDuck(LambdaExpression expression) { Debug.Assert(expression.Parameters.Count == 1); @@ -239,11 +246,21 @@ protected override Expression VisitMethodCall(MethodCallExpression node) { var targetParameter = Expression.Parameter(this.targetType, left.Name); return Expression.Call(targetParameter, FindCorrespondingMethod(node.Method), node.Arguments); - } + } else { - return node; + return base.VisitMethodCall(node); + } + } + + protected override Expression VisitIndex(IndexExpression node) + { + if (node.Object is ParameterExpression left && left.Type == this.duckType) + { + var targetParameter = Expression.Parameter(this.targetType, left.Name); + return Expression.MakeIndex(targetParameter, FindCorrespondingProperty(node.Indexer), node.Arguments); } + return base.VisitIndex(node); } protected override Expression VisitMember(MemberExpression node) @@ -255,7 +272,7 @@ protected override Expression VisitMember(MemberExpression node) } else { - return node; + return base.VisitMember(node); } } @@ -305,7 +322,7 @@ private PropertyInfo FindCorrespondingProperty(PropertyInfo duckProperty) { var candidateTargetProperties = this.targetType - .GetProperties(BindingFlags.NonPublic | BindingFlags.Instance) + .GetProperties(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance) .Where(ctp => IsCorrespondingProperty(duckProperty, ctp)) .ToArray(); @@ -388,6 +405,5 @@ private static bool IsCorrespondingProperty(PropertyInfo duckProperty, PropertyI // TODO: parameter lists should be compared, too, to properly support indexers. } } - } } diff --git a/tests/Moq.Tests/ProtectedAsMockFixture.cs b/tests/Moq.Tests/ProtectedAsMockFixture.cs index ef518ae67..21da0d2ba 100644 --- a/tests/Moq.Tests/ProtectedAsMockFixture.cs +++ b/tests/Moq.Tests/ProtectedAsMockFixture.cs @@ -130,6 +130,13 @@ public void Setup_can_setup_generic_method() Assert.Equal(3, handledMessages.Count); } + [Fact] + public void Setup_can_automock() + { + this.protectedMock.Setup(m => m.Nested.Method(1)).Returns(123); + Assert.Equal(123, mock.Object.GetNested().Method(1)); + } + [Fact] public void SetupGet_can_setup_readonly_property() { @@ -150,6 +157,26 @@ public void SetupGet_can_setup_readwrite_property() Assert.Equal(42, actual); } + [Fact] + public void SetUpGet_can_automock() + { + this.protectedMock.SetupGet(m => m.Nested.Value).Returns(42); + + var actual = mock.Object.GetNested().Value; + + Assert.Equal(42, actual); + } + + [Fact] + public void SetupGet_can_setup_virtual_property() + { + this.protectedMock.SetupGet(m => m.VirtualGet).Returns(42); + + var actual = mock.Object.GetVirtual(); + + Assert.Equal(42, actual); + } + [Fact] public void SetupProperty_can_setup_readwrite_property() { @@ -259,7 +286,15 @@ public void SetUpSet_Should_Work_With_Indexers() mock.Object.SetMultipleIndexer(1, "Ok", 999); Assert.Throws(() => mock.Object.SetMultipleIndexer(1, "Bad", 999)); + } + + [Fact] + public void SetupSet_can_setup_virtual_property() + { + this.protectedMock.SetupSet(m => m.VirtualSet = 999).Throws(new ExpectedException()); + mock.Object.SetVirtual(123); + Assert.Throws(() => mock.Object.SetVirtual(999)); } [Fact] @@ -293,7 +328,6 @@ void VerifySet(Times? times = null,string failMessage = null) var mockException = Assert.Throws(() => VerifySet(Times.AtMostOnce(),"custom fail message")); Assert.StartsWith("custom fail message", mockException.Message); - } [Fact] @@ -384,12 +418,51 @@ public void VerifyGet_includes_failure_message_in_exception() public interface INested { int Value { get; set; } + int Method(int value); } + public abstract class Foo { protected Foo() { } + private int _virtualSet; + public virtual int VirtualSet + { + get + { + return _virtualSet; + } + protected set + { + _virtualSet = value; + } + + } + + public void SetVirtual(int value) + { + VirtualSet = value; + } + + private int _virtualGet; + public virtual int VirtualGet + { + protected get + { + return _virtualGet; + } + set + { + _virtualGet = value; + } + + } + + public int GetVirtual() + { + return VirtualGet; + } public int ReadOnlyProperty => this.ReadOnlyPropertyImpl; @@ -437,10 +510,17 @@ public void SetMultipleIndexer(int index, string sIndex, int value) { this[index, sIndex] = value; } + + public int GetMultipleIndexer(int index, string sIndex) + { + return this[index, sIndex]; + } } public interface Fooish { + int VirtualGet { get; set; } + int VirtualSet { get; set; } int ReadOnlyPropertyImpl { get; } int ReadWritePropertyImpl { get; set; } int NonExistentProperty { get; } From bd90bc0284aed015d7f598e8a98c1bb24cfbde70 Mon Sep 17 00:00:00 2001 From: Tony Hallett Date: Tue, 20 Jul 2021 13:40:45 +0100 Subject: [PATCH 3/5] revert whitespace --- src/Moq/Protected/ProtectedAsMock.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Moq/Protected/ProtectedAsMock.cs b/src/Moq/Protected/ProtectedAsMock.cs index b82718ec9..a39df1d9e 100644 --- a/src/Moq/Protected/ProtectedAsMock.cs +++ b/src/Moq/Protected/ProtectedAsMock.cs @@ -246,7 +246,7 @@ protected override Expression VisitMethodCall(MethodCallExpression node) { var targetParameter = Expression.Parameter(this.targetType, left.Name); return Expression.Call(targetParameter, FindCorrespondingMethod(node.Method), node.Arguments); - } + } else { return base.VisitMethodCall(node); From be2bc09a854707b70bca3275c4b6aefff6bb3d85 Mon Sep 17 00:00:00 2001 From: Tony Hallett Date: Tue, 20 Jul 2021 13:41:25 +0100 Subject: [PATCH 4/5] revert unused code --- tests/Moq.Tests/ProtectedAsMockFixture.cs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/tests/Moq.Tests/ProtectedAsMockFixture.cs b/tests/Moq.Tests/ProtectedAsMockFixture.cs index 21da0d2ba..67b00711b 100644 --- a/tests/Moq.Tests/ProtectedAsMockFixture.cs +++ b/tests/Moq.Tests/ProtectedAsMockFixture.cs @@ -510,11 +510,6 @@ public void SetMultipleIndexer(int index, string sIndex, int value) { this[index, sIndex] = value; } - - public int GetMultipleIndexer(int index, string sIndex) - { - return this[index, sIndex]; - } } public interface Fooish From 1ede937ebab95348f6db45b9f6a8fc45099990fc Mon Sep 17 00:00:00 2001 From: Tony Hallett Date: Tue, 20 Jul 2021 14:26:05 +0100 Subject: [PATCH 5/5] remove unused method --- tests/Moq.Tests/ProtectedAsMockFixture.cs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/tests/Moq.Tests/ProtectedAsMockFixture.cs b/tests/Moq.Tests/ProtectedAsMockFixture.cs index 0d63616ea..8fdc97891 100644 --- a/tests/Moq.Tests/ProtectedAsMockFixture.cs +++ b/tests/Moq.Tests/ProtectedAsMockFixture.cs @@ -474,12 +474,7 @@ public void SetMultipleIndexer(int index, string sIndex, int value) this[index, sIndex] = value; } - public int GetMultipleIndexer(int index, string sIndex) - { - return this[index, sIndex]; - } - - private int _virtualSet; + private int _virtualSet; public virtual int VirtualSet { get