Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make SetupProperty work with recursive expressions again #1241

Merged
merged 3 commits into from Mar 6, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
7 changes: 7 additions & 0 deletions CHANGELOG.md
Expand Up @@ -5,6 +5,13 @@ All notable changes to this project will be documented in this file.
The format is loosely based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/).


## Unreleased

#### Fixed

* Regression: Property stubs not working on sub mock (@aaronburro, #1240)


## 4.17.1 (2022-02-26)

#### Added
Expand Down
24 changes: 24 additions & 0 deletions src/Moq/Mock.cs
Expand Up @@ -609,6 +609,30 @@ internal static SequenceSetup SetupSequence(Mock mock, LambdaExpression expressi
});
}

internal static StubbedPropertySetup SetupProperty(Mock mock, LambdaExpression expression, object initialValue)
{
Guard.NotNull(expression, nameof(expression));

var pi = expression.ToPropertyInfo();

if (!pi.CanRead(out var getter))
{
Guard.CanRead(pi);
}

if (!pi.CanWrite(out var setter))
{
Guard.CanWrite(pi);
}

return Mock.SetupRecursive(mock, expression, (targetMock, _, _) =>
{
var setup = new StubbedPropertySetup(targetMock, expression, getter, setter, initialValue);
targetMock.MutableSetups.Add(setup);
return setup;
});
}

private static TSetup SetupRecursive<TSetup>(Mock mock, LambdaExpression expression, Func<Mock, Expression, MethodExpectation, TSetup> setupLast, bool allowNonOverridableLastProperty = false)
where TSetup : ISetup
{
Expand Down
17 changes: 1 addition & 16 deletions src/Moq/Mock`1.cs
Expand Up @@ -628,22 +628,7 @@ public Mock<T> SetupProperty<TProperty>(Expression<Func<T, TProperty>> property)
/// </example>
public Mock<T> SetupProperty<TProperty>(Expression<Func<T, TProperty>> property, TProperty initialValue)
{
Guard.NotNull(property, nameof(property));

var pi = property.ToPropertyInfo();

if (!pi.CanRead(out var getter))
{
Guard.CanRead(pi);
}

if (!pi.CanWrite(out var setter))
{
Guard.CanWrite(pi);
}

var setup = new StubbedPropertySetup(this, property, getter, setter, initialValue);
this.MutableSetups.Add(setup);
Mock.SetupProperty(this, property, initialValue);
return this;
}

Expand Down
42 changes: 42 additions & 0 deletions tests/Moq.Tests/Regressions/IssueReportsFixture.cs
Expand Up @@ -3740,6 +3740,48 @@ public void Pass_byte_array_indirectly_via_method_call()

#endregion

#region 1240

public class Issue1240
{
public interface IFoo { IBar Bar { get; } }
public interface IBar
{
string Prop1 { get; }
string Prop2 { get; set; }
}

[Fact]
public void Property_on_submock_should_be_stubbed_1()
{
const string prop2 = "Prop2";
var mock = new Mock<IFoo>();

// mock.SetupGet(m => m.Bar.Prop1).Returns("Prop1");
// ^ This line being commented out is the only difference from the test below.
// Its absence would cause a `NullReferenceException` later.

mock.SetupProperty(m => m.Bar.Prop2);
mock.Object.Bar.Prop2 = prop2;
Assert.Equal(prop2, mock.Object.Bar.Prop2);
}

[Fact]
public void Property_on_submock_should_be_stubbed_2()
{
const string prop2 = "Prop2";
var mock = new Mock<IFoo>();

mock.SetupGet(m => m.Bar.Prop1).Returns("Prop1");

mock.SetupProperty(m => m.Bar.Prop2);
mock.Object.Bar.Prop2 = prop2;
Assert.Equal(prop2, mock.Object.Bar.Prop2);
}
}

#endregion

// Old @ Google Code

#region #47
Expand Down