Skip to content

Commit

Permalink
Add dedicated setup type for SetupAllProperties
Browse files Browse the repository at this point in the history
  • Loading branch information
stakx committed Feb 14, 2022
1 parent 5db2a42 commit a3e41a4
Show file tree
Hide file tree
Showing 5 changed files with 115 additions and 48 deletions.
2 changes: 1 addition & 1 deletion src/Moq/Mock.cs
Original file line number Diff line number Diff line change
Expand Up @@ -611,7 +611,7 @@ private static TSetup SetupRecursive<TSetup>(Mock mock, LambdaExpression origina

internal static void SetupAllProperties(Mock mock)
{
// TODO: implement!
mock.MutableSetups.Add(new StubbedPropertiesSetup(mock));
}

#endregion
Expand Down
4 changes: 4 additions & 0 deletions src/Moq/MockDefaultValueProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
110 changes: 110 additions & 0 deletions src/Moq/StubbedPropertiesSetup.cs
Original file line number Diff line number Diff line change
@@ -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<string, object> values;
private readonly DefaultValueProvider defaultValueProvider;

public StubbedPropertiesSetup(Mock mock, DefaultValueProvider defaultValueProvider = null)
: base(originalExpression: null, mock, new PropertyAccessorExpectation(mock))
{
this.values = new Dictionary<string, object>();
this.defaultValueProvider = defaultValueProvider ?? mock.DefaultValueProvider;

this.MarkAsVerifiable();
}

public DefaultValueProvider DefaultValueProvider => this.defaultValueProvider;

public override IEnumerable<Mock> 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<object>.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();
}
}
}
}
26 changes: 0 additions & 26 deletions tests/Moq.Tests/SetupFixture.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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<IX>(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()
{
Expand Down Expand Up @@ -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<Func<IX, string>> originalExpressionLeftHandSide = m => m.Inner[1].ToString();
Expression<Func<IX, bool>> mockSpecification =
Expression.Lambda<Func<IX, bool>>(
Expression.MakeBinary(
ExpressionType.Equal,
originalExpressionLeftHandSide.Body,
Expression.Constant("")),
originalExpressionLeftHandSide.Parameters);
var mockObject = Mock.Of<IX>(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()
{
Expand Down
21 changes: 0 additions & 21 deletions tests/Moq.Tests/SetupsFixture.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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<object>();
var mock = Mock.Get(mockObject);
Assert.Empty(mock.Setups);
}

[Fact]
public void Setup_adds_one_setup_with_same_expression_to_Setups()
{
Expand All @@ -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<Func<object, bool>> mockSpecification = m => m.ToString() == default(string);
Expression<Func<object, string>> setupExpression = m => m.ToString();

var mockObject = Mock.Of<object>(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()
{
Expand Down

0 comments on commit a3e41a4

Please sign in to comment.