Skip to content

Commit e987280

Browse files
committed
port ElementSelectors.ByNameAndAllAttributes from Java version
1 parent 7183029 commit e987280

File tree

7 files changed

+105
-13
lines changed

7 files changed

+105
-13
lines changed

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,3 +222,9 @@ assemblies. In order to run the tests use
222222
> dotnet test src/tests/net-constraints-nunit3/XMLUnit.NUnit3.Constraints.Test.csproj
223223
> dotnet test src/tests/net-placeholders/XMLUnit.Placeholders.Tests.csproj
224224
```
225+
226+
You may need to specify
227+
[`--roll-forward`](https://learn.microsoft.com/en-us/dotnet/core/tools/dotnet#rollforward)
228+
of
229+
[`DOTNET_ROLL_FORWARD`](https://learn.microsoft.com/en-us/dotnet/core/tools/dotnet-environment-variables#dotnet_roll_forward)
230+
to run the tests when using recent versions of .NET.

RELEASE_NOTES.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
## XMLUnit.NET 2.9.3 - /not released, yet/
44

5+
* add a new `ElementSelectors.ByNameAndAllAttributes` variant that filters attributes before deciding whether elements can
6+
be compared.
7+
Inspired by Issue [#xmlunit/259](https://github.com/xmlunit/xmlunit/issues/259)
8+
59
* `Nodes.StripElementContentWhitespace` had the same problem of not
610
knowning about `XmlWhitespace` that caused
711
Issue [#38](https://github.com/xmlunit/xmlunit.net/issues/38)

src/main/net-core/Diff/ElementSelectors.cs

Lines changed: 39 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -152,19 +152,31 @@ public static ElementSelector
152152
/// Elements with the same local name (and namespace URI - if any)
153153
/// and attribute values for all attributes can be compared.
154154
/// </summary>
155+
/// <remarks>
156+
/// <para>
157+
/// This ElementSelector doesn't know anything about a
158+
/// potentially configured attribute filter so may also
159+
/// compare attributes that are excluded from comparison by
160+
/// the filter. Use the ByNameAndAllAttributes(Predicate)
161+
/// passing in your attribute filter if this causes problems.
162+
/// </para>
163+
/// </remarks>
155164
public static bool ByNameAndAllAttributes(XmlElement controlElement,
156165
XmlElement testElement) {
157-
if (!ByName(controlElement, testElement)) {
158-
return false;
159-
}
160-
IDictionary<XmlQualifiedName, string> cAttrs =
161-
Nodes.GetAttributes(controlElement);
162-
IDictionary<XmlQualifiedName, string> tAttrs =
163-
Nodes.GetAttributes(testElement);
164-
if (cAttrs.Count != tAttrs.Count) {
165-
return false;
166-
}
167-
return MapsEqualForKeys(cAttrs, tAttrs, cAttrs.Keys);
166+
return ByNameAndAllAttributes(ignored => true, controlElement, testElement);
167+
}
168+
169+
/// <summary>
170+
/// Elements with the same local name (and namespace URI - if any)
171+
/// and attribute values for all attributes can be compared.
172+
/// </summary>
173+
/// <remarks>
174+
/// <para>
175+
/// since XMLUnit 2.9.3
176+
/// </para>
177+
/// </remarks>
178+
public static ElementSelector ByNameAndAllAttributes(Predicate<XmlAttribute> attributeFiler) {
179+
return (control, test) => ByNameAndAllAttributes(attributeFiler, control, test);
168180
}
169181

170182
/// <summary>
@@ -420,5 +432,21 @@ private static bool
420432
});
421433
}
422434

435+
private static bool ByNameAndAllAttributes(Predicate<XmlAttribute> attributeFiler,
436+
XmlElement controlElement,
437+
XmlElement testElement) {
438+
if (!ByName(controlElement, testElement)) {
439+
return false;
440+
}
441+
IDictionary<XmlQualifiedName, string> cAttrs =
442+
Nodes.GetAttributes(controlElement, attributeFiler);
443+
IDictionary<XmlQualifiedName, string> tAttrs =
444+
Nodes.GetAttributes(testElement, attributeFiler);
445+
if (cAttrs.Count != tAttrs.Count) {
446+
return false;
447+
}
448+
return MapsEqualForKeys(cAttrs, tAttrs, cAttrs.Keys);
449+
}
450+
423451
}
424452
}

src/main/net-core/Diff/IDifferenceEngine.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,12 @@ public interface IDifferenceEngine {
8282
/// If you want to suppress comparison of them you'll need to
8383
/// implement <see cref="DifferenceEvaluator"/>
8484
/// </para>
85+
/// <para>
86+
/// Note that NodeMatcher will not by aware of the configured
87+
/// attribute filter and if its decision is based on
88+
/// attributes it will in general also consider attributes the
89+
/// filter would suppress.
90+
/// </para>
8591
/// </remarks>
8692
Predicate<XmlAttribute> AttributeFilter { set; }
8793

@@ -105,4 +111,4 @@ public interface IDifferenceEngine {
105111
/// <param name="test">the document to test</param>
106112
void Compare(ISource control, ISource test);
107113
}
108-
}
114+
}

src/main/net-core/Util/Nodes.cs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ the License. You may obtain a copy of the License at
1212
limitations under the License.
1313
*/
1414

15+
using System;
1516
using System.Collections.Generic;
1617
using System.Linq;
1718
using System.Text;
@@ -51,9 +52,23 @@ public static string GetMergedNestedText(XmlNode n) {
5152
/// </summary>
5253
public static IDictionary<XmlQualifiedName, string>
5354
GetAttributes(XmlNode n) {
55+
return GetAttributes(n, ignored => true);
56+
}
57+
58+
/// <summary>
59+
/// Obtains an element's attributes as dictionary.
60+
/// </summary>
61+
/// <remarks>
62+
/// <para>
63+
/// since XMLUnit 2.9.3
64+
/// </para>
65+
/// </remarks>
66+
public static IDictionary<XmlQualifiedName, string>
67+
GetAttributes(XmlNode n, Predicate<XmlAttribute> attributeFilter) {
5468
XmlAttributeCollection coll = n.Attributes;
5569
if (coll != null) {
5670
return coll.Cast<XmlAttribute>()
71+
.Where(a => attributeFilter(a))
5772
.ToDictionary<XmlAttribute, XmlQualifiedName, string>(GetQName,
5873
a => a.Value);
5974
}

src/tests/net-core/Diff/ElementSelectorsTest.cs

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,30 @@ [Test] public void ByNameAndAllAttributes() {
117117
differentNS));
118118
}
119119

120+
[Test] public void ByNameAndAllAttributesWithFilter() {
121+
XmlElement control = doc.CreateElement(FOO);
122+
control.SetAttribute(BAR, BAR);
123+
XmlElement equal = doc.CreateElement(FOO);
124+
equal.SetAttribute(BAR, BAR);
125+
equal.SetAttribute("x", "y");
126+
XmlElement noAttributes = doc.CreateElement(FOO);
127+
XmlElement differentValue = doc.CreateElement(FOO);
128+
differentValue.SetAttribute(BAR, FOO);
129+
XmlElement differentName = doc.CreateElement(FOO);
130+
differentName.SetAttribute(FOO, FOO);
131+
XmlElement differentNS = doc.CreateElement(FOO);
132+
differentNS.SetAttribute(BAR, SOME_URI, BAR);
133+
Predicate<XmlAttribute> filter = a => BAR == a.Name;
134+
ElementSelector es = ElementSelectors.ByNameAndAllAttributes(filter);
135+
136+
Assert.IsTrue(es(control, equal));
137+
Assert.IsFalse(es(control, noAttributes));
138+
Assert.IsFalse(es(noAttributes, control));
139+
Assert.IsFalse(es(control, differentValue));
140+
Assert.IsFalse(es(control, differentName));
141+
Assert.IsFalse(es(control, differentNS));
142+
}
143+
120144
[Test] public void ByNameAndAttributes_NamePart() {
121145
PureElementNameComparisons(ElementSelectors
122146
.ByNameAndAttributes(new string[] {}));
@@ -559,4 +583,4 @@ public void ConditionalSelectorBuilderWontAllowMultipleDefaults() {
559583
});
560584
}
561585
}
562-
}
586+
}

src/tests/net-core/Util/NodesTest.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,15 @@ [Test] public void AttributeIDictionarywithNS() {
123123
Assert.AreEqual(BAR, m[new XmlQualifiedName(FOO, SOME_URI)]);
124124
}
125125

126+
[Test] public void AttributeMapWithFilter() {
127+
XmlElement e = doc.CreateElement(FOO);
128+
e.SetAttribute(FOO, BAR);
129+
e.SetAttribute("x", "y");
130+
IDictionary<XmlQualifiedName, string> m = Nodes.GetAttributes(e, a => FOO == a.Name);
131+
Assert.AreEqual(1, m.Count);
132+
Assert.AreEqual(BAR, m[new XmlQualifiedName(FOO)]);
133+
}
134+
126135
private XmlDocument HandleWsSetup() {
127136
return Convert.ToDocument(InputBuilder.FromString(
128137
"<root>\n"

0 commit comments

Comments
 (0)