Skip to content

Commit

Permalink
Proposed fix for #1183 - creating multiple regex within short time mi…
Browse files Browse the repository at this point in the history
…ght yield identical stringsr #1183 (+1 squashed commits)

Squashed commits:

[e8e3387] Proposed fix for #1183 - creating multiple regex within short time might yield identical strings
  • Loading branch information
Magnus Mikkelsen authored and MagnusMikkelsen committed Jun 30, 2020
1 parent 0ab5d0f commit 02f6b7c
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 3 deletions.
18 changes: 15 additions & 3 deletions Src/AutoFixture/RegularExpressionGenerator.cs
Expand Up @@ -10,6 +10,16 @@ namespace AutoFixture
/// </summary>
public class RegularExpressionGenerator : ISpecimenBuilder
{
private readonly Random random;

/// <summary>
/// Initializes a new instance of the <see cref="RegularExpressionGenerator"/> class.
/// </summary>
public RegularExpressionGenerator()
{
this.random = new Random();
}

/// <summary>
/// Creates a string that is guaranteed to match a RegularExpressionRequest.
/// </summary>
Expand All @@ -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;
Expand Down
25 changes: 25 additions & 0 deletions Src/AutoFixtureUnitTest/RegularExpressionGeneratorTest.cs
Expand Up @@ -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]+\])?")]
Expand Down

0 comments on commit 02f6b7c

Please sign in to comment.