Skip to content

Commit fd4dfb4

Browse files
committed
port placeholder change that allows arguments fro Java version
1 parent 8dafede commit fd4dfb4

File tree

7 files changed

+214
-17
lines changed

7 files changed

+214
-17
lines changed

RELEASE_NOTES.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
11
# Release Notes
22

3-
## XMLUnit.NET 2.7.3 - /nor released, yet/
3+
## XMLUnit.NET 2.8.0 - /nor released, yet/
4+
5+
This version contains a backwards incompatible change to the
6+
`IPlaceholderHandler` interface that is part of the experimental
7+
placeholders module: The `Evaluate` method now receives a variable
8+
number of string arguments in addition to the textual content of the
9+
element/attribute. This allows placeholders like
10+
`${xmlunit.matchesRegex(some\s*regex)}`.
411

512
* add a new `${xmlunit.isDateTime}` placeholder
613
[#31](https://github.com/xmlunit/xmlunit.net/pull/31) and

src/main/net-placeholders/IPlaceholderHandler.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ namespace Org.XmlUnit.Placeholder {
2929
/// method may be invoked by multiple threads in parallel.
3030
/// </para>
3131
/// <para>
32-
/// since 2.6.0
32+
/// since 2.8.0
3333
/// </para>
3434
/// </remarks>
3535
public interface IPlaceholderHandler {
@@ -42,6 +42,6 @@ public interface IPlaceholderHandler {
4242
/// Evaluate the test value when control contained the
4343
/// placeholder handled by this class.
4444
/// </summary>
45-
ComparisonResult Evaluate(string testText);
45+
ComparisonResult Evaluate(string testText, params string[] args);
4646
}
4747
}

src/main/net-placeholders/IgnorePlaceholderHandler.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ public class IgnorePlaceholderHandler : IPlaceholderHandler {
3232
/// <inheritdoc/>
3333
public string Keyword { get { return PLACEHOLDER_NAME_IGNORE; } }
3434
/// <inheritdoc/>
35-
public ComparisonResult Evaluate(string testText) {
35+
public ComparisonResult Evaluate(string testText, params string[] args) {
3636
return ComparisonResult.EQUAL;
3737
}
3838
}

src/main/net-placeholders/IsDateTimePlaceholderHandler.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ public class IsDateTimePlaceholderHandler : IPlaceholderHandler
3232
public string Keyword { get { return _keyword; } }
3333

3434
/// <inheritdoc/>
35-
public ComparisonResult Evaluate(string testText)
35+
public ComparisonResult Evaluate(string testText, params string[] args)
3636
{
3737
DateTime _;
3838
var result = DateTime.TryParse(testText, out _);

src/main/net-placeholders/IsNumberPlaceholderHandler.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ public class IsNumberPlaceholderHandler : IPlaceholderHandler {
3333
/// <inheritdoc/>
3434
public string Keyword { get { return PLACEHOLDER_NAME; } }
3535
/// <inheritdoc/>
36-
public ComparisonResult Evaluate(string testText) {
36+
public ComparisonResult Evaluate(string testText, params string[] args) {
3737
return testText != null && NUMBER_PATTERN_REGEX.Match(testText).Success
3838
? ComparisonResult.EQUAL : ComparisonResult.DIFFERENT;
3939
}

src/main/net-placeholders/PlaceholderDifferenceEvaluator.cs

Lines changed: 102 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -57,9 +57,31 @@ namespace Org.XmlUnit.Placeholder {
5757
public class PlaceholderDifferenceEvaluator {
5858
public static readonly string PLACEHOLDER_DEFAULT_OPENING_DELIMITER_REGEX = Regex.Escape("${");
5959
public static readonly string PLACEHOLDER_DEFAULT_CLOSING_DELIMITER_REGEX = Regex.Escape("}");
60+
/// <remarks>
61+
/// <para>
62+
/// since 2.8.0
63+
/// </para>
64+
/// </remarks>
65+
public static readonly string PLACEHOLDER_DEFAULT_ARGS_OPENING_DELIMITER_REGEX = Regex.Escape("(");
66+
67+
/// <remarks>
68+
/// <para>
69+
/// since 2.8.0
70+
/// </para>
71+
/// </remarks>
72+
public static readonly string PLACEHOLDER_DEFAULT_ARGS_CLOSING_DELIMITER_REGEX = Regex.Escape(")");
73+
74+
/// <remarks>
75+
/// <para>
76+
/// since 2.8.0
77+
/// </para>
78+
/// </remarks>
79+
public static readonly string PLACEHOLDER_DEFAULT_ARGS_SEPARATOR_REGEX = Regex.Escape(",");
80+
6081
private static readonly string PLACEHOLDER_PREFIX_REGEX = Regex.Escape("xmlunit.");
6182
// IReadOnlyDictionary is .NET Framework 4.5
6283
private static readonly IDictionary<string, IPlaceholderHandler> KNOWN_HANDLERS;
84+
private static readonly string[] NO_ARGS = new string[0];
6385

6486
static PlaceholderDifferenceEvaluator() {
6587
var m = new Dictionary<string, IPlaceholderHandler>();
@@ -88,6 +110,8 @@ private static IEnumerable<Type> GetLoadableTypes(Assembly assembly) {
88110
}
89111

90112
private readonly Regex placeholderRegex;
113+
private readonly Regex argsRegex;
114+
private readonly Regex argsSplitter;
91115

92116
/// <summary>
93117
/// Creates a PlaceholderDifferenceEvaluator with default
@@ -113,7 +137,50 @@ public PlaceholderDifferenceEvaluator() : this(null, null) {
113137
/// PlaceholderDifferenceEvaluator#PLACEHOLDER_DEFAULT_CLOSING_DELIMITER_REGEX
114138
/// if the parameter is null or blank</param>
115139
public PlaceholderDifferenceEvaluator(string placeholderOpeningDelimiterRegex,
116-
string placeholderClosingDelimiterRegex) {
140+
string placeholderClosingDelimiterRegex)
141+
: this(placeholderOpeningDelimiterRegex, placeholderClosingDelimiterRegex, null, null, null) {
142+
}
143+
144+
/// <summary>
145+
/// Creates a PlaceholderDifferenceEvaluator with default
146+
/// delimiters PLACEHOLDER_DEFAULT_OPENING_DELIMITER_REGEX and
147+
/// PLACEHOLDER_DEFAULT_CLOSING_DELIMITER_REGEX.
148+
/// </summary>
149+
/// <param name="placeholderOpeningDelimiterRegex">regular
150+
/// expression for the opening delimiter of placeholder,
151+
/// defaults to
152+
/// PlaceholderDifferenceEvaluator#PLACEHOLDER_DEFAULT_OPENING_DELIMITER_REGEX
153+
/// if the parameter is null or blank</param>
154+
/// <param name="placeholderClosingDelimiterRegex">regular
155+
/// expression for the closing delimiter of placeholder,
156+
/// defaults to
157+
/// PlaceholderDifferenceEvaluator#PLACEHOLDER_DEFAULT_CLOSING_DELIMITER_REGEX
158+
/// if the parameter is null or blank</param>
159+
/// <param name="placeholderArgsOpeningDelimiterRegex">regular
160+
/// expression for the opening delimiter of the placeholder's
161+
/// argument list, defaults to
162+
/// PlaceholderDifferenceEvaluator#PLACEHOLDER_DEFAULT_ARGS_OPENING_DELIMITER_REGEX
163+
/// if the parameter is null or blank</param>
164+
/// <param name="placeholderArgsClosingDelimiterRegex">regular
165+
/// expression for the closing delimiter of the placeholder's
166+
/// argument list, defaults to
167+
/// PlaceholderDifferenceEvaluator#PLACEHOLDER_DEFAULT_ARGS_CLOSING_DELIMITER_REGEX
168+
/// if the parameter is null or blank</param>
169+
/// <param name="placeholderArgsSeparatorRegex">regular
170+
/// expression for the delimiter between arguments inside of
171+
/// the placeholder's argument list, defaults to
172+
/// PlaceholderDifferenceEvaluator#PLACEHOLDER_DEFAULT_ARGS_SEPARATOR_REGEX
173+
/// if the parameter is null or blank</param>
174+
/// <remarks>
175+
/// <para>
176+
/// since 2.8.0
177+
/// </para>
178+
/// </remarks>
179+
public PlaceholderDifferenceEvaluator(string placeholderOpeningDelimiterRegex,
180+
string placeholderClosingDelimiterRegex,
181+
string placeholderArgsOpeningDelimiterRegex,
182+
string placeholderArgsClosingDelimiterRegex,
183+
string placeholderArgsSeparatorRegex) {
117184
if (placeholderOpeningDelimiterRegex == null
118185
|| placeholderOpeningDelimiterRegex.Trim().Length == 0) {
119186
placeholderOpeningDelimiterRegex = PLACEHOLDER_DEFAULT_OPENING_DELIMITER_REGEX;
@@ -122,10 +189,26 @@ public PlaceholderDifferenceEvaluator(string placeholderOpeningDelimiterRegex,
122189
|| placeholderClosingDelimiterRegex.Trim().Length == 0) {
123190
placeholderClosingDelimiterRegex = PLACEHOLDER_DEFAULT_CLOSING_DELIMITER_REGEX;
124191
}
192+
if (placeholderArgsOpeningDelimiterRegex == null
193+
|| placeholderArgsOpeningDelimiterRegex.Trim().Length == 0) {
194+
placeholderArgsOpeningDelimiterRegex = PLACEHOLDER_DEFAULT_ARGS_OPENING_DELIMITER_REGEX;
195+
}
196+
if (placeholderArgsClosingDelimiterRegex == null
197+
|| placeholderArgsClosingDelimiterRegex.Trim().Length == 0) {
198+
placeholderArgsClosingDelimiterRegex = PLACEHOLDER_DEFAULT_ARGS_CLOSING_DELIMITER_REGEX;
199+
}
200+
if (placeholderArgsSeparatorRegex == null
201+
|| placeholderArgsSeparatorRegex.Trim().Length == 0) {
202+
placeholderArgsSeparatorRegex = PLACEHOLDER_DEFAULT_ARGS_SEPARATOR_REGEX;
203+
}
125204

126205
placeholderRegex = new Regex("(\\s*" + placeholderOpeningDelimiterRegex
127206
+ "\\s*" + PLACEHOLDER_PREFIX_REGEX + "(.+)" + "\\s*"
128207
+ placeholderClosingDelimiterRegex + "\\s*)");
208+
argsRegex = new Regex("((.*)\\s*" + placeholderArgsOpeningDelimiterRegex
209+
+ "(.+)"
210+
+ "\\s*" + placeholderArgsClosingDelimiterRegex + "\\s*)");
211+
argsSplitter = new Regex(placeholderArgsSeparatorRegex);
129212
}
130213

131214
/// <summary>
@@ -171,7 +254,7 @@ public ComparisonResult Evaluate(Comparison comparison, ComparisonResult outcome
171254
private bool IsMissingTextNodeDifference(Comparison comparison) {
172255
return ControlHasOneTextChildAndTestHasNone(comparison)
173256
|| CantFindControlTextChildInTest(comparison);
174-
}
257+
}
175258

176259
private bool ControlHasOneTextChildAndTestHasNone(Comparison comparison) {
177260
Comparison.Detail controlDetails = comparison.ControlDetails;
@@ -254,14 +337,24 @@ private ComparisonResult EvaluateAttributeListLengthConsideringPlaceholders(Comp
254337

255338
private ComparisonResult EvaluateConsideringPlaceholders(string controlText, string testText,
256339
ComparisonResult outcome) {
257-
Match m = placeholderRegex.Match(controlText);
258-
if (m.Success) {
259-
string keyword = m.Groups[2].Captures[0].Value.Trim();
340+
Match placeholderMatch = placeholderRegex.Match(controlText);
341+
if (placeholderMatch.Success) {
342+
string content = placeholderMatch.Groups[2].Captures[0].Value.Trim();
343+
Match argsMatch = argsRegex.Match(content);
344+
string keyword;
345+
string[] args;
346+
if (argsMatch.Success) {
347+
keyword = argsMatch.Groups[2].Captures[0].Value.Trim();
348+
args = argsSplitter.Split(argsMatch.Groups[3].Captures[0].Value);
349+
} else {
350+
keyword = content;
351+
args = NO_ARGS;
352+
}
260353
if (IsKnown(keyword)) {
261-
if (m.Groups[1].Captures[0].Value.Trim() != controlText.Trim()) {
354+
if (placeholderMatch.Groups[1].Captures[0].Value.Trim() != controlText.Trim()) {
262355
throw new XMLUnitException("The placeholder must exclusively occupy the text node.");
263356
}
264-
return Evaluate(keyword, testText);
357+
return Evaluate(keyword, testText, args);
265358
}
266359
}
267360

@@ -273,8 +366,8 @@ private bool IsKnown(string keyword) {
273366
return KNOWN_HANDLERS.ContainsKey(keyword);
274367
}
275368

276-
private ComparisonResult Evaluate(string keyword, string testText) {
277-
return KNOWN_HANDLERS[keyword].Evaluate(testText);
369+
private ComparisonResult Evaluate(string keyword, string testText, string[] args) {
370+
return KNOWN_HANDLERS[keyword].Evaluate(testText, args);
278371
}
279372
}
280373
}

src/main/net-placeholders/PlaceholderSupport.cs

Lines changed: 99 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,54 @@ public static D WithPlaceholderSupport<D>(this D configurer)
5858
public static D WithPlaceholderSupportUsingDelimiters<D>(this D configurer, string placeholderOpeningDelimiterRegex,
5959
string placeholderClosingDelimiterRegex)
6060
where D : IDifferenceEngineConfigurer<D> {
61+
return WithPlaceholderSupportUsingDelimiters(configurer, placeholderOpeningDelimiterRegex,
62+
placeholderClosingDelimiterRegex, null, null, null);
63+
}
64+
65+
/// <summary>
66+
/// Adds placeholder support to an IDifferenceEngineConfigurer.
67+
/// </summary>
68+
/// <param name="configurer">configurer the configurer to add support to</param>
69+
/// <param name="placeholderOpeningDelimiterRegex">regular
70+
/// expression for the opening delimiter of placeholder,
71+
/// defaults to
72+
/// PlaceholderDifferenceEvaluator#PLACEHOLDER_DEFAULT_OPENING_DELIMITER_REGEX
73+
/// if the parameter is null or blank</param>
74+
/// <param name="placeholderClosingDelimiterRegex">regular
75+
/// expression for the closing delimiter of placeholder,
76+
/// defaults to
77+
/// PlaceholderDifferenceEvaluator#PLACEHOLDER_DEFAULT_CLOSING_DELIMITER_REGEX
78+
/// if the parameter is null or blank</param>
79+
/// <param name="placeholderArgsOpeningDelimiterRegex">regular
80+
/// expression for the opening delimiter of the placeholder's
81+
/// argument list, defaults to
82+
/// PlaceholderDifferenceEvaluator#PLACEHOLDER_DEFAULT_ARGS_OPENING_DELIMITER_REGEX
83+
/// if the parameter is null or blank</param>
84+
/// <param name="placeholderArgsClosingDelimiterRegex">regular
85+
/// expression for the closing delimiter of the placeholder's
86+
/// argument list, defaults to
87+
/// PlaceholderDifferenceEvaluator#PLACEHOLDER_DEFAULT_ARGS_CLOSING_DELIMITER_REGEX
88+
/// if the parameter is null or blank</param>
89+
/// <param name="placeholderArgsSeparatorRegex">regular
90+
/// expression for the delimiter between arguments inside of
91+
/// the placeholder's argument list, defaults to
92+
/// PlaceholderDifferenceEvaluator#PLACEHOLDER_DEFAULT_ARGS_SEPARATOR_REGEX
93+
/// if the parameter is null or blank</param>
94+
/// <remarks>
95+
/// <para>
96+
/// since 2.8.0
97+
/// </para>
98+
/// </remarks>
99+
/// <return>the configurer with placeholder support added in.</return>
100+
public static D WithPlaceholderSupportUsingDelimiters<D>(this D configurer, string placeholderOpeningDelimiterRegex,
101+
string placeholderClosingDelimiterRegex,
102+
string placeholderArgsOpeningDelimiterRegex,
103+
string placeholderArgsClosingDelimiterRegex,
104+
string placeholderArgsSeparatorRegex)
105+
where D : IDifferenceEngineConfigurer<D> {
61106
return configurer.WithDifferenceEvaluator(new PlaceholderDifferenceEvaluator(placeholderOpeningDelimiterRegex,
62-
placeholderClosingDelimiterRegex).Evaluate);
107+
placeholderClosingDelimiterRegex, placeholderArgsOpeningDelimiterRegex,
108+
placeholderArgsClosingDelimiterRegex, placeholderArgsSeparatorRegex).Evaluate);
63109
}
64110

65111
/// <summary>
@@ -99,9 +145,60 @@ public static D WithPlaceholderSupportUsingDelimitersChainedAfter<D>(this D conf
99145
string placeholderOpeningDelimiterRegex, string placeholderClosingDelimiterRegex,
100146
DifferenceEvaluator evaluator)
101147
where D : IDifferenceEngineConfigurer<D> {
148+
return WithPlaceholderSupportUsingDelimitersChainedAfter(configurer, placeholderOpeningDelimiterRegex,
149+
placeholderClosingDelimiterRegex, null, null, null, evaluator);
150+
}
151+
152+
/// <summary>
153+
/// Adds placeholder support to an IDifferenceEngineConfigurer
154+
/// considering an additional DifferenceEvaluator.
155+
/// </summary>
156+
/// <param name="configurer">configurer the configurer to add support to</param>
157+
/// <param name="placeholderOpeningDelimiterRegex">regular
158+
/// expression for the opening delimiter of placeholder,
159+
/// defaults to
160+
/// PlaceholderDifferenceEvaluator#PLACEHOLDER_DEFAULT_OPENING_DELIMITER_REGEX
161+
/// if the parameter is null or blank</param>
162+
/// <param name="placeholderClosingDelimiterRegex">regular
163+
/// expression for the closing delimiter of placeholder,
164+
/// defaults to
165+
/// PlaceholderDifferenceEvaluator#PLACEHOLDER_DEFAULT_CLOSING_DELIMITER_REGEX
166+
/// if the parameter is null or blank</param>
167+
/// <param name="evaluator">the additional evaluator -
168+
/// placeholder support is chained after the given
169+
/// evaluator.</param>
170+
/// <param name="placeholderArgsOpeningDelimiterRegex">regular
171+
/// expression for the opening delimiter of the placeholder's
172+
/// argument list, defaults to
173+
/// PlaceholderDifferenceEvaluator#PLACEHOLDER_DEFAULT_ARGS_OPENING_DELIMITER_REGEX
174+
/// if the parameter is null or blank</param>
175+
/// <param name="placeholderArgsClosingDelimiterRegex">regular
176+
/// expression for the closing delimiter of the placeholder's
177+
/// argument list, defaults to
178+
/// PlaceholderDifferenceEvaluator#PLACEHOLDER_DEFAULT_ARGS_CLOSING_DELIMITER_REGEX
179+
/// if the parameter is null or blank</param>
180+
/// <param name="placeholderArgsSeparatorRegex">regular
181+
/// expression for the delimiter between arguments inside of
182+
/// the placeholder's argument list, defaults to
183+
/// PlaceholderDifferenceEvaluator#PLACEHOLDER_DEFAULT_ARGS_SEPARATOR_REGEX
184+
/// if the parameter is null or blank</param>
185+
/// <remarks>
186+
/// <para>
187+
/// since 2.8.0
188+
/// </para>
189+
/// </remarks>
190+
/// <return>the configurer with placeholder support added in.</return>
191+
public static D WithPlaceholderSupportUsingDelimitersChainedAfter<D>(this D configurer,
192+
string placeholderOpeningDelimiterRegex, string placeholderClosingDelimiterRegex,
193+
string placeholderArgsOpeningDelimiterRegex,
194+
string placeholderArgsClosingDelimiterRegex,
195+
string placeholderArgsSeparatorRegex,
196+
DifferenceEvaluator evaluator)
197+
where D : IDifferenceEngineConfigurer<D> {
102198
return configurer.WithDifferenceEvaluator(DifferenceEvaluators.Chain(
103199
evaluator, new PlaceholderDifferenceEvaluator(placeholderOpeningDelimiterRegex,
104-
placeholderClosingDelimiterRegex).Evaluate));
200+
placeholderClosingDelimiterRegex, placeholderArgsOpeningDelimiterRegex,
201+
placeholderArgsClosingDelimiterRegex, placeholderArgsSeparatorRegex).Evaluate));
105202
}
106203
}
107204
}

0 commit comments

Comments
 (0)