diff --git a/Src/AutoFixture/RegularExpressionGenerator.cs b/Src/AutoFixture/RegularExpressionGenerator.cs
index 31346f9f9..6cbdf320a 100644
--- a/Src/AutoFixture/RegularExpressionGenerator.cs
+++ b/Src/AutoFixture/RegularExpressionGenerator.cs
@@ -10,6 +10,16 @@ namespace AutoFixture
///
public class RegularExpressionGenerator : ISpecimenBuilder
{
+ private readonly Random random;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public RegularExpressionGenerator()
+ {
+ this.random = new Random();
+ }
+
///
/// Creates a string that is guaranteed to match a RegularExpressionRequest.
///
@@ -28,16 +38,18 @@ public object Create(object request, ISpecimenContext context)
return new NoSpecimen();
}
- return GenerateRegularExpression(regularExpressionRequest);
+ return this.GenerateRegularExpression(regularExpressionRequest);
}
- private static object GenerateRegularExpression(RegularExpressionRequest request)
+ private object GenerateRegularExpression(RegularExpressionRequest request)
{
string pattern = request.Pattern;
try
{
- string regex = new Xeger(pattern).Generate();
+ // Use the Xeger constructor overload that that takes an instance of Random.
+ // Otherwise identically strings can be generated, if regex are generated within short time.
+ string regex = new Xeger(pattern, this.random).Generate();
if (Regex.IsMatch(regex, pattern))
{
return regex;
diff --git a/Src/AutoFixtureUnitTest/RegularExpressionGeneratorTest.cs b/Src/AutoFixtureUnitTest/RegularExpressionGeneratorTest.cs
index 570461564..2eff00d8c 100644
--- a/Src/AutoFixtureUnitTest/RegularExpressionGeneratorTest.cs
+++ b/Src/AutoFixtureUnitTest/RegularExpressionGeneratorTest.cs
@@ -103,6 +103,31 @@ public void CreateWithRegularExpressionRequestReturnsCorrectResult(string patter
Assert.True(Regex.IsMatch(result.ToString(), pattern), string.Format("result: {0}", result));
}
+ [Theory]
+ [InlineData(@"^[A-Z]{27}$")]
+ public void CreateMultipleWithRegularExpressionRequestReturnsDifferentResults(string pattern)
+ {
+ // This test exposes an issue with Xeger/Random.
+ // Xeger(pattern) internally creates an instance of Random with the default seed.
+ // This means that the RegularExpressionGenerator might create identical strings
+ // if called multiple times within a short time.
+
+ // Arrange
+ var sut = new RegularExpressionGenerator();
+ var request = new RegularExpressionRequest(pattern);
+ var dummyContext = new DelegatingSpecimenContext();
+
+ // Repeat a few times - because the issue seen comes from Random class using tickcount as seed.
+ for (int i = 0; i < 10; i++)
+ {
+ var result1 = sut.Create(request, dummyContext);
+ var result2 = sut.Create(request, dummyContext);
+
+ // Assert
+ Assert.NotEqual(result1, result2);
+ }
+ }
+
[Theory]
[InlineData("[")]
[InlineData(@"(?\[Test\]|\[Foo\]|\[Bar\])?(?:-)?(?\[[()a-zA-Z0-9_\s]+\])?(?:-)?(?\[[a-zA-Z0-9_\s]+\])?(?:-)?(?\[[a-zA-Z0-9_\s]+\])?(?:-)?(?\[[a-zA-Z0-9_\s]+\])?")]