Skip to content

Commit a8263ce

Browse files
committed
ADD: diff:ignoreAttributes element comparer
1 parent e0c5092 commit a8263ce

10 files changed

+157
-26
lines changed

src/AngleSharp.Diffing.Tests/Core/HtmlDifferenceEngineTest.cs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -374,6 +374,23 @@ public void Test3()
374374
results.ShouldBeEmpty();
375375
}
376376

377+
[Fact(DisplayName = "When comparer returns SkipAttributes from an element comparison, attributes are not compared")]
378+
public void Test4()
379+
{
380+
var sut = CreateHtmlDiffer(
381+
nodeMatcher: OneToOneNodeListMatcher,
382+
nodeFilter: NoneNodeFilter,
383+
nodeComparer: c => CompareResult.Same | CompareResult.SkipAttributes,
384+
attrMatcher: AttributeNameMatcher,
385+
attrFilter: NoneAttrFilter,
386+
attrComparer: SameResultAttrComparer
387+
);
388+
389+
var results = sut.Compare(ToNodeList(@"<p id=""foo""></p>"), ToNodeList(@"<p id=""bar"" unexpected></p>"));
390+
391+
results.ShouldBeEmpty();
392+
}
393+
377394
#region NodeFilters
378395
private static FilterDecision NoneNodeFilter(ComparisonSource source) => FilterDecision.Keep;
379396
private static FilterDecision RemoveCommentNodeFilter(ComparisonSource source) => source.Node.NodeType == NodeType.Comment ? FilterDecision.Exclude : FilterDecision.Keep;

src/AngleSharp.Diffing.Tests/DiffBuilderTest.cs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,5 +89,41 @@ public void Test004()
8989
nodeComparerCalled.ShouldBeTrue();
9090
attrComparerCalled.ShouldBeTrue();
9191
}
92+
93+
[Theory(DisplayName = "When a control element has 'diff:ignoreChildren', calling Build() with DefaultOptions() returns empty diffs")]
94+
[InlineData(@"<p diff:ignoreChildren>hello <em>world</em></p>",
95+
@"<p>world says <strong>hello</strong></p>")]
96+
[InlineData(@"<p diff:ignoreChildren>hello</p>",
97+
@"<p>world says <strong>hello</strong></p>")]
98+
[InlineData(@"<p diff:ignoreChildren>hello <em>world</em></p>",
99+
@"<p>world says</p>")]
100+
public void Test005(string control, string test)
101+
{
102+
var diffs = DiffBuilder
103+
.Compare(control)
104+
.WithTest(test)
105+
.Build()
106+
.ToList();
107+
108+
diffs.ShouldBeEmpty();
109+
}
110+
111+
[Theory(DisplayName = "When a control element has 'diff:ignoreAttributes', calling Build() with DefaultOptions() returns empty diffs")]
112+
[InlineData(@"<p id=""foo"" diff:ignoreAttributes></p>",
113+
@"<p id=""bar""></p>")]
114+
[InlineData(@"<p diff:ignoreAttributes></p>",
115+
@"<p unexpected></p>")]
116+
[InlineData(@"<p id=""foo"" diff:ignoreAttributes></p>",
117+
@"<p></p>")]
118+
public void Test006(string control, string test)
119+
{
120+
var diffs = DiffBuilder
121+
.Compare(control)
122+
.WithTest(test)
123+
.Build()
124+
.ToList();
125+
126+
diffs.ShouldBeEmpty();
127+
}
92128
}
93129
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
using System.Linq;
2+
3+
using AngleSharp.Diffing.Core;
4+
5+
using Shouldly;
6+
7+
using Xunit;
8+
9+
namespace AngleSharp.Diffing.Strategies.ElementStrategies
10+
{
11+
public class IgnoreAttributesElementComparerTest : DiffingTestBase
12+
{
13+
public IgnoreAttributesElementComparerTest(DiffingTestFixture fixture) : base(fixture)
14+
{
15+
}
16+
17+
[Theory(DisplayName = "When a control element does not contain the 'diff:ignoreAttributes' attribute or it is 'diff:ignoreAttributes=false', the current decision is returned")]
18+
[InlineData(@"<p></p>")]
19+
[InlineData(@"<p diff:ignoreAttributes=""false""></p>")]
20+
[InlineData(@"<p diff:ignoreAttributes=""FALSE""></p>")]
21+
[InlineData(@"<p diff:ignoreAttributes=""faLsE""></p>")]
22+
public void Test001(string controlHtml)
23+
{
24+
var comparison = ToComparison(controlHtml, "<p></p>");
25+
26+
IgnoreAttributesElementComparer.Compare(comparison, CompareResult.Different).ShouldBe(CompareResult.Different);
27+
IgnoreAttributesElementComparer.Compare(comparison, CompareResult.Same).ShouldBe(CompareResult.Same);
28+
IgnoreAttributesElementComparer.Compare(comparison, CompareResult.Skip).ShouldBe(CompareResult.Skip);
29+
}
30+
31+
[Theory(DisplayName = "When a control element has 'diff:ignoreAttributes' attribute, CompareResult.SkipAttributes flag is returned")]
32+
[InlineData(@"<p diff:ignoreAttributes></p>")]
33+
[InlineData(@"<p diff:ignoreAttributes=""true""></p>")]
34+
[InlineData(@"<p diff:ignoreAttributes=""TRUE""></p>")]
35+
[InlineData(@"<p diff:ignoreAttributes=""TrUe""></p>")]
36+
public void Test002(string controlHtml)
37+
{
38+
var comparison = ToComparison(controlHtml, "<p></p>");
39+
40+
IgnoreAttributesElementComparer.Compare(comparison, CompareResult.Same).ShouldBe(CompareResult.Same | CompareResult.SkipAttributes);
41+
IgnoreAttributesElementComparer.Compare(comparison, CompareResult.Different).ShouldBe(CompareResult.Different | CompareResult.SkipAttributes);
42+
}
43+
}
44+
}

