Skip to content

Commit

Permalink
Merge pull request #36 from Quantumplation/SetLambda
Browse files Browse the repository at this point in the history
Adds a Set overload which takes a lambda factory method
  • Loading branch information
robdmoore committed May 21, 2015
2 parents 1c8fe7b + 1d1d47d commit 67df72a
Show file tree
Hide file tree
Showing 5 changed files with 81 additions and 28 deletions.
11 changes: 11 additions & 0 deletions CONTRIBUTOR_GUIDELINES.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
Contributor Guidelines
======================

Hi! Thank you for your interest in contributing to this open source library!
We ask that you follow the following style guidelines when submitting pull
requests, to keep the code consistent and maintainable.

- Do not put an if clause and it's statement on the same line: separate them
with a new-line and indent accordingly.

(This file will be expanded as more guidelines are established by the maintainer)
29 changes: 28 additions & 1 deletion TestStack.Dossier.Tests/BuildTests.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Shouldly;
using System.Collections.Generic;
using Shouldly;
using TestStack.Dossier.Tests.TestHelpers.Builders;
using TestStack.Dossier.Tests.TestHelpers.Objects.Entities;
using Xunit;
Expand Down Expand Up @@ -47,6 +48,32 @@ public void GivenBuilder_WhenCallingSetExplicitly_ShouldOverrideValues()
customer.YearJoined.ShouldBe(2014);
}

[Fact]
public void GivenBuilder_WhenCallingSetWithLambda_ShouldInvokeEachTime()
{
int counter = 2014;
var builder = new CustomerBuilder()
.Set(x => x.FirstName, "Pi")
.Set(x => x.LastName, "Lanningham")
.Set(x => x.YearJoined, () => counter++);

var customerA = builder.Build();
var customerB = builder.Build();

customerA.YearJoined.ShouldBe(2014);
customerB.YearJoined.ShouldBe(2015);

List<Customer> customerList = CustomerBuilder.CreateListOfSize(10)
.All()
.Set(x => x.YearJoined, () => counter++);
int newCounter = 2016;
foreach (var c in customerList)
{
c.YearJoined.ShouldBe(newCounter++);
}

}

