Skip to content

Commit

Permalink
Implements .Clone() on top of flowed localized seed. #100.
Browse files Browse the repository at this point in the history
  • Loading branch information
bchavez committed Nov 4, 2017
1 parent da37d08 commit 4426d3f
Show file tree
Hide file tree
Showing 4 changed files with 128 additions and 22 deletions.
1 change: 1 addition & 0 deletions Source/Bogus.Tests/Bogus.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="CloneTests.cs" />
<Compile Include="DataSetTests\AddressTest.cs" />
<Compile Include="DataSetTests\CardTests.cs" />
<Compile Include="DataSetTests\CommerceTest.cs" />
Expand Down
50 changes: 50 additions & 0 deletions Source/Bogus.Tests/CloneTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
using FluentAssertions;
using Xunit;

namespace Bogus.Tests
{
public class CloneTests : SeededTest
{
[Fact]
public void can_create_a_simple_clone()
{
var orderFaker = new Faker<Examples.Order>()
.UseSeed(88)
.RuleFor(o => o.OrderId, f => f.IndexVariable++)
.RuleFor(o => o.Quantity, f => f.Random.Number(1, 3))
.RuleFor(o => o.Item, f => f.Commerce.Product());

var clone = orderFaker.Clone();

var clonedOrder = clone.Generate();

var rootOrder = orderFaker.Generate();

clonedOrder.ShouldBeEquivalentTo(rootOrder);
}

[Fact]
public void clone_has_different_rules()
{
var rootFaker = new Faker<Examples.Order>()
.UseSeed(88)
.RuleFor(o => o.OrderId, f => f.IndexVariable++)
.RuleFor(o => o.Quantity, f => f.Random.Number(1, 3))
.RuleFor(o => o.Item, f => f.Commerce.Product());

var cloneFaker = rootFaker.Clone()
.RuleFor(o => o.Quantity, f => f.Random.Number(4, 6));

var rootOrder = rootFaker.Generate();
var clonedOrder = cloneFaker.Generate();

rootOrder.Quantity.Should()
.BeGreaterOrEqualTo(1).And
.BeLessOrEqualTo(3);

clonedOrder.Quantity.Should()
.BeGreaterOrEqualTo(4).And
.BeLessOrEqualTo(6);
}
}
}
41 changes: 21 additions & 20 deletions Source/Bogus.Tests/GitHubIssues/Issue100.cs
Original file line number Diff line number Diff line change
Expand Up @@ -147,26 +147,27 @@ public void complex_faker_t_test()
CheckSequence(items);
}

//[Fact]
//public void parallel_determinism()
//{
// var orderFaker = new Faker<Examples.Order>()
// .RuleFor(o => o.OrderId, f => f.IndexVariable++)
// .RuleFor(o => o.Quantity, f => f.Random.Number(1, 3))
// .RuleFor(o => o.Item, f => f.Commerce.Product());

// var orders = ParallelEnumerable.Range(1, 5)
// .Select(threadId =>
// orderFaker
// .UseSeed(88)
// .Generate(4).ToArray()
// ).ToArray();

// foreach( var orderOfFour in orders )
// {
// CheckSequence(orderOfFour);
// }
//}
[Fact]
public void parallel_determinism()
{
var orderFaker = new Faker<Examples.Order>()
.RuleFor(o => o.OrderId, f => f.IndexVariable++)
.RuleFor(o => o.Quantity, f => f.Random.Number(1, 3))
.RuleFor(o => o.Item, f => f.Commerce.Product());

var orders = ParallelEnumerable.Range(1, 5)
.Select(threadId =>
orderFaker
.Clone()
.UseSeed(88)
.Generate(4).ToArray()
).ToArray();

foreach( var orderOfFour in orders )
{
CheckSequence(orderOfFour);
}
}

private void CheckSequence(Examples.Order[] items)
{
Expand Down
58 changes: 56 additions & 2 deletions Source/Bogus/Faker[T].cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,62 @@ public class Faker<T> : ILocaleAware, IRuleSet<T> where T : class
protected internal Dictionary<string, bool> StrictModes = new Dictionary<string, bool>();
protected internal bool? IsValid;
protected internal string currentRuleSet = Default;
protected internal int? localSeed; // if null, the global Randomizer.Seed is used.
#pragma warning restore 1591

/// <summary>
/// Clones the internal state of a Faker[T] into a new Faker[T] so that
/// both are isolated from each other. The clone will have internal state
/// reset as if .Generate() was never
/// </summary>
public Faker<T> Clone()
{
var clone = new Faker<T>(this.Locale, this.binder);

//copy internal state.
//strict modes.
foreach( var root in this.StrictModes )
{
clone.StrictModes.Add(root.Key, root.Value);
}

//ignores
foreach( var root in this.Ignores )
{
foreach( var str in root.Value )
{
clone.Ignores.Add(root.Key, str);
}
}

//create actions
foreach( var root in this.CreateActions )
{
clone.CreateActions[root.Key] = root.Value;
}
//finalize actions
foreach( var root in this.FinalizeActions )
{
clone.FinalizeActions.Add(root.Key, root.Value);
}

//actions
foreach( var root in this.Actions )
{
foreach( var kv in root.Value )
{
clone.Actions.Add(root.Key, kv.Key, kv.Value);
}
}

if( localSeed.HasValue )
{
clone.UseSeed(localSeed.Value);
}

return clone;
}

/// <summary>
/// The current locale.
/// </summary>
Expand Down Expand Up @@ -68,8 +122,8 @@ public Faker(string locale = "en", IBinder binder = null)
/// <para name="seed">The seed value to use within this Faker[T] instance.</para>
public virtual Faker<T> UseSeed(int seed)
{
var r = new Randomizer(seed);
this.FakerHub.Random = r;
this.localSeed = seed;
this.FakerHub.Random = new Randomizer(seed);
return this;
}

Expand Down

0 comments on commit 4426d3f

Please sign in to comment.