src/AngleSharp.Diffing.Tests/Strategies/ElementStrategies/IgnoreChildrenElementComparerTest.cs

Lines changed: 2 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ public IgnoreChildrenElementComparerTest(DiffingTestFixture fixture) : base(fixt
2121
[InlineData(@"<p diff:ignoreChildren=""faLsE""></p>")]
2222
public void Test001(string controlHtml)
2323
{
24-
var comparison = ToComparison(controlHtml, "<p><em></em></p>");
24+
var comparison = ToComparison(controlHtml, "<p></p>");
2525

2626
IgnoreChildrenElementComparer.Compare(comparison, CompareResult.Different).ShouldBe(CompareResult.Different);
2727
IgnoreChildrenElementComparer.Compare(comparison, CompareResult.Same).ShouldBe(CompareResult.Same);
@@ -35,28 +35,10 @@ public void Test001(string controlHtml)
3535
[InlineData(@"<p diff:ignoreChildren=""TrUe""></p>")]
3636
public void Test002(string controlHtml)
3737
{
38-
var comparison = ToComparison(controlHtml, "<p><em></em></p>");
38+
var comparison = ToComparison(controlHtml, "<p></p>");
3939

4040
IgnoreChildrenElementComparer.Compare(comparison, CompareResult.Same).ShouldBe(CompareResult.Same | CompareResult.SkipChildren);
4141
IgnoreChildrenElementComparer.Compare(comparison, CompareResult.Different).ShouldBe(CompareResult.Different | CompareResult.SkipChildren);
4242
}
43-
44-
[Theory(DisplayName = "When a control element has 'diff:ignoreChildren', calling Build() with DefaultOptions() returns empty diffs")]
45-
[InlineData(@"<p diff:ignoreChildren>hello <em>world</em></p>",
46-
@"<p>world says <strong>hello</strong></p>")]
47-
[InlineData(@"<p diff:ignoreChildren>hello</p>",
48-
@"<p>world says <strong>hello</strong></p>")]
49-
[InlineData(@"<p diff:ignoreChildren>hello <em>world</em></p>",
50-
@"<p>world says</p>")]
51-
public void Test004(string control, string test)
52-
{
53-
var diffs = DiffBuilder
54-
.Compare(control)
55-
.WithTest(test)
56-
.Build()
57-
.ToList();
58-
59-
diffs.ShouldBeEmpty();
60-
}
6143
}
6244
}

src/AngleSharp.Diffing/Core/CompareResult.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@ public enum CompareResult
2424
/// Use when the comparison should skip any child-nodes.
2525
/// </summary>
2626
SkipChildren = 8,
27+
/// <summary>
28+
/// Use when the comparison should skip any attributes.
29+
/// </summary>
30+
SkipAttributes = 16,
2731
}
2832

2933
/// <summary>

src/AngleSharp.Diffing/Core/HtmlDifferenceEngine.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,8 @@ private IEnumerable<IDiff> CompareElement(in Comparison comparison)
113113

114114
if (compareRes != CompareResult.Skip)
115115
{
116-
result.AddRange(CompareElementAttributes(comparison));
116+
if (!compareRes.HasFlag(CompareResult.SkipAttributes))
117+
result.AddRange(CompareElementAttributes(comparison));
117118
if (!compareRes.HasFlag(CompareResult.SkipChildren))
118119
result.AddRange(CompareChildNodes(comparison));
119120
}

