Skip to content

Commit 498445d

Browse files
feat: implementation of OrderingStyleAttributeComparer.cs
Closes #17
1 parent 667b247 commit 498445d

File tree

5 files changed

+147
-2
lines changed

5 files changed

+147
-2
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
# 0.18.0
2+
3+
Released on Tuesday, February 15, 2022.
4+
5+
- Added a new style comparer which orders the styles before comparing them. By [@grishat](https://github.com/SebastianStehle).
6+
17
# 0.17.0
28

39
Released on Wednesday, September 8, 2021.
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
using AngleSharp.Diffing.Core;
2+
using Shouldly;
3+
using Xunit;
4+
5+
namespace AngleSharp.Diffing.Strategies.AttributeStrategies
6+
{
7+
public class OrderingStyleAttributeComparerTest : DiffingTestBase
8+
{
9+
public OrderingStyleAttributeComparerTest(DiffingTestFixture fixture) : base(fixture)
10+
{
11+
}
12+
13+
[Fact(DisplayName = "When attribute is not style the current decision is used")]
14+
public void Test001()
15+
{
16+
var comparison = ToAttributeComparison(@"<p foo=""bar"">", "foo", @"<p foo=""zab"">", "foo");
17+
StyleAttributeComparer.Compare(comparison, CompareResult.Different).ShouldBe(CompareResult.Different);
18+
StyleAttributeComparer.Compare(comparison, CompareResult.Same).ShouldBe(CompareResult.Same);
19+
StyleAttributeComparer.Compare(comparison, CompareResult.Skip).ShouldBe(CompareResult.Skip);
20+
}
21+
22+
[Theory(DisplayName = "When style attributes has different values then Different is returned")]
23+
[InlineData(@"<p style=""color: red"">", @"<p style=""color: black"">")]
24+
[InlineData(@"<p style=""color: red"">", @"<p style=""text-align:center"">")]
25+
[InlineData(@"<p style=""color: red"">", @"<p style=""color: red;text-align:center"">")]
26+
[InlineData(@"<p style=""color: red;text-align:center"">", @"<p style=""color: red"">")]
27+
public void Test002(string control, string test)
28+
{
29+
var comparison = ToAttributeComparison(control, "style", test, "style");
30+
OrderingStyleAttributeComparer.Compare(comparison, CompareResult.Unknown).ShouldBe(CompareResult.Different);
31+
}
32+
33+
[Fact(DisplayName = "Comparer should correctly ignore insignificant whitespace")]
34+
public void Test003()
35+
{
36+
var comparison = ToAttributeComparison(@"<p style=""color: red"">", "style", @"<p style=""color:red"">", "style");
37+
OrderingStyleAttributeComparer.Compare(comparison, CompareResult.Unknown).ShouldBe(CompareResult.Same);
38+
}
39+
40+
[Theory(DisplayName = "Comparer should ignore trailing semi colons")]
41+
[InlineData(@"<p style=""color:red;"">", @"<p style=""color:red"">")]
42+
[InlineData(@"<p style=""color:red"">", @"<p style=""color:red;"">")]
43+
public void Test004(string control, string test)
44+
{
45+
var comparison = ToAttributeComparison(control, "style", test, "style");
46+
OrderingStyleAttributeComparer.Compare(comparison, CompareResult.Unknown).ShouldBe(CompareResult.Same);
47+
}
48+
49+
[Theory(DisplayName = "Comparer should ignore different order")]
50+
[InlineData(@"<p style=""alpha:0;border:0;color:red;"">", @"<p style=""color:red;border:0;alpha:0"">")]
51+
[InlineData(@"<p style=""alpha:0;border:0;color:red;"">", @"<p style=""border:0;color:red;alpha:0"">")]
52+
public void Test005(string control, string test)
53+
{
54+
var comparison = ToAttributeComparison(control, "style", test, "style");
55+
OrderingStyleAttributeComparer.Compare(comparison, CompareResult.Unknown).ShouldBe(CompareResult.Same);
56+
}
57+
58+
[Theory(DisplayName = "Comparer should ignore different order inside style")]
59+
[InlineData(@"<p style=""border:1px solid black"">", @"<p style=""border:solid 1px black"">")]
60+
public void Test006(string control, string test)
61+
{
62+
var comparison = ToAttributeComparison(control, "style", test, "style");
63+
OrderingStyleAttributeComparer.Compare(comparison, CompareResult.Unknown).ShouldBe(CompareResult.Same);
64+
}
65+
}
66+
}

src/AngleSharp.Diffing.Tests/Strategies/AttributeStrategies/StyleAttributeComparerTest.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,5 +45,13 @@ public void Test004(string control, string test)
4545
var comparison = ToAttributeComparison(control, "style", test, "style");
4646
StyleAttributeComparer.Compare(comparison, CompareResult.Unknown).ShouldBe(CompareResult.Same);
4747
}
48+
49+
[Theory(DisplayName = "Comparer should ignore different order inside style")]
50+
[InlineData(@"<p style=""border:1px solid black"">", @"<p style=""border:solid 1px black"">")]
51+
public void Test005(string control, string test)
52+
{
53+
var comparison = ToAttributeComparison(control, "style", test, "style");
54+
StyleAttributeComparer.Compare(comparison, CompareResult.Unknown).ShouldBe(CompareResult.Same);
55+
}
4856
}
4957
}

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

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,9 +58,19 @@ public static IDiffingStrategyCollection AddBooleanAttributeComparer(this IDiffi
5858
/// <summary>
5959
/// Enables the special style attributes comparer during diffing.
6060
/// </summary>
61-
public static IDiffingStrategyCollection AddStyleAttributeComparer(this IDiffingStrategyCollection builder)
61+
/// <param name="ignoreOrder">Then the flag is true, the comparer orders the styles in ascending order before comparing them.
62+
/// Therefore two styles are identical if they have the same properties and values but in different order.
63+
/// </param>
64+
public static IDiffingStrategyCollection AddStyleAttributeComparer(this IDiffingStrategyCollection builder, bool ignoreOrder = false)
6265
{
63-
builder.AddComparer(StyleAttributeComparer.Compare, StrategyType.Specialized);
66+
if (ignoreOrder)
67+
{
68+
builder.AddComparer(OrderingStyleAttributeComparer.Compare, StrategyType.Specialized);
69+
}
70+
else
71+
{
72+
builder.AddComparer(StyleAttributeComparer.Compare, StrategyType.Specialized);
73+
}
6474
return builder;
6575
}
6676
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
using System;
2+
using System.Linq;
3+
4+
using AngleSharp.Css.Dom;
5+
using AngleSharp.Diffing.Core;
6+
using AngleSharp.Dom;
7+
8+
namespace AngleSharp.Diffing.Strategies.AttributeStrategies
9+
{
10+
/// <summary>
11+
/// Represents the style attribute comparer strategy which orders the styles before comparing them.
12+
/// </summary>
13+
public static class OrderingStyleAttributeComparer
14+
{
15+
/// <summary>
16+
/// The style attribute comparer strategy.
17+
/// </summary>
18+
public static CompareResult Compare(in AttributeComparison comparison, CompareResult currentDecision)
19+
{
20+
if (currentDecision.IsSameOrSkip())
21+
return currentDecision;
22+
23+
return IsStyleAttributeComparison(comparison)
24+
? CompareElementStyle(comparison)
25+
: currentDecision;
26+
}
27+
28+
private static CompareResult CompareElementStyle(in AttributeComparison comparison)
29+
{
30+
var (ctrlElm, testElm) = comparison.GetAttributeElements();
31+
var ctrlStyle = ctrlElm.GetStyle();
32+
var testStyle = testElm.GetStyle();
33+
return CompareCssStyleDeclarations(ctrlStyle, testStyle)
34+
? CompareResult.Same
35+
: CompareResult.Different;
36+
}
37+
38+
private static bool IsStyleAttributeComparison(in AttributeComparison comparison)
39+
{
40+
return comparison.Control.Attribute.Name.Equals(AttributeNames.Style, StringComparison.Ordinal) &&
41+
comparison.Test.Attribute.Name.Equals(AttributeNames.Style, StringComparison.Ordinal);
42+
}
43+
44+
private static bool CompareCssStyleDeclarations(ICssStyleDeclaration control, ICssStyleDeclaration test)
45+
{
46+
if (control.Length != test.Length)
47+
return false;
48+
49+
var orderedControl = control.CssText.Split(';').Select(x => x.Trim()).OrderBy(x => x);
50+
var orderedTest = test.CssText.Split(';').Select(x => x.Trim()).OrderBy(x => x);
51+
52+
return orderedControl.SequenceEqual(orderedTest, StringComparer.Ordinal);
53+
}
54+
}
55+
}

0 commit comments

Comments
 (0)