Skip to content

Commit 591529d

Browse files
authored
Merge pull request #16 from AngleSharp/devel
0.7.0 release
2 parents 1096d5b + 5a95070 commit 591529d

11 files changed

+284
-11
lines changed

CHANGELOG.md

+6
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
# 0.17.0
2+
3+
Released on Wednesday, September 8, 2021.
4+
5+
- Added the ability to ignore an elements children or its attributes. By [@grishat](https://github.com/grishat).
6+
17
# 0.16.0
28

39
Released on Wednesday, June 24, 2021.

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

+38
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,44 @@ public void Test2()
357357
results.ShouldBeEmpty();
358358
}
359359

360+
[Theory(DisplayName = "When comparer returns SkipChildren flag from an element comparison, child nodes are not compared")]
361+
[InlineData(CompareResult.Same | CompareResult.SkipChildren)]
362+
[InlineData(CompareResult.Skip | CompareResult.SkipChildren)]
363+
public void Test3(CompareResult compareResult)
364+
{
365+
var sut = CreateHtmlDiffer(
366+
nodeMatcher: OneToOneNodeListMatcher,
367+
nodeFilter: NoneNodeFilter,
368+
nodeComparer: c => c.Control.Node.NodeName == "P" ? compareResult : throw new Exception("NODE COMPARER SHOULD NOT BE CALLED ON CHILD NODES"),
369+
attrMatcher: AttributeNameMatcher,
370+
attrFilter: NoneAttrFilter,
371+
attrComparer: SameResultAttrComparer
372+
);
373+
374+
var results = sut.Compare(ToNodeList(@"<p><em>foo</em></p>"), ToNodeList(@"<p><span>baz</span></p>"));
375+
376+
results.ShouldBeEmpty();
377+
}
378+
379+
[Theory(DisplayName = "When comparer returns SkipAttributes flag from an element comparison, attributes are not compared")]
380+
[InlineData(CompareResult.Same | CompareResult.SkipAttributes)]
381+
[InlineData(CompareResult.Skip | CompareResult.SkipAttributes)]
382+
public void Test4(CompareResult compareResult)
383+
{
384+
var sut = CreateHtmlDiffer(
385+
nodeMatcher: OneToOneNodeListMatcher,
386+
nodeFilter: NoneNodeFilter,
387+
nodeComparer: c => compareResult,
388+
attrMatcher: AttributeNameMatcher,
389+
attrFilter: NoneAttrFilter,
390+
attrComparer: SameResultAttrComparer
391+
);
392+
393+
var results = sut.Compare(ToNodeList(@"<p id=""foo""></p>"), ToNodeList(@"<p id=""bar"" unexpected></p>"));
394+
395+
results.ShouldBeEmpty();
396+
}
397+
360398
#region NodeFilters
361399
private static FilterDecision NoneNodeFilter(ComparisonSource source) => FilterDecision.Keep;
362400
private static FilterDecision RemoveCommentNodeFilter(ComparisonSource source) => source.Node.NodeType == NodeType.Comment ? FilterDecision.Exclude : FilterDecision.Keep;

src/AngleSharp.Diffing.Tests/DiffBuilderTest.cs

+36
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
}
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+
}
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 IgnoreChildrenElementComparerTest : DiffingTestBase
12+
{
13+
public IgnoreChildrenElementComparerTest(DiffingTestFixture fixture) : base(fixture)
14+
{
15+
}
16+
17+
[Theory(DisplayName = "When a control element does not contain the 'diff:ignoreChildren' attribute or it is 'diff:ignoreChildren=false', the current decision is returned")]
18+
[InlineData(@"<p></p>")]
19+
[InlineData(@"<p diff:ignoreChildren=""false""></p>")]
20+
[InlineData(@"<p diff:ignoreChildren=""FALSE""></p>")]
21+
[InlineData(@"<p diff:ignoreChildren=""faLsE""></p>")]
22+
public void Test001(string controlHtml)
23+
{
24+
var comparison = ToComparison(controlHtml, "<p></p>");
25+
26+
IgnoreChildrenElementComparer.Compare(comparison, CompareResult.Different).ShouldBe(CompareResult.Different);
27+
IgnoreChildrenElementComparer.Compare(comparison, CompareResult.Same).ShouldBe(CompareResult.Same);
28+
IgnoreChildrenElementComparer.Compare(comparison, CompareResult.Skip).ShouldBe(CompareResult.Skip);
29+
}
30+
31+
[Theory(DisplayName = "When a control element has 'diff:ignoreChildren' attribute, CompareResult.SkipChildren flag is returned")]
32+
[InlineData(@"<p diff:ignoreChildren></p>")]
33+
[InlineData(@"<p diff:ignoreChildren=""true""></p>")]
34+
[InlineData(@"<p diff:ignoreChildren=""TRUE""></p>")]
35+
[InlineData(@"<p diff:ignoreChildren=""TrUe""></p>")]
36+
public void Test002(string controlHtml)
37+
{
38+
var comparison = ToComparison(controlHtml, "<p></p>");
39+
40+
IgnoreChildrenElementComparer.Compare(comparison, CompareResult.Same).ShouldBe(CompareResult.Same | CompareResult.SkipChildren);
41+
IgnoreChildrenElementComparer.Compare(comparison, CompareResult.Different).ShouldBe(CompareResult.Different | CompareResult.SkipChildren);
42+
}
43+
}
44+
}