src/AngleSharp.Diffing/Strategies/DiffingStrategyPipelineBuilderExtensions.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,15 @@ public static IDiffingStrategyCollection AddDefaultOptions(this IDiffingStrategy
1919
.AddAttributeNameMatcher()
2020
.AddElementComparer()
2121
.AddIgnoreElementSupport()
22-
.AddIgnoreChildrenElementSupport()
2322
.AddStyleSheetComparer()
2423
.AddTextComparer(WhitespaceOption.Normalize, ignoreCase: false)
2524
.AddAttributeComparer()
2625
.AddClassAttributeComparer()
2726
.AddBooleanAttributeComparer(BooleanAttributeComparision.Strict)
28-
.AddStyleAttributeComparer();
27+
.AddStyleAttributeComparer()
28+
.AddIgnoreChildrenElementSupport()
29+
.AddIgnoreAttributesElementSupport()
30+
;
2931
}
3032
}
3133
}

src/AngleSharp.Diffing/Strategies/ElementStrategies/DiffingStrategyPipelineBuilderExtensions.cs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ public static IDiffingStrategyCollection AddIgnoreElementSupport(this IDiffingSt
3535
}
3636

3737
/// <summary>
38-
/// Enables the ignore children element `diff:ignorechildren` attribute during diffing.
38+
/// Enables the ignore children element `diff:ignoreChildren` attribute during diffing.
3939
/// </summary>
4040
/// <param name="builder"></param>
4141
/// <returns></returns>
@@ -44,5 +44,16 @@ public static IDiffingStrategyCollection AddIgnoreChildrenElementSupport(this ID
4444
builder.AddComparer(IgnoreChildrenElementComparer.Compare, StrategyType.Specialized);
4545
return builder;
4646
}
47+
48+
/// <summary>
49+
/// Enables the ignore attributes element `diff:ignoreAttributes` attribute during diffing.
50+
/// </summary>
51+
/// <param name="builder"></param>
52+
/// <returns></returns>
53+
public static IDiffingStrategyCollection AddIgnoreAttributesElementSupport(this IDiffingStrategyCollection builder)
54+
{
55+
builder.AddComparer(IgnoreAttributesElementComparer.Compare, StrategyType.Specialized);
56+
return builder;
57+
}
4758
}
4859
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
using AngleSharp.Diffing.Core;
2+
using AngleSharp.Diffing.Extensions;
3+
using AngleSharp.Dom;
4+
5+
namespace AngleSharp.Diffing.Strategies.ElementStrategies
6+
{
7+
/// <summary>
8+
/// Represents the ignore attributes element comparer.
9+
/// </summary>
10+
public static class IgnoreAttributesElementComparer
11+
{
12+
private const string DIFF_IGNORE_ATTRIBUTES_ATTRIBUTE = "diff:ignoreattributes";
13+
14+
/// <summary>
15+
/// The ignore attributes element comparer.
16+
/// </summary>
17+
public static CompareResult Compare(in Comparison comparison, CompareResult currentDecision)
18+
{
19+
if (currentDecision == CompareResult.Skip)
20+
return currentDecision;
21+
22+
return ControlHasTruthyIgnoreAttributesAttribute(comparison)
23+
? currentDecision | CompareResult.SkipAttributes
24+
: currentDecision;
25+
}
26+
27+
private static bool ControlHasTruthyIgnoreAttributesAttribute(in Comparison comparison)
28+
{
29+
return comparison.Control.Node is IElement element &&
30+
element.TryGetAttrValue(DIFF_IGNORE_ATTRIBUTES_ATTRIBUTE, out bool shouldIgnore) &&
31+
shouldIgnore;
32+
}
33+
}
34+
}

src/AngleSharp.Diffing/Strategies/ElementStrategies/IgnoreChildrenElementComparer.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,12 @@ public static CompareResult Compare(in Comparison comparison, CompareResult curr
1919
if (currentDecision == CompareResult.Skip)
2020
return currentDecision;
2121

22-
return ControlHasTruthyIgnoreAttribute(comparison)
22+
return ControlHasTruthyIgnoreChildrenAttribute(comparison)
2323
? currentDecision | CompareResult.SkipChildren
2424
: currentDecision;
2525
}
2626

27-
private static bool ControlHasTruthyIgnoreAttribute(in Comparison comparison)
27+
private static bool ControlHasTruthyIgnoreChildrenAttribute(in Comparison comparison)
2828
{
2929
return comparison.Control.Node is IElement element &&
3030
element.TryGetAttrValue(DIFF_IGNORE_CHILDREN_ATTRIBUTE, out bool shouldIgnore) &&

0 commit comments

Comments
 (0)