[Fact]
public void GivenBasicBuilder_WhenCallingBuildImplicitly_ThenReturnAnObject()
{
Expand Down
25 changes: 13 additions & 12 deletions TestStack.Dossier.Tests/ProxyBuilderTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ class ProxyBuilderTests
[Fact]
public void GivenClassToProxyWithNoProperties_WhenBuildingProxy_ReturnAClassWithNoReturnsValuesSet()
{
var proxyBuilder = new ProxyBuilder<Customer>(new Dictionary<string, object>());
var proxyBuilder = new ProxyBuilder<Customer>(new Dictionary<string, Func<object>>());

var proxy = proxyBuilder.Build();

Expand All @@ -24,33 +24,34 @@ public void GivenClassToProxyWithNoProperties_WhenBuildingProxy_ReturnAClassWith
[Fact]
public void GivenClassToProxyWithNoProperties_WhenBuildingProxy_ReturnAnNSubstituteProxyOfThatClass()
{
var proxyBuilder = new ProxyBuilder<Customer>(new Dictionary<string, object>());
var proxyBuilder = new ProxyBuilder<Customer>(new Dictionary<string, Func<object>>());

var proxy = proxyBuilder.Build();

proxy.DidNotReceive().CustomerForHowManyYears(Arg.Any<DateTime>());
}

[Fact]
public void GivenClassToProxyWithSinglePropertyValue_WhenBuildingProxy_ReturnAClassWithReturnValueSet()
public void GivenClassToProxyWithSinglePropertyValue_WhenBuildingProxy_ReturnAClassWithReturnValueSetFromFunction()
{
var proxyBuilder = new ProxyBuilder<Customer>(new Dictionary<string, object> {{"FirstName", "FirstName"}});
int nonce = new Random().Next(0, 100);
var proxyBuilder = new ProxyBuilder<Customer>(new Dictionary<string, Func<object>> {{"FirstName", () => "FirstName" + nonce}});

var proxy = proxyBuilder.Build();

proxy.FirstName.ShouldBe("FirstName");
proxy.FirstName.ShouldBe("FirstName" + nonce);
proxy.LastName.ShouldBe(string.Empty);
proxy.YearJoined.ShouldBe(0);
}

[Fact]
public void GivenClassToProxyWithMultiplePropertyValues_WhenBuildingProxy_ReturnAClassWithReturnValueSet()
{
var proxyBuilder = new ProxyBuilder<Customer>(new Dictionary<string, object>
var proxyBuilder = new ProxyBuilder<Customer>(new Dictionary<string, Func<object>>
{
{ "FirstName", "FirstName" },
{ "LastName", "LastName" },
{ "YearJoined", 1 },
{ "FirstName", () => "FirstName" },
{ "LastName", () => "LastName" },
{ "YearJoined", () => 1 },
}
);

Expand All @@ -64,10 +65,10 @@ public void GivenClassToProxyWithMultiplePropertyValues_WhenBuildingProxy_Return
[Fact]
public void GivenClassWithSomeVirtualProperties_WhenBuildingProxy_ThenOnlyVirtualMembersAreProxied()
{
var proxyBuilder = new ProxyBuilder<Company>(new Dictionary<string, object>()
var proxyBuilder = new ProxyBuilder<Company>(new Dictionary<string, Func<object>>()
{
{"Name", "Vandelay Industries"},
{"EmployeeCount", 100}
{"Name", () => "Vandelay Industries"},
{"EmployeeCount", () => 100}
});

var proxy = proxyBuilder.Build();
Expand Down
9 changes: 5 additions & 4 deletions TestStack.Dossier/ProxyBuilder.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using NSubstitute;
Expand All @@ -11,13 +12,13 @@ namespace TestStack.Dossier
/// <typeparam name="T">The type being proxied</typeparam>
public class ProxyBuilder<T> where T : class
{
private readonly Dictionary<string, object> _properties;
private readonly Dictionary<string, Func<object>> _properties;

/// <summary>
/// Create a proxy builder to proxy the given property values for the type {T}.
/// </summary>
/// <param name="properties"></param>
public ProxyBuilder(Dictionary<string, object> properties)
public ProxyBuilder(Dictionary<string, Func<object>> properties)
{
_properties = properties;
}
Expand All @@ -33,7 +34,7 @@ public T Build()
foreach (var property in properties.Where(property => _properties.ContainsKey(property.Name)))
{
if (property.GetGetMethod().IsVirtual)
property.GetValue(proxy, null).Returns(_properties[property.Name]);
property.GetValue(proxy, null).Returns(_properties[property.Name]());
}

return proxy;
Expand Down
35 changes: 24 additions & 11 deletions TestStack.Dossier/TestDataBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ public abstract class TestDataBuilder<TObject, TBuilder>
where TObject : class
where TBuilder : TestDataBuilder<TObject, TBuilder>, new()
{
private readonly Dictionary<string, object> _properties = new Dictionary<string, object>(StringComparer.InvariantCultureIgnoreCase);
private readonly Dictionary<string, Func<object>> _properties = new Dictionary<string, Func<object>>();
private ProxyBuilder<TObject> _proxyBuilder;

/// <summary>
Expand Down Expand Up @@ -107,16 +107,30 @@ public TBuilder AsProxy()
/// </summary>
/// <param name="proxy">The proxy object</param>
protected virtual void AlterProxy(TObject proxy) {}

/// <summary>
/// Records the given value for the given property from {TObject} and returns the builder to allow chaining.
/// </summary>
/// <typeparam name="TValue">The type of the property</typeparam>
/// <param name="property">A lambda expression specifying the property to record a value for</param>
/// <param name="value">The builder so that other method calls can be chained</param>
/// <param name="value">The value to set the property to</param>
/// <returns>The builder so that other method calls can be chained</returns>
public virtual TBuilder Set<TValue>(Expression<Func<TObject, TValue>> property, TValue value)
{
_properties[Reflector.GetPropertyNameFor(property)] = value;
_properties[Reflector.GetPropertyNameFor(property)] = () => value;
return this as TBuilder;
}

/// <summary>
/// Records a given value provider for the given property from {TObject} and returns the builder to allow chaining.
/// </summary>
/// <typeparam name="TValue">The type of the property</typeparam>
/// <param name="property">A lambda expression specifying the property to record a value for</param>
/// <param name="factory">A method which produces instances of {TValue} for the property.</param>
/// <returns>The builder so that other method calls can be chained</returns>
public virtual TBuilder Set<TValue>(Expression<Func<TObject, TValue>> property, Func<TValue> factory)
{
_properties[Reflector.GetPropertyNameFor(property)] = () => factory() as object;
return this as TBuilder;
}

Expand All @@ -129,10 +143,7 @@ public virtual TBuilder Set<TValue>(Expression<Func<TObject, TValue>> property,
/// <returns>The recorded value of the property or an anonymous value for it</returns>
public TValue Get<TValue>(Expression<Func<TObject, TValue>> property)
{
if (!Has(property))
return Any.Get(property);

return (TValue)_properties[Reflector.GetPropertyNameFor(property)];
return (TValue)Get(typeof (TValue), Reflector.GetPropertyNameFor(property));
}

/// <summary>
Expand All @@ -144,9 +155,11 @@ public TValue Get<TValue>(Expression<Func<TObject, TValue>> property)
/// <returns></returns>
public object Get(Type type, string propertyName)
{
if (!Has(propertyName))
return Any.Get(type, propertyName);
return _properties[propertyName];
Func<object> factory;
if (_properties.TryGetValue(propertyName, out factory))
return factory();

return Any.Get(type, propertyName);
}

/// <summary>
Expand Down

0 comments on commit 67df72a

Please sign in to comment.