Skip to content

Commit

Permalink
Merge pull request #16 from AngleSharp/devel
Browse files Browse the repository at this point in the history
0.7.0 release
  • Loading branch information
egil authored Sep 8, 2021
2 parents 1096d5b + 5a95070 commit 591529d
Show file tree
Hide file tree
Showing 11 changed files with 284 additions and 11 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
# 0.17.0

Released on Wednesday, September 8, 2021.

- Added the ability to ignore an elements children or its attributes. By [@grishat](https://github.com/grishat).

# 0.16.0

Released on Wednesday, June 24, 2021.
Expand Down
38 changes: 38 additions & 0 deletions src/AngleSharp.Diffing.Tests/Core/HtmlDifferenceEngineTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,44 @@ public void Test2()
results.ShouldBeEmpty();
}

[Theory(DisplayName = "When comparer returns SkipChildren flag from an element comparison, child nodes are not compared")]
[InlineData(CompareResult.Same | CompareResult.SkipChildren)]
[InlineData(CompareResult.Skip | CompareResult.SkipChildren)]
public void Test3(CompareResult compareResult)
{
var sut = CreateHtmlDiffer(
nodeMatcher: OneToOneNodeListMatcher,
nodeFilter: NoneNodeFilter,
nodeComparer: c => c.Control.Node.NodeName == "P" ? compareResult : throw new Exception("NODE COMPARER SHOULD NOT BE CALLED ON CHILD NODES"),
attrMatcher: AttributeNameMatcher,
attrFilter: NoneAttrFilter,
attrComparer: SameResultAttrComparer
);

var results = sut.Compare(ToNodeList(@"<p><em>foo</em></p>"), ToNodeList(@"<p><span>baz</span></p>"));

results.ShouldBeEmpty();
}

[Theory(DisplayName = "When comparer returns SkipAttributes flag from an element comparison, attributes are not compared")]
[InlineData(CompareResult.Same | CompareResult.SkipAttributes)]
[InlineData(CompareResult.Skip | CompareResult.SkipAttributes)]
public void Test4(CompareResult compareResult)
{
var sut = CreateHtmlDiffer(
nodeMatcher: OneToOneNodeListMatcher,
nodeFilter: NoneNodeFilter,
nodeComparer: c => compareResult,
attrMatcher: AttributeNameMatcher,
attrFilter: NoneAttrFilter,
attrComparer: SameResultAttrComparer
);

var results = sut.Compare(ToNodeList(@"<p id=""foo""></p>"), ToNodeList(@"<p id=""bar"" unexpected></p>"));

results.ShouldBeEmpty();
}

#region NodeFilters
private static FilterDecision NoneNodeFilter(ComparisonSource source) => FilterDecision.Keep;
private static FilterDecision RemoveCommentNodeFilter(ComparisonSource source) => source.Node.NodeType == NodeType.Comment ? FilterDecision.Exclude : FilterDecision.Keep;
Expand Down
36 changes: 36 additions & 0 deletions src/AngleSharp.Diffing.Tests/DiffBuilderTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -89,5 +89,41 @@ public void Test004()
nodeComparerCalled.ShouldBeTrue();
attrComparerCalled.ShouldBeTrue();
}

[Theory(DisplayName = "When a control element has 'diff:ignoreChildren', calling Build() with DefaultOptions() returns empty diffs")]
[InlineData(@"<p diff:ignoreChildren>hello <em>world</em></p>",
@"<p>world says <strong>hello</strong></p>")]
[InlineData(@"<p diff:ignoreChildren>hello</p>",
@"<p>world says <strong>hello</strong></p>")]
[InlineData(@"<p diff:ignoreChildren>hello <em>world</em></p>",
@"<p>world says</p>")]
public void Test005(string control, string test)
{
var diffs = DiffBuilder
.Compare(control)
.WithTest(test)
.Build()
.ToList();

diffs.ShouldBeEmpty();
}

