Skip to content

Setups can now be reused in other setups as well as the Randomizer class #53

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

Merged
merged 1 commit into from
Nov 14, 2015
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions ObjectFiller.Test/ObjectFiller.Test.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@
<Compile Include="SaveFillerSetupTest.cs" />
<Compile Include="EmailAddressesPluginTest.cs" />
<Compile Include="TestPoco\TestEnum.cs" />
<Compile Include="SetupTests.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\ObjectFiller\ObjectFiller.csproj">
Expand Down
81 changes: 81 additions & 0 deletions ObjectFiller.Test/SetupTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace ObjectFiller.Test
{
using Tynamix.ObjectFiller;

[TestClass]
public class SetupTests
{
public class Parent
{
public Child Child { get; set; }
}

public class Child
{
public int Value { get; set; }
}

[TestMethod]
public void RandomizerCreatesObjectsBasedOnPreviouseSetups()
{
int givenValue = Randomizer<int>.Create();

var childFiller = new Filler<Child>();
var childSetup = childFiller.Setup().OnProperty(x => x.Value).Use(givenValue).Result;

var child = Randomizer<Child>.Create(childSetup);
Assert.AreEqual(givenValue, child.Value);
}

[TestMethod]
public void UseSetupsAgainForPropertyConfigurations()
{
int givenValue = Randomizer<int>.Create();

var childFiller = new Filler<Child>();
var childSetup = childFiller.Setup().OnProperty(x => x.Value).Use(givenValue).Result;

var parentFiller = new Filler<Parent>();
parentFiller.Setup().OnProperty(x => x.Child).Use(childSetup);

var parent = parentFiller.Create();
Assert.AreEqual(givenValue, parent.Child.Value);
}

[TestMethod]
public void UseSetupsAgainForTypeConfigurations()
{
int givenValue = Randomizer<int>.Create();

var childFiller = new Filler<Child>();
var childSetup = childFiller.Setup().OnProperty(x => x.Value).Use(givenValue).Result;

var parentFiller = new Filler<Parent>();
parentFiller.Setup().OnType<Child>().Use(childSetup);

var parent = parentFiller.Create();
Assert.AreEqual(givenValue, parent.Child.Value);
}

[TestMethod]
public void UseSetupsAgain()
{
int givenValue = Randomizer<int>.Create();

var firstChildFiller = new Filler<Child>();
var childSetup = firstChildFiller.Setup().OnProperty(x => x.Value).Use(givenValue).Result;

var secondChildFiller = new Filler<Child>();
secondChildFiller.Setup(childSetup);

var child = secondChildFiller.Create();

Assert.AreEqual(givenValue, child.Value);
}


}
}
78 changes: 52 additions & 26 deletions ObjectFiller/Randomizer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,32 +39,7 @@ static Randomizer()
/// <returns>A value of type <see cref="T"/></returns>
public static T Create()
{
Type targetType = typeof(T);
if (!Setup.TypeToRandomFunc.ContainsKey(targetType))
{
if (targetType.IsClass)
{
var fillerType = typeof(Filler<>).MakeGenericType(typeof(T));
var objectFiller = Activator.CreateInstance(fillerType);
var methodInfo = objectFiller.GetType().GetMethods().Single(x => !x.GetParameters().Any() && x.Name == "Create");

try
{
return (T)methodInfo.Invoke(objectFiller, null);
}
catch (Exception ex)
{
throw new InvalidOperationException(
"The type " + typeof(T).FullName + " needs additional information to get created. "
+ "Please use the Filler class and call \"Setup\" to create a setup for that type. See Innerexception for more details.",
ex);
}
}

return default(T);
}

return (T)Setup.TypeToRandomFunc[typeof(T)]();
return Create(null as FillerSetup);
}

/// <summary>
Expand Down Expand Up @@ -93,5 +68,56 @@ public static T Create(IRandomizerPlugin<T> randomizerPlugin)
Setup.TypeToRandomFunc[typeof(T)] = () => randomizerPlugin.GetValue();
return randomizerPlugin.GetValue();
}