src/AngleSharp.Diffing/Core/CompareResult.cs

+15-4
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,33 @@
1-
namespace AngleSharp.Diffing.Core
1+
using System;
2+
3+
namespace AngleSharp.Diffing.Core
24
{
35
/// <summary>
46
/// Represents a result of a comparison.
57
/// </summary>
8+
[Flags]
69
public enum CompareResult
710
{
811
/// <summary>
912
/// Use when the two compared nodes or attributes are the same.
1013
/// </summary>
11-
Same,
14+
Same = 1,
1215
/// <summary>
1316
/// Use when the two compared nodes or attributes are the different.
1417
/// </summary>
15-
Different,
18+
Different = 2,
1619
/// <summary>
1720
/// Use when the comparison should be skipped and any child-nodes or attributes skipped as well.
1821
/// </summary>
19-
Skip
22+
Skip = 4,
23+
/// <summary>
24+
/// Use when the comparison should skip any child-nodes.
25+
/// </summary>
26+
SkipChildren = 8,
27+
/// <summary>
28+
/// Use when the comparison should skip any attributes.
29+
/// </summary>
30+
SkipAttributes = 16,
2031
}
2132

2233
/// <summary>

src/AngleSharp.Diffing/Core/HtmlDifferenceEngine.cs

+7-5
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ private IEnumerable<IDiff> CompareNode(in Comparison comparison)
9292
}
9393

9494
var compareRes = _diffingStrategy.Compare(comparison);
95-
if (compareRes == CompareResult.Different)
95+
if (compareRes.HasFlag(CompareResult.Different))
9696
{
9797
IDiff diff = new NodeDiff(comparison);
9898
return new[] { diff };
@@ -106,15 +106,17 @@ private IEnumerable<IDiff> CompareElement(in Comparison comparison)
106106
var result = new List<IDiff>();
107107

108108
var compareRes = _diffingStrategy.Compare(comparison);
109-
if (compareRes == CompareResult.Different)
109+
if (compareRes.HasFlag(CompareResult.Different))
110110
{
111111
result.Add(new NodeDiff(comparison));
112112
}
113113

114-
if (compareRes != CompareResult.Skip)
114+
if (!compareRes.HasFlag(CompareResult.Skip))
115115
{
116-
result.AddRange(CompareElementAttributes(comparison));
117-
result.AddRange(CompareChildNodes(comparison));
116+
if (!compareRes.HasFlag(CompareResult.SkipAttributes))
117+
result.AddRange(CompareElementAttributes(comparison));
118+
if (!compareRes.HasFlag(CompareResult.SkipChildren))
119+
result.AddRange(CompareChildNodes(comparison));
118120
}
119121

120122
return result;

src/AngleSharp.Diffing/Strategies/DiffingStrategyPipelineBuilderExtensions.cs

+4-2
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,10 @@ public static IDiffingStrategyCollection AddDefaultOptions(this IDiffingStrategy
2424
.AddAttributeComparer()
2525
.AddClassAttributeComparer()
2626
.AddBooleanAttributeComparer(BooleanAttributeComparision.Strict)
27-
.AddStyleAttributeComparer();
28-
;
27+
.AddStyleAttributeComparer()
28+
.AddIgnoreChildrenElementSupport()
29+
.AddIgnoreAttributesElementSupport()
30+
;
2931
}
3032
}
3133
}

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

+22
Original file line numberDiff line numberDiff line change
@@ -33,5 +33,27 @@ public static IDiffingStrategyCollection AddIgnoreElementSupport(this IDiffingSt
3333
builder.AddComparer(IgnoreElementComparer.Compare, StrategyType.Specialized);
3434
return builder;
3535
}
36+
37+
/// <summary>
38+
/// Enables the ignore children element `diff:ignoreChildren` attribute during diffing.
39+
/// </summary>
40+
/// <param name="builder"></param>
41+
/// <returns></returns>
42+
public static IDiffingStrategyCollection AddIgnoreChildrenElementSupport(this IDiffingStrategyCollection builder)
43+
{
44+
builder.AddComparer(IgnoreChildrenElementComparer.Compare, StrategyType.Specialized);
45+
return builder;
46+
}
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+
}
3658
}
3759
}
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+
}
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 children element comparer.
9+
/// </summary>
10+
public static class IgnoreChildrenElementComparer
11+
{
12+
private const string DIFF_IGNORE_CHILDREN_ATTRIBUTE = "diff:ignorechildren";
13+
14+
/// <summary>
15+
/// The ignore children 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 ControlHasTruthyIgnoreChildrenAttribute(comparison)
23+
? currentDecision | CompareResult.SkipChildren
24+
: currentDecision;
25+
}
26+
27+
private static bool ControlHasTruthyIgnoreChildrenAttribute(in Comparison comparison)
28+
{
29+
return comparison.Control.Node is IElement element &&
30+
element.TryGetAttrValue(DIFF_IGNORE_CHILDREN_ATTRIBUTE, out bool shouldIgnore) &&
31+
shouldIgnore;
32+
}
33+
}
34+
}

0 commit comments

Comments
 (0)