[Theory(DisplayName = "When a control element has 'diff:ignoreAttributes', calling Build() with DefaultOptions() returns empty diffs")]
[InlineData(@"<p id=""foo"" diff:ignoreAttributes></p>",
@"<p id=""bar""></p>")]
[InlineData(@"<p diff:ignoreAttributes></p>",
@"<p unexpected></p>")]
[InlineData(@"<p id=""foo"" diff:ignoreAttributes></p>",
@"<p></p>")]
public void Test006(string control, string test)
{
var diffs = DiffBuilder
.Compare(control)
.WithTest(test)
.Build()
.ToList();

diffs.ShouldBeEmpty();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
using System.Linq;

using AngleSharp.Diffing.Core;

using Shouldly;

using Xunit;

namespace AngleSharp.Diffing.Strategies.ElementStrategies
{
public class IgnoreAttributesElementComparerTest : DiffingTestBase
{
public IgnoreAttributesElementComparerTest(DiffingTestFixture fixture) : base(fixture)
{
}

[Theory(DisplayName = "When a control element does not contain the 'diff:ignoreAttributes' attribute or it is 'diff:ignoreAttributes=false', the current decision is returned")]
[InlineData(@"<p></p>")]
[InlineData(@"<p diff:ignoreAttributes=""false""></p>")]
[InlineData(@"<p diff:ignoreAttributes=""FALSE""></p>")]
[InlineData(@"<p diff:ignoreAttributes=""faLsE""></p>")]
public void Test001(string controlHtml)
{
var comparison = ToComparison(controlHtml, "<p></p>");

IgnoreAttributesElementComparer.Compare(comparison, CompareResult.Different).ShouldBe(CompareResult.Different);
IgnoreAttributesElementComparer.Compare(comparison, CompareResult.Same).ShouldBe(CompareResult.Same);
IgnoreAttributesElementComparer.Compare(comparison, CompareResult.Skip).ShouldBe(CompareResult.Skip);
}

[Theory(DisplayName = "When a control element has 'diff:ignoreAttributes' attribute, CompareResult.SkipAttributes flag is returned")]
[InlineData(@"<p diff:ignoreAttributes></p>")]
[InlineData(@"<p diff:ignoreAttributes=""true""></p>")]
[InlineData(@"<p diff:ignoreAttributes=""TRUE""></p>")]
[InlineData(@"<p diff:ignoreAttributes=""TrUe""></p>")]
public void Test002(string controlHtml)
{
var comparison = ToComparison(controlHtml, "<p></p>");

IgnoreAttributesElementComparer.Compare(comparison, CompareResult.Same).ShouldBe(CompareResult.Same | CompareResult.SkipAttributes);
IgnoreAttributesElementComparer.Compare(comparison, CompareResult.Different).ShouldBe(CompareResult.Different | CompareResult.SkipAttributes);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
using System.Linq;

using AngleSharp.Diffing.Core;

using Shouldly;

using Xunit;

namespace AngleSharp.Diffing.Strategies.ElementStrategies
{
public class IgnoreChildrenElementComparerTest : DiffingTestBase
{
public IgnoreChildrenElementComparerTest(DiffingTestFixture fixture) : base(fixture)
{
}

[Theory(DisplayName = "When a control element does not contain the 'diff:ignoreChildren' attribute or it is 'diff:ignoreChildren=false', the current decision is returned")]
[InlineData(@"<p></p>")]
[InlineData(@"<p diff:ignoreChildren=""false""></p>")]
[InlineData(@"<p diff:ignoreChildren=""FALSE""></p>")]
[InlineData(@"<p diff:ignoreChildren=""faLsE""></p>")]
public void Test001(string controlHtml)
{
var comparison = ToComparison(controlHtml, "<p></p>");

IgnoreChildrenElementComparer.Compare(comparison, CompareResult.Different).ShouldBe(CompareResult.Different);
IgnoreChildrenElementComparer.Compare(comparison, CompareResult.Same).ShouldBe(CompareResult.Same);
IgnoreChildrenElementComparer.Compare(comparison, CompareResult.Skip).ShouldBe(CompareResult.Skip);
}

[Theory(DisplayName = "When a control element has 'diff:ignoreChildren' attribute, CompareResult.SkipChildren flag is returned")]
[InlineData(@"<p diff:ignoreChildren></p>")]
[InlineData(@"<p diff:ignoreChildren=""true""></p>")]
[InlineData(@"<p diff:ignoreChildren=""TRUE""></p>")]
[InlineData(@"<p diff:ignoreChildren=""TrUe""></p>")]
public void Test002(string controlHtml)
{
var comparison = ToComparison(controlHtml, "<p></p>");

IgnoreChildrenElementComparer.Compare(comparison, CompareResult.Same).ShouldBe(CompareResult.Same | CompareResult.SkipChildren);
IgnoreChildrenElementComparer.Compare(comparison, CompareResult.Different).ShouldBe(CompareResult.Different | CompareResult.SkipChildren);
}
}
}
19 changes: 15 additions & 4 deletions src/AngleSharp.Diffing/Core/CompareResult.cs
Original file line number Diff line number Diff line change
@@ -1,22 +1,33 @@
namespace AngleSharp.Diffing.Core
using System;

namespace AngleSharp.Diffing.Core
{
/// <summary>
/// Represents a result of a comparison.
/// </summary>
[Flags]
public enum CompareResult
{
/// <summary>
/// Use when the two compared nodes or attributes are the same.
/// </summary>
Same,
Same = 1,
/// <summary>
/// Use when the two compared nodes or attributes are the different.
/// </summary>
Different,
Different = 2,
/// <summary>
/// Use when the comparison should be skipped and any child-nodes or attributes skipped as well.
/// </summary>
Skip
Skip = 4,
/// <summary>
/// Use when the comparison should skip any child-nodes.
/// </summary>
SkipChildren = 8,
/// <summary>
/// Use when the comparison should skip any attributes.
/// </summary>
SkipAttributes = 16,
}

/// <summary>
Expand Down
12 changes: 7 additions & 5 deletions src/AngleSharp.Diffing/Core/HtmlDifferenceEngine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ private IEnumerable<IDiff> CompareNode(in Comparison comparison)
}

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

var compareRes = _diffingStrategy.Compare(comparison);
if (compareRes == CompareResult.Different)
if (compareRes.HasFlag(CompareResult.Different))
{
result.Add(new NodeDiff(comparison));
}

if (compareRes != CompareResult.Skip)
if (!compareRes.HasFlag(CompareResult.Skip))
{
result.AddRange(CompareElementAttributes(comparison));
result.AddRange(CompareChildNodes(comparison));
if (!compareRes.HasFlag(CompareResult.SkipAttributes))
result.AddRange(CompareElementAttributes(comparison));
if (!compareRes.HasFlag(CompareResult.SkipChildren))
result.AddRange(CompareChildNodes(comparison));
}

return result;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,10 @@ public static IDiffingStrategyCollection AddDefaultOptions(this IDiffingStrategy
.AddAttributeComparer()
.AddClassAttributeComparer()
.AddBooleanAttributeComparer(BooleanAttributeComparision.Strict)
.AddStyleAttributeComparer();
;
.AddStyleAttributeComparer()
.AddIgnoreChildrenElementSupport()
.AddIgnoreAttributesElementSupport()
;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,5 +33,27 @@ public static IDiffingStrategyCollection AddIgnoreElementSupport(this IDiffingSt
builder.AddComparer(IgnoreElementComparer.Compare, StrategyType.Specialized);
return builder;
}

/// <summary>
/// Enables the ignore children element `diff:ignoreChildren` attribute during diffing.
/// </summary>
/// <param name="builder"></param>
/// <returns></returns>
public static IDiffingStrategyCollection AddIgnoreChildrenElementSupport(this IDiffingStrategyCollection builder)
{
builder.AddComparer(IgnoreChildrenElementComparer.Compare, StrategyType.Specialized);
return builder;
}

/// <summary>
/// Enables the ignore attributes element `diff:ignoreAttributes` attribute during diffing.
/// </summary>
/// <param name="builder"></param>
/// <returns></returns>
public static IDiffingStrategyCollection AddIgnoreAttributesElementSupport(this IDiffingStrategyCollection builder)
{
builder.AddComparer(IgnoreAttributesElementComparer.Compare, StrategyType.Specialized);
return builder;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
using AngleSharp.Diffing.Core;
using AngleSharp.Diffing.Extensions;
using AngleSharp.Dom;

namespace AngleSharp.Diffing.Strategies.ElementStrategies
{
/// <summary>
/// Represents the ignore attributes element comparer.
/// </summary>
public static class IgnoreAttributesElementComparer
{
private const string DIFF_IGNORE_ATTRIBUTES_ATTRIBUTE = "diff:ignoreattributes";

/// <summary>
/// The ignore attributes element comparer.
/// </summary>
public static CompareResult Compare(in Comparison comparison, CompareResult currentDecision)
{
if (currentDecision == CompareResult.Skip)
return currentDecision;

return ControlHasTruthyIgnoreAttributesAttribute(comparison)
? currentDecision | CompareResult.SkipAttributes
: currentDecision;
}

private static bool ControlHasTruthyIgnoreAttributesAttribute(in Comparison comparison)
{
return comparison.Control.Node is IElement element &&
element.TryGetAttrValue(DIFF_IGNORE_ATTRIBUTES_ATTRIBUTE, out bool shouldIgnore) &&
shouldIgnore;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
using AngleSharp.Diffing.Core;
using AngleSharp.Diffing.Extensions;
using AngleSharp.Dom;

namespace AngleSharp.Diffing.Strategies.ElementStrategies
{
/// <summary>
/// Represents the ignore children element comparer.
/// </summary>
public static class IgnoreChildrenElementComparer
{
private const string DIFF_IGNORE_CHILDREN_ATTRIBUTE = "diff:ignorechildren";

/// <summary>
/// The ignore children element comparer.
/// </summary>
public static CompareResult Compare(in Comparison comparison, CompareResult currentDecision)
{
if (currentDecision == CompareResult.Skip)
return currentDecision;

return ControlHasTruthyIgnoreChildrenAttribute(comparison)
? currentDecision | CompareResult.SkipChildren
: currentDecision;
}

private static bool ControlHasTruthyIgnoreChildrenAttribute(in Comparison comparison)
{
return comparison.Control.Node is IElement element &&
element.TryGetAttrValue(DIFF_IGNORE_CHILDREN_ATTRIBUTE, out bool shouldIgnore) &&
shouldIgnore;
}
}
}

0 comments on commit 591529d

Please sign in to comment.