Skip to content

Commit 528ae49

Browse files
dstjdennisdoomen
authored andcommitted
Add MatchRegex() and NotMatchRegex() assertions (#23)
1 parent 9d65489 commit 528ae49

File tree

3 files changed

+129
-1
lines changed

3 files changed

+129
-1
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,11 @@
1212
- `HaveCount()`
1313
- `HaveElement()`
1414
- `HaveValue()`
15+
- `MatchRegex()`
1516
- `NotBeEquivalentTo()`
1617
- `NotHaveElement()`
1718
- `NotHaveValue()`
19+
- `NotMatchRegex()`
1820

1921
See "in-code" description for more information.
2022

Src/FluentAssertions.Json/JTokenAssertions.cs

Lines changed: 63 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
using FluentAssertions.Formatting;
77
using FluentAssertions.Primitives;
88
using Newtonsoft.Json.Linq;
9+
using System.Text.RegularExpressions;
10+
using System;
911

1012
namespace FluentAssertions.Json
1113
{
@@ -180,6 +182,67 @@ public AndConstraint<JTokenAssertions> NotHaveValue(string unexpected, string be
180182
return new AndConstraint<JTokenAssertions>(this);
181183
}
182184

185+
/// <summary>
186+
/// Asserts that the current <see cref="JToken" /> matches the specified <paramref name="regularExpression" /> regular expression pattern.
187+
/// </summary>
188+
/// <param name="regularExpression">The expected regular expression pattern</param>
189+
public AndConstraint<JTokenAssertions> MatchRegex(string regularExpression)
190+
{
191+
return MatchRegex(regularExpression, string.Empty);
192+
}
193+
194+
/// <summary>
195+
/// Asserts that the current <see cref="JToken" /> matches the specified <paramref name="regularExpression" /> regular expression pattern.
196+
/// </summary>
197+
/// <param name="regularExpression">The expected regular expression pattern</param>
198+
/// <param name="because">
199+
/// A formatted phrase as is supported by <see cref="string.Format(string,object[])" /> explaining why the assertion
200+
/// is needed. If the phrase does not start with the word <i>because</i>, it is prepended automatically.
201+
/// </param>
202+
/// <param name="becauseArgs">
203+
/// Zero or more objects to format using the placeholders in <see paramref="because" />.
204+
/// </param>
205+
public AndConstraint<JTokenAssertions> MatchRegex(string regularExpression, string because, params object[] becauseArgs)
206+
{
207+
if (regularExpression == null) {
208+
throw new ArgumentNullException(nameof(regularExpression), "MatchRegex does not support <null> pattern");
209+
}
210+
211+
Execute.Assertion
212+
.ForCondition(Regex.IsMatch(Subject.Value<string>(), regularExpression ?? ""))
213+
.BecauseOf(because, becauseArgs)
214+
.FailWith("Expected {context:JSON property} {0} to match regex pattern {1}{reason}, but found {2}.",
215+
Subject.Path, regularExpression, Subject.Value<string>());
216+
217+
return new AndConstraint<JTokenAssertions>(this);
218+
}
219+
220+
/// <summary>
221+
/// Asserts that the current <see cref="JToken" /> does not match the specified <paramref name="regularExpression" /> regular expression pattern.
222+
/// </summary>
223+
/// <param name="regularExpression">The expected regular expression pattern</param>
224+
/// <param name="because">
225+
/// A formatted phrase as is supported by <see cref="string.Format(string,object[])" /> explaining why the assertion
226+
/// is needed. If the phrase does not start with the word <i>because</i>, it is prepended automatically.
227+
/// </param>
228+
/// <param name="becauseArgs">
229+
/// Zero or more objects to format using the placeholders in <see paramref="because" />.
230+
/// </param>
231+
public AndConstraint<JTokenAssertions> NotMatchRegex(string regularExpression, string because = "", params object[] becauseArgs)
232+
{
233+
if (regularExpression == null) {
234+
throw new ArgumentNullException(nameof(regularExpression), "MatchRegex does not support <null> pattern");
235+
}
236+
237+
Execute.Assertion
238+
.ForCondition(!Regex.IsMatch(Subject.Value<string>(), regularExpression))
239+
.BecauseOf(because, becauseArgs)
240+
.FailWith("Did not expect {context:JSON property} {0} to match regex pattern {1}{reason}.",
241+
Subject.Path, regularExpression, Subject.Value<string>());
242+
243+
return new AndConstraint<JTokenAssertions>(this);
244+
}
245+
183246
/// <summary>
184247
/// Asserts that the current <see cref="JToken" /> has a direct child element with the specified
185248
/// <paramref name="expected" /> name.
@@ -397,6 +460,5 @@ public string Format(JToken value, bool useLineBreaks = false)
397460
UseLineBreaks = useLineBreaks
398461
}, null);
399462
}
400-
401463
}
402464
}

