Skip to content

Commit ee864f3

Browse files
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 <[email protected]>
1 parent d6dee90 commit ee864f3

File tree

7 files changed

+113
-5
lines changed

7 files changed

+113
-5
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
# 0.18.0
2+
3+
- Added a new comparer, which ensures element tags are closed the same way, e.g. `<br> and <br />` would not be considered equal, but `<br>` and `<br>` would be.
4+
15
# 0.17.1
26

37
Released on Friday, February 3, 2023.

src/AngleSharp.Diffing.Tests/DiffingTestFixture.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,11 @@ public class DiffingTestFixture
1111

1212
public DiffingTestFixture()
1313
{
14-
var config = Configuration.Default.WithCss();
14+
// Create a custom config with a parser to allow access to the source reference from the AST.
15+
var config = Configuration.Default
16+
.WithCss()
17+
.With<IHtmlParser>(ctx => new HtmlParser(new HtmlParserOptions { IsKeepingSourceReferences = true, IsScripting = ctx?.IsScripting() ?? false }, ctx));
18+
1519
_context = BrowsingContext.New(config);
1620
_htmlParser = _context.GetService<IHtmlParser>();
1721
_document = _context.OpenNewAsync().Result;
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
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 ElementClosingComparerTest : DiffingTestBase
12+
{
13+
public ElementClosingComparerTest(DiffingTestFixture fixture) : base(fixture)
14+
{
15+
}
16+
17+
[Fact(DisplayName = "When control and test nodes have are both self closed, the result is Same")]
18+
public void Test001()
19+
{
20+
var comparison = ToComparison("<v:image />", "<v:image />");
21+
22+
ElementClosingComparer.Compare(comparison, CompareResult.Unknown).ShouldBe(CompareResult.Same);
23+
}
24+
25+
[Fact(DisplayName = "When control and test nodes have are both not self closed, the result is Same")]
26+
public void Test002()
27+
{
28+
var comparison = ToComparison("<v:image />", "<v:image />");
29+
30+
ElementClosingComparer.Compare(comparison, CompareResult.Unknown).ShouldBe(CompareResult.Same);
31+
}
32+
33+
[Fact(DisplayName = "When either control or test node is self closed, the result is Same")]
34+
public void Test003()
35+
{
36+
var comparison = ToComparison("<v:image />", "<v:image>");
37+
38+
ElementClosingComparer.Compare(comparison, CompareResult.Unknown).ShouldBe(CompareResult.Different);
39+
}
40+
}
41+
}

src/AngleSharp.Diffing/DiffBuilder.cs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,19 @@ public class DiffBuilder
3434
private DiffBuilder(string control)
3535
{
3636
Control = control;
37-
var config = Configuration.Default.WithCss();
37+
38+
// Create a custom config with a parser to allow access to the source reference from the AST.
39+
var config = Configuration.Default
40+
.WithCss()
41+
.With<IHtmlParser>(ctx => new HtmlParser(new HtmlParserOptions
42+
{
43+
IsKeepingSourceReferences = true,
44+
IsScripting = ctx?.IsScripting() ?? false
45+
}, ctx));
46+
3847
_context = BrowsingContext.New(config);
39-
_htmlParser = _context.GetService<IHtmlParser>() ?? throw new InvalidOperationException("No IHtmlParser registered in the default AngleSharp browsing context.");
48+
_htmlParser = _context.GetService<IHtmlParser>()
49+
?? throw new InvalidOperationException("No IHtmlParser registered in the default AngleSharp browsing context.");
4050
_document = _context.OpenNewAsync().Result;
4151
}
4252

src/AngleSharp.Diffing/HtmlDiffer.cs

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System;
22
using System.Collections.Generic;
3+
34
using AngleSharp.Diffing.Core;
45
using AngleSharp.Diffing.Extensions;
56
using AngleSharp.Dom;
@@ -24,9 +25,19 @@ public class HtmlDiffer
2425
public HtmlDiffer(IDiffingStrategy diffingStrategy)
2526
{
2627
_diffingStrategy = diffingStrategy ?? throw new ArgumentNullException(nameof(diffingStrategy));
27-
var config = Configuration.Default.WithCss();
28+
29+
// Create a custom config with a parser to allow access to the source reference from the AST.
30+
var config = Configuration.Default
31+
.WithCss()
32+
.With<IHtmlParser>(ctx => new HtmlParser(new HtmlParserOptions
33+
{
34+
IsKeepingSourceReferences = true,
35+
IsScripting = ctx?.IsScripting() ?? false
36+
}, ctx));
37+
2838
_context = BrowsingContext.New(config);
29-
_htmlParser = _context.GetService<IHtmlParser>() ?? throw new InvalidOperationException("No IHtmlParser registered in the default AngleSharp browsing context.");
39+
_htmlParser = _context.GetService<IHtmlParser>()
40+
?? throw new InvalidOperationException("No IHtmlParser registered in the default AngleSharp browsing context.");
3041
_document = _context.OpenNewAsync().Result;
3142
}
3243

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,15 @@ public static IDiffingStrategyCollection AddElementComparer(this IDiffingStrateg
1414
return builder;
1515
}
1616

17+
/// <summary>
18+
/// Adds an element comparer that ensures element tags are closed the same way, e.g. `&lt;br&gt;` and `&lt;br /&gt;` would not be considered equal, but `&lt;br&gt;` and `&lt;br&gt;` would be.
19+
/// </summary>
20+
public static IDiffingStrategyCollection AddElementClosingComparer(this IDiffingStrategyCollection builder)
21+
{
22+
builder.AddComparer(ElementClosingComparer.Compare, StrategyType.Generalized);
23+
return builder;
24+
}
25+
1726
/// <summary>
1827
/// Enables the CSS-selector matcher strategy during diffing.
1928
/// </summary>
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
using AngleSharp.Diffing.Core;
2+
using AngleSharp.Dom;
3+
using AngleSharp.Html.Parser.Tokens;
4+
5+
namespace AngleSharp.Diffing.Strategies.ElementStrategies
6+
{
7+
/// <summary>
8+
/// Represents the element closing comparer strategy.
9+
/// </summary>
10+
public static class ElementClosingComparer
11+
{
12+
/// <summary>
13+
/// The element comparer closing strategy.
14+
/// </summary>
15+
public static CompareResult Compare(in Comparison comparison, CompareResult currentDecision)
16+
{
17+
if (currentDecision == CompareResult.Skip)
18+
return currentDecision;
19+
20+
if (comparison.Test.Node is not IElement testElement || testElement.SourceReference is not HtmlTagToken testTag)
21+
return currentDecision;
22+
23+
if (comparison.Control.Node is not IElement controlElement || controlElement.SourceReference is not HtmlTagToken controlTag)
24+
return currentDecision;
25+
26+
return testTag.IsSelfClosing == controlTag.IsSelfClosing ? CompareResult.Same : CompareResult.Different;
27+
}
28+
}
29+
}

0 commit comments

Comments
 (0)