From d6dee908e08ffda2cbd52152bed4b204cb82ace5 Mon Sep 17 00:00:00 2001 From: Egil Hansen Date: Sat, 4 Feb 2023 18:36:52 +0000 Subject: [PATCH 1/2] refactor: correct test names --- .../NodeStrategies/ForwardSearchingNodeMatcherTest.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/AngleSharp.Diffing.Tests/Strategies/NodeStrategies/ForwardSearchingNodeMatcherTest.cs b/src/AngleSharp.Diffing.Tests/Strategies/NodeStrategies/ForwardSearchingNodeMatcherTest.cs index eb6e294..5cc6626 100644 --- a/src/AngleSharp.Diffing.Tests/Strategies/NodeStrategies/ForwardSearchingNodeMatcherTest.cs +++ b/src/AngleSharp.Diffing.Tests/Strategies/NodeStrategies/ForwardSearchingNodeMatcherTest.cs @@ -15,7 +15,7 @@ public ForwardSearchingNodeMatcherTest(DiffingTestFixture fixture) : base(fixtur { } - [Theory(DisplayName = "The matcher matches two nodes with the same node name")] + [Theory(DisplayName = "The matcher matches two nodes with of the same type")] [InlineData("textnode", "textnode")] [InlineData("

", "

")] [InlineData("", "")] @@ -33,7 +33,7 @@ public void Test001(string controlHtml, string testHtml) actual.ShouldAllBe((c, idx) => c.Control == controls[idx] && c.Test == tests[idx]); } - [Theory(DisplayName = "The matcher matches two nodes with the same node name")] + [Theory(DisplayName = "The matcher matches two nodes of the same type skipping excluded")] [InlineData("asdf

Hello world

asdf

Hello world

", "asdf

Hello world

asdf

Hello world

")] public void Test0011(string controlHtml, string testHtml) { From ee864f3ef0deffcf2509ea081feac5fbe39f9136 Mon Sep 17 00:00:00 2001 From: Sebastian Stehle Date: Sun, 5 Mar 2023 09:43:25 +0100 Subject: [PATCH 2/2] feat: Self closing comparer. (#32) * Self closing comparer. * Implement suggestions. * Added changelog entry. * Update CHANGELOG.md * Update CHANGELOG.md * add IsKeepingSourceReferences to diffbuilder too --------- Co-authored-by: Egil Hansen --- CHANGELOG.md | 4 ++ .../DiffingTestFixture.cs | 6 ++- .../ElementClosingComparerTest.cs | 41 +++++++++++++++++++ src/AngleSharp.Diffing/DiffBuilder.cs | 14 ++++++- src/AngleSharp.Diffing/HtmlDiffer.cs | 15 ++++++- ...iffingStrategyPipelineBuilderExtensions.cs | 9 ++++ .../ElementClosingComparer.cs | 29 +++++++++++++ 7 files changed, 113 insertions(+), 5 deletions(-) create mode 100644 src/AngleSharp.Diffing.Tests/Strategies/ElementStrategies/ElementClosingComparerTest.cs create mode 100644 src/AngleSharp.Diffing/Strategies/ElementStrategies/ElementClosingComparer.cs diff --git a/CHANGELOG.md b/CHANGELOG.md index 486d859..ed5594b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +# 0.18.0 + +- Added a new comparer, which ensures element tags are closed the same way, e.g. `
and
` would not be considered equal, but `
` and `
` would be. + # 0.17.1 Released on Friday, February 3, 2023. diff --git a/src/AngleSharp.Diffing.Tests/DiffingTestFixture.cs b/src/AngleSharp.Diffing.Tests/DiffingTestFixture.cs index afe756f..9cdaf9c 100644 --- a/src/AngleSharp.Diffing.Tests/DiffingTestFixture.cs +++ b/src/AngleSharp.Diffing.Tests/DiffingTestFixture.cs @@ -11,7 +11,11 @@ public class DiffingTestFixture public DiffingTestFixture() { - var config = Configuration.Default.WithCss(); + // Create a custom config with a parser to allow access to the source reference from the AST. + var config = Configuration.Default + .WithCss() + .With(ctx => new HtmlParser(new HtmlParserOptions { IsKeepingSourceReferences = true, IsScripting = ctx?.IsScripting() ?? false }, ctx)); + _context = BrowsingContext.New(config); _htmlParser = _context.GetService(); _document = _context.OpenNewAsync().Result; diff --git a/src/AngleSharp.Diffing.Tests/Strategies/ElementStrategies/ElementClosingComparerTest.cs b/src/AngleSharp.Diffing.Tests/Strategies/ElementStrategies/ElementClosingComparerTest.cs new file mode 100644 index 0000000..cf254f0 --- /dev/null +++ b/src/AngleSharp.Diffing.Tests/Strategies/ElementStrategies/ElementClosingComparerTest.cs @@ -0,0 +1,41 @@ +using System.Linq; + +using AngleSharp.Diffing.Core; + +using Shouldly; + +using Xunit; + +namespace AngleSharp.Diffing.Strategies.ElementStrategies +{ + public class ElementClosingComparerTest : DiffingTestBase + { + public ElementClosingComparerTest(DiffingTestFixture fixture) : base(fixture) + { + } + + [Fact(DisplayName = "When control and test nodes have are both self closed, the result is Same")] + public void Test001() + { + var comparison = ToComparison("", ""); + + ElementClosingComparer.Compare(comparison, CompareResult.Unknown).ShouldBe(CompareResult.Same); + } + + [Fact(DisplayName = "When control and test nodes have are both not self closed, the result is Same")] + public void Test002() + { + var comparison = ToComparison("", ""); + + ElementClosingComparer.Compare(comparison, CompareResult.Unknown).ShouldBe(CompareResult.Same); + } + + [Fact(DisplayName = "When either control or test node is self closed, the result is Same")] + public void Test003() + { + var comparison = ToComparison("", ""); + + ElementClosingComparer.Compare(comparison, CompareResult.Unknown).ShouldBe(CompareResult.Different); + } + } +} diff --git a/src/AngleSharp.Diffing/DiffBuilder.cs b/src/AngleSharp.Diffing/DiffBuilder.cs index 16b4303..3e18049 100644 --- a/src/AngleSharp.Diffing/DiffBuilder.cs +++ b/src/AngleSharp.Diffing/DiffBuilder.cs @@ -34,9 +34,19 @@ public class DiffBuilder private DiffBuilder(string control) { Control = control; - var config = Configuration.Default.WithCss(); + + // Create a custom config with a parser to allow access to the source reference from the AST. + var config = Configuration.Default + .WithCss() + .With(ctx => new HtmlParser(new HtmlParserOptions + { + IsKeepingSourceReferences = true, + IsScripting = ctx?.IsScripting() ?? false + }, ctx)); + _context = BrowsingContext.New(config); - _htmlParser = _context.GetService() ?? throw new InvalidOperationException("No IHtmlParser registered in the default AngleSharp browsing context."); + _htmlParser = _context.GetService() + ?? throw new InvalidOperationException("No IHtmlParser registered in the default AngleSharp browsing context."); _document = _context.OpenNewAsync().Result; } diff --git a/src/AngleSharp.Diffing/HtmlDiffer.cs b/src/AngleSharp.Diffing/HtmlDiffer.cs index a9afc52..292c04f 100644 --- a/src/AngleSharp.Diffing/HtmlDiffer.cs +++ b/src/AngleSharp.Diffing/HtmlDiffer.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; + using AngleSharp.Diffing.Core; using AngleSharp.Diffing.Extensions; using AngleSharp.Dom; @@ -24,9 +25,19 @@ public class HtmlDiffer public HtmlDiffer(IDiffingStrategy diffingStrategy) { _diffingStrategy = diffingStrategy ?? throw new ArgumentNullException(nameof(diffingStrategy)); - var config = Configuration.Default.WithCss(); + + // Create a custom config with a parser to allow access to the source reference from the AST. + var config = Configuration.Default + .WithCss() + .With(ctx => new HtmlParser(new HtmlParserOptions + { + IsKeepingSourceReferences = true, + IsScripting = ctx?.IsScripting() ?? false + }, ctx)); + _context = BrowsingContext.New(config); - _htmlParser = _context.GetService() ?? throw new InvalidOperationException("No IHtmlParser registered in the default AngleSharp browsing context."); + _htmlParser = _context.GetService() + ?? throw new InvalidOperationException("No IHtmlParser registered in the default AngleSharp browsing context."); _document = _context.OpenNewAsync().Result; } diff --git a/src/AngleSharp.Diffing/Strategies/ElementStrategies/DiffingStrategyPipelineBuilderExtensions.cs b/src/AngleSharp.Diffing/Strategies/ElementStrategies/DiffingStrategyPipelineBuilderExtensions.cs index 3b0b475..68787eb 100644 --- a/src/AngleSharp.Diffing/Strategies/ElementStrategies/DiffingStrategyPipelineBuilderExtensions.cs +++ b/src/AngleSharp.Diffing/Strategies/ElementStrategies/DiffingStrategyPipelineBuilderExtensions.cs @@ -14,6 +14,15 @@ public static IDiffingStrategyCollection AddElementComparer(this IDiffingStrateg return builder; } + /// + /// Adds an element comparer that ensures element tags are closed the same way, e.g. `<br>` and `<br />` would not be considered equal, but `<br>` and `<br>` would be. + /// + public static IDiffingStrategyCollection AddElementClosingComparer(this IDiffingStrategyCollection builder) + { + builder.AddComparer(ElementClosingComparer.Compare, StrategyType.Generalized); + return builder; + } + /// /// Enables the CSS-selector matcher strategy during diffing. /// diff --git a/src/AngleSharp.Diffing/Strategies/ElementStrategies/ElementClosingComparer.cs b/src/AngleSharp.Diffing/Strategies/ElementStrategies/ElementClosingComparer.cs new file mode 100644 index 0000000..06544b4 --- /dev/null +++ b/src/AngleSharp.Diffing/Strategies/ElementStrategies/ElementClosingComparer.cs @@ -0,0 +1,29 @@ +using AngleSharp.Diffing.Core; +using AngleSharp.Dom; +using AngleSharp.Html.Parser.Tokens; + +namespace AngleSharp.Diffing.Strategies.ElementStrategies +{ + /// + /// Represents the element closing comparer strategy. + /// + public static class ElementClosingComparer + { + /// + /// The element comparer closing strategy. + /// + public static CompareResult Compare(in Comparison comparison, CompareResult currentDecision) + { + if (currentDecision == CompareResult.Skip) + return currentDecision; + + if (comparison.Test.Node is not IElement testElement || testElement.SourceReference is not HtmlTagToken testTag) + return currentDecision; + + if (comparison.Control.Node is not IElement controlElement || controlElement.SourceReference is not HtmlTagToken controlTag) + return currentDecision; + + return testTag.IsSelfClosing == controlTag.IsSelfClosing ? CompareResult.Same : CompareResult.Different; + } + } +}