Skip to content

Commit

Permalink
Added a new overload to MatchRegex() to assert on the number of reg…
Browse files Browse the repository at this point in the history
…ex matches (#1869)
  • Loading branch information
IT-VBFK committed Apr 1, 2022
1 parent df9ff7d commit 654827f
Show file tree
Hide file tree
Showing 10 changed files with 271 additions and 3 deletions.
97 changes: 96 additions & 1 deletion Src/FluentAssertions/Primitives/StringAssertions.cs
Expand Up @@ -387,6 +387,46 @@ public AndConstraint<TAssertions> NotMatch(string wildcardPattern, string becaus
return new AndConstraint<TAssertions>((TAssertions)this);
}

/// <summary>
/// Asserts that a string matches a regular expression with expected occurrence
/// </summary>
/// <param name="regularExpression">
/// The regular expression with which the subject is matched.
/// </param>
/// <param name="occurrenceConstraint">
/// A constraint specifying the expected amount of times a regex should match a string.
/// It can be created by invoking static methods Once, Twice, Thrice, or Times(int)
/// on the classes <see cref="Exactly"/>, <see cref="AtLeast"/>, <see cref="MoreThan"/>, <see cref="AtMost"/>, and <see cref="LessThan"/>.
/// For example, <see cref="Exactly.Times(int)"/> or <see cref="LessThan.Twice()"/>.
/// </param>
/// <param name="because">
/// A formatted phrase as is supported by <see cref="string.Format(string,object[])" /> explaining why the assertion
/// is needed. If the phrase does not start with the word <i>because</i>, it is prepended automatically.
/// </param>
/// <param name="becauseArgs">
/// Zero or more objects to format using the placeholders in <paramref name="because" />.
/// </param>
public AndConstraint<TAssertions> MatchRegex([RegexPattern][StringSyntax("Regex")] string regularExpression,
OccurrenceConstraint occurrenceConstraint, string because = "", params object[] becauseArgs)
{
Guard.ThrowIfArgumentIsNull(regularExpression, nameof(regularExpression),
"Cannot match string against <null>. Provide a regex pattern or use the BeNull method.");

Regex regex;
try
{
regex = new Regex(regularExpression);
}
catch (ArgumentException)
{
Execute.Assertion.FailWith("Cannot match {context:string} against {0} because it is not a valid regular expression.",
regularExpression);
return new AndConstraint<TAssertions>((TAssertions)this);
}

return MatchRegex(regex, occurrenceConstraint, because, becauseArgs);
}

/// <summary>
/// Asserts that a string matches a regular expression.
/// </summary>
Expand Down Expand Up @@ -420,6 +460,60 @@ public AndConstraint<TAssertions> NotMatch(string wildcardPattern, string becaus
return MatchRegex(regex, because, becauseArgs);
}

/// <summary>
/// Asserts that a string matches a regular expression with expected occurrence
/// </summary>
/// <param name="regularExpression">
/// The regular expression with which the subject is matched.
/// </param>
/// <param name="occurrenceConstraint">
/// A constraint specifying the expected amount of times a regex should match a string.
/// It can be created by invoking static methods Once, Twice, Thrice, or Times(int)
/// on the classes <see cref="Exactly"/>, <see cref="AtLeast"/>, <see cref="MoreThan"/>, <see cref="AtMost"/>, and <see cref="LessThan"/>.
/// For example, <see cref="Exactly.Times(int)"/> or <see cref="LessThan.Twice()"/>.
/// </param>
/// <param name="because">
/// A formatted phrase as is supported by <see cref="string.Format(string,object[])" /> explaining why the assertion
/// is needed. If the phrase does not start with the word <i>because</i>, it is prepended automatically.
/// </param>
/// <param name="becauseArgs">
/// Zero or more objects to format using the placeholders in <paramref name="because" />.
/// </param>
public AndConstraint<TAssertions> MatchRegex(Regex regularExpression,
OccurrenceConstraint occurrenceConstraint, string because = "", params object[] becauseArgs)
{
Guard.ThrowIfArgumentIsNull(regularExpression, nameof(regularExpression),
"Cannot match string against <null>. Provide a regex pattern or use the BeNull method.");

var regexStr = regularExpression.ToString();
if (regexStr.Length == 0)
{
throw new ArgumentException(
"Cannot match string against an empty string. Provide a regex pattern or use the BeEmpty method.",
nameof(regularExpression));
}

bool success = Execute.Assertion
.ForCondition(Subject is not null)
.UsingLineBreaks
.BecauseOf(because, becauseArgs)
.FailWith("Expected {context:string} to match regex {0}{reason}, but it was <null>.", regexStr);

if (success)
{
int actual = regularExpression.Matches(Subject).Count;

Execute.Assertion
.ForConstraint(occurrenceConstraint, actual)
.UsingLineBreaks
.BecauseOf(because, becauseArgs)
.FailWith($"Expected {{context:string}} to match regex {{0}} {{expectedOccurrence}}{{reason}}, but found it {actual.Times()}.",
regexStr);
}

return new AndConstraint<TAssertions>((TAssertions)this);
}

/// <summary>
/// Asserts that a string matches a regular expression.
/// </summary>
Expand All @@ -433,7 +527,8 @@ public AndConstraint<TAssertions> NotMatch(string wildcardPattern, string becaus
/// <param name="becauseArgs">
/// Zero or more objects to format using the placeholders in <paramref name="because" />.
/// </param>
public AndConstraint<TAssertions> MatchRegex(Regex regularExpression, string because = "", params object[] becauseArgs)
public AndConstraint<TAssertions> MatchRegex(Regex regularExpression,
string because = "", params object[] becauseArgs)
{
Guard.ThrowIfArgumentIsNull(regularExpression, nameof(regularExpression),
"Cannot match string against <null>. Provide a regex pattern or use the BeNull method.");
Expand Down
Expand Up @@ -2121,6 +2121,8 @@ namespace FluentAssertions.Primitives
public FluentAssertions.AndConstraint<TAssertions> MatchEquivalentOf(string wildcardPattern, string because = "", params object[] becauseArgs) { }
public FluentAssertions.AndConstraint<TAssertions> MatchRegex(string regularExpression, string because = "", params object[] becauseArgs) { }
public FluentAssertions.AndConstraint<TAssertions> MatchRegex(System.Text.RegularExpressions.Regex regularExpression, string because = "", params object[] becauseArgs) { }
public FluentAssertions.AndConstraint<TAssertions> MatchRegex(string regularExpression, FluentAssertions.OccurrenceConstraint occurrenceConstraint, string because = "", params object[] becauseArgs) { }
public FluentAssertions.AndConstraint<TAssertions> MatchRegex(System.Text.RegularExpressions.Regex regularExpression, FluentAssertions.OccurrenceConstraint occurrenceConstraint, string because = "", params object[] becauseArgs) { }
public FluentAssertions.AndConstraint<TAssertions> NotBe(string unexpected, string because = "", params object[] becauseArgs) { }
public FluentAssertions.AndConstraint<TAssertions> NotBeEmpty(string because = "", params object[] becauseArgs) { }
public FluentAssertions.AndConstraint<TAssertions> NotBeEquivalentTo(string unexpected, string because = "", params object[] becauseArgs) { }
Expand Down
Expand Up @@ -2204,6 +2204,8 @@ namespace FluentAssertions.Primitives
public FluentAssertions.AndConstraint<TAssertions> MatchEquivalentOf(string wildcardPattern, string because = "", params object[] becauseArgs) { }
public FluentAssertions.AndConstraint<TAssertions> MatchRegex(string regularExpression, string because = "", params object[] becauseArgs) { }
public FluentAssertions.AndConstraint<TAssertions> MatchRegex(System.Text.RegularExpressions.Regex regularExpression, string because = "", params object[] becauseArgs) { }
public FluentAssertions.AndConstraint<TAssertions> MatchRegex(string regularExpression, FluentAssertions.OccurrenceConstraint occurrenceConstraint, string because = "", params object[] becauseArgs) { }
public FluentAssertions.AndConstraint<TAssertions> MatchRegex(System.Text.RegularExpressions.Regex regularExpression, FluentAssertions.OccurrenceConstraint occurrenceConstraint, string because = "", params object[] becauseArgs) { }
public FluentAssertions.AndConstraint<TAssertions> NotBe(string unexpected, string because = "", params object[] becauseArgs) { }
public FluentAssertions.AndConstraint<TAssertions> NotBeEmpty(string because = "", params object[] becauseArgs) { }
public FluentAssertions.AndConstraint<TAssertions> NotBeEquivalentTo(string unexpected, string because = "", params object[] becauseArgs) { }
Expand Down
Expand Up @@ -2121,6 +2121,8 @@ namespace FluentAssertions.Primitives
public FluentAssertions.AndConstraint<TAssertions> MatchEquivalentOf(string wildcardPattern, string because = "", params object[] becauseArgs) { }
public FluentAssertions.AndConstraint<TAssertions> MatchRegex(string regularExpression, string because = "", params object[] becauseArgs) { }
public FluentAssertions.AndConstraint<TAssertions> MatchRegex(System.Text.RegularExpressions.Regex regularExpression, string because = "", params object[] becauseArgs) { }
public FluentAssertions.AndConstraint<TAssertions> MatchRegex(string regularExpression, FluentAssertions.OccurrenceConstraint occurrenceConstraint, string because = "", params object[] becauseArgs) { }
public FluentAssertions.AndConstraint<TAssertions> MatchRegex(System.Text.RegularExpressions.Regex regularExpression, FluentAssertions.OccurrenceConstraint occurrenceConstraint, string because = "", params object[] becauseArgs) { }
public FluentAssertions.AndConstraint<TAssertions> NotBe(string unexpected, string because = "", params object[] becauseArgs) { }
public FluentAssertions.AndConstraint<TAssertions> NotBeEmpty(string because = "", params object[] becauseArgs) { }
public FluentAssertions.AndConstraint<TAssertions> NotBeEquivalentTo(string unexpected, string because = "", params object[] becauseArgs) { }
Expand Down
Expand Up @@ -2121,6 +2121,8 @@ namespace FluentAssertions.Primitives
public FluentAssertions.AndConstraint<TAssertions> MatchEquivalentOf(string wildcardPattern, string because = "", params object[] becauseArgs) { }
public FluentAssertions.AndConstraint<TAssertions> MatchRegex(string regularExpression, string because = "", params object[] becauseArgs) { }
public FluentAssertions.AndConstraint<TAssertions> MatchRegex(System.Text.RegularExpressions.Regex regularExpression, string because = "", params object[] becauseArgs) { }
public FluentAssertions.AndConstraint<TAssertions> MatchRegex(string regularExpression, FluentAssertions.OccurrenceConstraint occurrenceConstraint, string because = "", params object[] becauseArgs) { }
public FluentAssertions.AndConstraint<TAssertions> MatchRegex(System.Text.RegularExpressions.Regex regularExpression, FluentAssertions.OccurrenceConstraint occurrenceConstraint, string because = "", params object[] becauseArgs) { }
public FluentAssertions.AndConstraint<TAssertions> NotBe(string unexpected, string because = "", params object[] becauseArgs) { }
public FluentAssertions.AndConstraint<TAssertions> NotBeEmpty(string because = "", params object[] becauseArgs) { }
public FluentAssertions.AndConstraint<TAssertions> NotBeEquivalentTo(string unexpected, string because = "", params object[] becauseArgs) { }
Expand Down
Expand Up @@ -2073,6 +2073,8 @@ namespace FluentAssertions.Primitives
public FluentAssertions.AndConstraint<TAssertions> MatchEquivalentOf(string wildcardPattern, string because = "", params object[] becauseArgs) { }
public FluentAssertions.AndConstraint<TAssertions> MatchRegex(string regularExpression, string because = "", params object[] becauseArgs) { }
public FluentAssertions.AndConstraint<TAssertions> MatchRegex(System.Text.RegularExpressions.Regex regularExpression, string because = "", params object[] becauseArgs) { }
public FluentAssertions.AndConstraint<TAssertions> MatchRegex(string regularExpression, FluentAssertions.OccurrenceConstraint occurrenceConstraint, string because = "", params object[] becauseArgs) { }
public FluentAssertions.AndConstraint<TAssertions> MatchRegex(System.Text.RegularExpressions.Regex regularExpression, FluentAssertions.OccurrenceConstraint occurrenceConstraint, string because = "", params object[] becauseArgs) { }
public FluentAssertions.AndConstraint<TAssertions> NotBe(string unexpected, string because = "", params object[] becauseArgs) { }
public FluentAssertions.AndConstraint<TAssertions> NotBeEmpty(string because = "", params object[] becauseArgs) { }
public FluentAssertions.AndConstraint<TAssertions> NotBeEquivalentTo(string unexpected, string because = "", params object[] becauseArgs) { }
Expand Down
Expand Up @@ -2121,6 +2121,8 @@ namespace FluentAssertions.Primitives
public FluentAssertions.AndConstraint<TAssertions> MatchEquivalentOf(string wildcardPattern, string because = "", params object[] becauseArgs) { }
public FluentAssertions.AndConstraint<TAssertions> MatchRegex(string regularExpression, string because = "", params object[] becauseArgs) { }
public FluentAssertions.AndConstraint<TAssertions> MatchRegex(System.Text.RegularExpressions.Regex regularExpression, string because = "", params object[] becauseArgs) { }
public FluentAssertions.AndConstraint<TAssertions> MatchRegex(string regularExpression, FluentAssertions.OccurrenceConstraint occurrenceConstraint, string because = "", params object[] becauseArgs) { }
public FluentAssertions.AndConstraint<TAssertions> MatchRegex(System.Text.RegularExpressions.Regex regularExpression, FluentAssertions.OccurrenceConstraint occurrenceConstraint, string because = "", params object[] becauseArgs) { }
public FluentAssertions.AndConstraint<TAssertions> NotBe(string unexpected, string because = "", params object[] becauseArgs) { }
public FluentAssertions.AndConstraint<TAssertions> NotBeEmpty(string because = "", params object[] becauseArgs) { }
public FluentAssertions.AndConstraint<TAssertions> NotBeEquivalentTo(string unexpected, string because = "", params object[] becauseArgs) { }
Expand Down

0 comments on commit 654827f

Please sign in to comment.