/// <summary>
/// Creates a factory method for the given type.
/// </summary>
/// <param name="setup">The setup which is used for the type.</param>
/// <returns>A function with which the given type can be instantiated.</returns>
internal static Func<T> CreateFactoryMethod(FillerSetup setup)
{
Type targetType = typeof(T);
if (!Setup.TypeToRandomFunc.ContainsKey(targetType))
{
if (targetType.IsClass)
{
var fillerType = typeof(Filler<>).MakeGenericType(typeof(T));
var objectFiller = Activator.CreateInstance(fillerType);

if (setup != null)
{
var setupMethod = objectFiller.GetType().GetMethods().Single(x => x.Name == "Setup" && x.GetParameters().Any());
setupMethod.Invoke(objectFiller, new[] { setup });
}

var createMethod = objectFiller.GetType().GetMethods().Single(x => !x.GetParameters().Any() && x.Name == "Create");
return () => (T)createMethod.Invoke(objectFiller, null);
}

return () => default(T);
}

return () => (T)Setup.TypeToRandomFunc[typeof(T)]();
}

public static T Create(FillerSetup setup)
{
var creationMethod = CreateFactoryMethod(setup);

T result;
try
{
result = creationMethod();
}
catch (Exception ex)
{
throw new InvalidOperationException(
"The type " + typeof(T).FullName + " needs additional information to get created. "
+ "Please use the Filler class and call \"Setup\" to create a setup for that type. See Innerexception for more details.",
ex);
}

return result;
}
}
}
15 changes: 15 additions & 0 deletions ObjectFiller/Setup/FluentPropertyApi.cs
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,21 @@ public FluentFillerApi<TTargetObject> Use(Func<TTargetType> randomizerFunc)
return this.callback;
}

/// <summary>
/// Defines which <see cref="FillerSetup"/> is used to generate a value for the given <see cref="TTargetType"/>
/// </summary>
/// <param name="setup">The setup which is used for configuration.</param>
public FluentFillerApi<TTargetObject> Use(FillerSetup setup)
{
foreach (PropertyInfo propertyInfo in this.affectedProperties)
{
var factoryMethod = Randomizer<TTargetType>.CreateFactoryMethod(setup);
this.setupManager.GetFor<TTargetObject>().PropertyToRandomFunc[propertyInfo] = () => factoryMethod();
}

return this.callback;
}

/// <summary>
/// Defines which implementation of the <see cref="IRandomizerPlugin{T}"/> interface will be used to generate a value for the given <see cref="TTargetType"/>
/// </summary>
Expand Down
16 changes: 15 additions & 1 deletion ObjectFiller/Setup/FluentTypeApi.cs
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,19 @@ public FluentFillerApi<TTargetObject> Use(IEnumerable<TTargetType> enumerable)
return this.Use(new EnumeratorPlugin<TTargetType>(enumerable));
}

/// <summary>
/// With this method you can use a previously defined setup for specific types.
/// </summary>
/// <param name="setup">The setup for the type.</param>
/// <returns>Main FluentFiller API</returns>
public FluentFillerApi<TTargetObject> Use(FillerSetup setup)
{
var factoryMethod = Randomizer<TTargetType>.CreateFactoryMethod(setup);
this.setupManager.GetFor<TTargetObject>().TypeToRandomFunc[typeof(TTargetType)] = () => factoryMethod();

return this.callback;
}

/// <summary>
/// Ignores the entity for which the fluent setup is made (Type, Property)
/// </summary>
Expand All @@ -108,7 +121,8 @@ public FluentFillerApi<TTargetObject> IgnoreIt()
public FluentFillerApi<TTargetObject> CreateInstanceOf<TImplementation>()
where TImplementation : class, TTargetType
{
this.setupManager.GetFor<TTargetObject>().InterfaceToImplementation.Add(typeof(TTargetType), typeof(TImplementation));
this.setupManager.GetFor<TTargetObject>()
.InterfaceToImplementation.Add(typeof(TTargetType), typeof(TImplementation));

return this.callback;
}
Expand Down