Tests/FluentAssertions.Json.Shared.Specs/JTokenAssertionsSpecs.cs

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -457,6 +457,70 @@ public void When_jtoken_does_have_value_NotHaveValue_should_fail()
457457

458458
#endregion (Not)HaveValue
459459

460+
#region (Not)MatchRegex
461+
462+
[Fact]
463+
public void When_json_matches_regex_pattern_MatchRegex_should_succeed()
464+
{
465+
//-----------------------------------------------------------------------------------------------------------
466+
// Arrange
467+
//-----------------------------------------------------------------------------------------------------------
468+
var subject = JToken.Parse("{ 'id': 42 }");
469+
470+
//-----------------------------------------------------------------------------------------------------------
471+
// Act & Assert
472+
//-----------------------------------------------------------------------------------------------------------
473+
subject["id"].Should().MatchRegex("\\d{2}");
474+
}
475+
476+
[Fact]
477+
public void When_json_does_not_match_regex_pattern_MatchRegex_should_fail()
478+
{
479+
//-----------------------------------------------------------------------------------------------------------
480+
// Arrange
481+
//-----------------------------------------------------------------------------------------------------------
482+
var subject = JToken.Parse("{ 'id': 'not two digits' }");
483+
484+
//-----------------------------------------------------------------------------------------------------------
485+
// Act & Assert
486+
//-----------------------------------------------------------------------------------------------------------
487+
subject["id"].Should().Invoking(x => x.MatchRegex("\\d{2}", "because foo"))
488+
.Should().Throw<XunitException>()
489+
.WithMessage("Expected JSON property \"id\" to match regex pattern \"\\d{2}\" because foo, but found \"not two digits\".");
490+
}
491+
492+
[Fact]
493+
public void When_json_does_not_match_regex_pattern_NotHaveRegexValue_should_succeed()
494+
{
495+
//-----------------------------------------------------------------------------------------------------------
496+
// Arrange
497+
//-----------------------------------------------------------------------------------------------------------
498+
var subject = JToken.Parse("{ 'id': 'not two digits' }");
499+
500+
//-----------------------------------------------------------------------------------------------------------
501+
// Act & Assert
502+
//-----------------------------------------------------------------------------------------------------------
503+
subject["id"].Should().NotMatchRegex("\\d{2}");
504+
}
505+
506+
[Fact]
507+
public void When_json_matches_regex_pattern_NotHaveRegexValue_should_fail()
508+
{
509+
//-----------------------------------------------------------------------------------------------------------
510+
// Arrange
511+
//-----------------------------------------------------------------------------------------------------------
512+
var subject = JToken.Parse("{ 'id': 42 }");
513+
514+
//-----------------------------------------------------------------------------------------------------------
515+
// Act & Assert
516+
//-----------------------------------------------------------------------------------------------------------
517+
subject["id"].Should().Invoking(x => x.NotMatchRegex("\\d{2}", "because foo"))
518+
.Should().Throw<XunitException>()
519+
.WithMessage("Did not expect JSON property \"id\" to match regex pattern \"\\d{2}\" because foo.");
520+
}
521+
522+
#endregion (Not)MatchRegex
523+
460524
#region (Not)HaveElement
461525

462526
[Fact]

0 commit comments

Comments
 (0)