From a3e41a40aa92ecd41356da5a0a3ea8d1f72fa65b Mon Sep 17 00:00:00 2001 From: Dominique Schuppli Date: Sat, 12 Feb 2022 22:25:15 +0100 Subject: [PATCH] Add dedicated setup type for `SetupAllProperties` --- src/Moq/Mock.cs | 2 +- src/Moq/MockDefaultValueProvider.cs | 4 + src/Moq/StubbedPropertiesSetup.cs | 110 ++++++++++++++++++++++++++++ tests/Moq.Tests/SetupFixture.cs | 26 ------- tests/Moq.Tests/SetupsFixture.cs | 21 ------ 5 files changed, 115 insertions(+), 48 deletions(-) create mode 100644 src/Moq/StubbedPropertiesSetup.cs diff --git a/src/Moq/Mock.cs b/src/Moq/Mock.cs index 9f90d2ebf..0a9aa6368 100644 --- a/src/Moq/Mock.cs +++ b/src/Moq/Mock.cs @@ -611,7 +611,7 @@ private static TSetup SetupRecursive(Mock mock, LambdaExpression origina internal static void SetupAllProperties(Mock mock) { - // TODO: implement! + mock.MutableSetups.Add(new StubbedPropertiesSetup(mock)); } #endregion diff --git a/src/Moq/MockDefaultValueProvider.cs b/src/Moq/MockDefaultValueProvider.cs index 7ca0982a6..603c4bb44 100644 --- a/src/Moq/MockDefaultValueProvider.cs +++ b/src/Moq/MockDefaultValueProvider.cs @@ -36,6 +36,10 @@ protected override object GetFallbackDefaultValue(Type type, Mock mock) var mockType = typeof(Mock<>).MakeGenericType(type); Mock newMock = (Mock)Activator.CreateInstance(mockType, mock.Behavior); newMock.DefaultValueProvider = mock.DefaultValueProvider; + if (mock.MutableSetups.FindLast(s => s is StubbedPropertiesSetup) is StubbedPropertiesSetup sts) + { + newMock.MutableSetups.Add(new StubbedPropertiesSetup(newMock, sts.DefaultValueProvider)); + } if(!type.IsDelegateType()) { newMock.CallBase = mock.CallBase; diff --git a/src/Moq/StubbedPropertiesSetup.cs b/src/Moq/StubbedPropertiesSetup.cs new file mode 100644 index 000000000..6160f5dc4 --- /dev/null +++ b/src/Moq/StubbedPropertiesSetup.cs @@ -0,0 +1,110 @@ +// Copyright (c) 2007, Clarius Consulting, Manas Technology Solutions, InSTEDD, and Contributors. +// All rights reserved. Licensed under the BSD 3-Clause License; see License.txt. + +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq.Expressions; + +using E = System.Linq.Expressions.Expression; + +namespace Moq +{ + internal sealed class StubbedPropertiesSetup : Setup + { + private readonly Dictionary values; + private readonly DefaultValueProvider defaultValueProvider; + + public StubbedPropertiesSetup(Mock mock, DefaultValueProvider defaultValueProvider = null) + : base(originalExpression: null, mock, new PropertyAccessorExpectation(mock)) + { + this.values = new Dictionary(); + this.defaultValueProvider = defaultValueProvider ?? mock.DefaultValueProvider; + + this.MarkAsVerifiable(); + } + + public DefaultValueProvider DefaultValueProvider => this.defaultValueProvider; + + public override IEnumerable InnerMocks + { + get + { + foreach (var value in this.values.Values) + { + var innerMock = TryGetInnerMockFrom(value); + if (innerMock != null) + { + yield return innerMock; + } + } + } + } + + public void SetProperty(string propertyName, object value) + { + this.values[propertyName] = value; + } + + protected override void ExecuteCore(Invocation invocation) + { + if (invocation.Method.ReturnType == typeof(void)) + { + Debug.Assert(invocation.Method.IsSetAccessor()); + Debug.Assert(invocation.Arguments.Length == 1); + + var propertyName = invocation.Method.Name.Substring(4); + this.values[propertyName] = invocation.Arguments[0]; + } + else + { + Debug.Assert(invocation.Method.IsGetAccessor()); + + var propertyName = invocation.Method.Name.Substring(4); + if (!this.values.TryGetValue(propertyName, out var value)) + { + value = this.values[propertyName] = this.Mock.GetDefaultValue(invocation.Method, out _, this.defaultValueProvider); + } + + invocation.ReturnValue = value; + } + } + + protected override void VerifySelf() + { + } + + private sealed class PropertyAccessorExpectation : Expectation + { + private readonly LambdaExpression expression; + + public PropertyAccessorExpectation(Mock mock) + { + Debug.Assert(mock != null); + + var mockType = mock.GetType(); + var mockedType = mockType.GetGenericArguments()[0]; + var mockGetMethod = Mock.GetMethod.MakeGenericMethod(mockedType); + var setupAllPropertiesMethod = mockType.GetMethod(nameof(Mock.SetupAllProperties)); + var mockParam = E.Parameter(mockedType, "m"); + this.expression = E.Lambda(E.Call(E.Call(mockGetMethod, mockParam), setupAllPropertiesMethod), mockParam); + } + + public override LambdaExpression Expression => this.expression; + + public override bool Equals(Expectation other) + { + return other is PropertyAccessorExpectation pae && ExpressionComparer.Default.Equals(this.expression, pae.expression); + } + + public override int GetHashCode() + { + return typeof(PropertyAccessorExpectation).GetHashCode(); + } + + public override bool IsMatch(Invocation invocation) + { + return invocation.Method.IsPropertyAccessor(); + } + } + } +} diff --git a/tests/Moq.Tests/SetupFixture.cs b/tests/Moq.Tests/SetupFixture.cs index 79279d7d3..ad68bad72 100644 --- a/tests/Moq.Tests/SetupFixture.cs +++ b/tests/Moq.Tests/SetupFixture.cs @@ -139,15 +139,6 @@ public void OriginalExpression_equal_to_Expression_for_simple_method_call() Assert.Equal(setup.Expression, setup.OriginalExpression, ExpressionComparer.Default); } - [Fact] - public void OriginalExpression_equal_to_Expression_for_simple_expression_in_Mock_Of() - { - var mockObject = Mock.Of(m => m.Property == null); - var setup = Mock.Get(mockObject).Setups.First(); - - Assert.Equal(setup.Expression, setup.OriginalExpression, ExpressionComparer.Default); - } - [Fact] public void OriginalExpression_returns_expression_different_from_Expression_for_multi_dot_expression() { @@ -178,23 +169,6 @@ public void OriginalExpression_returns_whole_multi_dot_expression() Assert.Equal(originalExpression, setup.OriginalExpression, ExpressionComparer.Default); } - [Fact] - public void OriginalExpression_returns_only_left_hand_side_of_expression_in_Mock_Of() - { - Expression> originalExpressionLeftHandSide = m => m.Inner[1].ToString(); - Expression> mockSpecification = - Expression.Lambda>( - Expression.MakeBinary( - ExpressionType.Equal, - originalExpressionLeftHandSide.Body, - Expression.Constant("")), - originalExpressionLeftHandSide.Parameters); - var mockObject = Mock.Of(mockSpecification); - var setup = Mock.Get(mockObject).Setups.First(); - - Assert.Equal(originalExpressionLeftHandSide, setup.OriginalExpression, ExpressionComparer.Default); - } - [Fact] public void OriginalExpression_same_for_all_partial_setups_resulting_from_it() { diff --git a/tests/Moq.Tests/SetupsFixture.cs b/tests/Moq.Tests/SetupsFixture.cs index 5641a25c9..817d797a8 100644 --- a/tests/Moq.Tests/SetupsFixture.cs +++ b/tests/Moq.Tests/SetupsFixture.cs @@ -18,14 +18,6 @@ public void Mock_made_with_new_operator_initially_has_no_setups() Assert.Empty(mock.Setups); } - [Fact] - public void Mock_made_with_Mock_Of_without_an_expression_initially_has_no_setups() - { - var mockObject = Mock.Of(); - var mock = Mock.Get(mockObject); - Assert.Empty(mock.Setups); - } - [Fact] public void Setup_adds_one_setup_with_same_expression_to_Setups() { @@ -38,19 +30,6 @@ public void Setup_adds_one_setup_with_same_expression_to_Setups() Assert.Equal(setupExpression, setup.Expression, ExpressionComparer.Default); } - [Fact] - public void Mock_Of_with_expression_for_a_single_member_adds_one_setup_with_same_but_only_partial_expression_to_Setups() - { - Expression> mockSpecification = m => m.ToString() == default(string); - Expression> setupExpression = m => m.ToString(); - - var mockObject = Mock.Of(mockSpecification); - var mock = Mock.Get(mockObject); - - var setup = Assert.Single(mock.Setups); - Assert.Equal(setupExpression, setup.Expression, ExpressionComparer.Default); - } - [Fact] public void Mock_Reset_results_in_empty_Setups() {