Skip to content

Commit 5efd0da

Browse files
committed
Add comparison of children & text
1 parent 219d5b0 commit 5efd0da

File tree

3 files changed

+80
-14
lines changed

3 files changed

+80
-14
lines changed

xml-compare/src/main/scala/software/purpledragon/xml/compare/XmlCompare.scala

Lines changed: 40 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,19 @@ package software.purpledragon.xml.compare
33
import software.purpledragon.xml.compare.options.DiffOption._
44
import software.purpledragon.xml.compare.options.DiffOptions
55

6-
import scala.xml.Node
6+
import scala.xml.{Node, Text}
77

88
object XmlCompare {
99
private type Check = (Node, Node, DiffOptions) => XmlDiff
1010

1111
val DefaultOptions: DiffOptions = Set(IgnorePrefix)
1212

1313
def compare(left: Node, right: Node, options: DiffOptions = DefaultOptions): XmlDiff = {
14-
val checks: Seq[Check] = Seq(compareNamespace)
14+
val checks: Seq[Check] = Seq(
15+
compareNamespace,
16+
compareText,
17+
compareChildren
18+
)
1519

1620
checks.foldLeft[XmlDiff](XmlEqual) { (status, check) =>
1721
if (!status.isEqual) {
@@ -25,13 +29,44 @@ object XmlCompare {
2529

2630
private def compareNamespace(left: Node, right: Node, options: DiffOptions): XmlDiff = {
2731
if (left.label != right.label) {
28-
XmlDiffers("different label")
32+
XmlDiffers("different label", left.label, right.label)
2933
} else if (left.namespace != right.namespace) {
30-
XmlDiffers("different namespace")
34+
XmlDiffers("different namespace", left.namespace, right.namespace)
3135
} else if (left.prefix != right.prefix && !options.contains(IgnorePrefix)) {
32-
XmlDiffers("different prefix")
36+
XmlDiffers("different prefix", left.prefix, right.prefix)
3337
} else {
3438
XmlEqual
3539
}
3640
}
41+
42+
private def compareText(left: Node, right: Node, options: DiffOptions): XmlDiff = {
43+
val leftText = left.child.collect({case t: Text => t}).map(_.text.trim).mkString
44+
val rightText = right.child.collect({case t: Text => t}).map(_.text.trim).mkString
45+
46+
if (leftText != rightText) {
47+
XmlDiffers("different text", leftText, rightText)
48+
} else {
49+
XmlEqual
50+
}
51+
}
52+
53+
private def compareChildren(left: Node, right: Node, options: DiffOptions): XmlDiff = {
54+
val leftChildren = left.child.filterNot(_.isInstanceOf[Text])
55+
val rightChildren = right.child.filterNot(_.isInstanceOf[Text])
56+
57+
if (leftChildren.size != rightChildren.size) {
58+
XmlDiffers("child count", leftChildren.size, rightChildren.size)
59+
} else {
60+
val meh: Seq[(Node, Node)] = leftChildren.zip(rightChildren)
61+
62+
meh.foldLeft[XmlDiff](XmlEqual) { case (status, (leftChild, rightChild)) =>
63+
if (!status.isEqual) {
64+
// already failed
65+
status
66+
} else {
67+
compare(leftChild, rightChild, options)
68+
}
69+
}
70+
}
71+
}
3772
}

xml-compare/src/main/scala/software/purpledragon/xml/compare/XmlDiff.scala

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,10 @@ sealed trait XmlDiff {
66

77
object XmlEqual extends XmlDiff {
88
override def isEqual: Boolean = true
9+
10+
override def toString: String = "XmlEqual"
911
}
1012

11-
case class XmlDiffers(reason: String) extends XmlDiff {
13+
case class XmlDiffers(reason: String, left: Any, right: Any) extends XmlDiff {
1214
override def isEqual: Boolean = false
1315
}

xml-compare/src/test/scala/software/purpledragon/xml/compare/XmlCompareSpec.scala

Lines changed: 37 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,16 @@ import org.scalatest.{FlatSpec, Matchers}
44

55
class XmlCompareSpec extends FlatSpec with Matchers {
66

7-
"comparing empty" should "match same element name" in {
7+
"compare with defaults" should "match same empty element" in {
88
XmlCompare.compare(<test/>, <test/>) shouldBe XmlEqual
99
}
1010

11-
it should "blah" in {
11+
it should "match empty elements ignoring collapsed" in {
1212
XmlCompare.compare(<test/>, <test></test>) shouldBe XmlEqual
1313
}
1414

15-
it should "not-match" in {
16-
XmlCompare.compare(<test/>, <foo/>) shouldBe XmlDiffers("different label")
15+
it should "not-match different label" in {
16+
XmlCompare.compare(<test/>, <foo/>) shouldBe XmlDiffers("different label", "test", "foo")
1717
}
1818

1919
it should "match same namespaces" in {
@@ -26,15 +26,44 @@ class XmlCompareSpec extends FlatSpec with Matchers {
2626
<e:test xmlns:e="http://example.com"/>) shouldBe XmlEqual
2727
}
2828

29-
it should "not-match different namespace prefix (with IgnorePrefix disabled)" in {
29+
it should "not-match different namespace url" in {
3030
XmlCompare.compare(
3131
<t:test xmlns:t="http://example.com"/>,
32-
<e:test xmlns:e="http://example.com"/>, Set.empty) shouldBe XmlDiffers("different prefix")
32+
<t:test xmlns:t="http://foo.com"/>) shouldBe
33+
XmlDiffers(
34+
"different namespace",
35+
"http://example.com",
36+
"http://foo.com")
3337
}
3438

35-
it should "not-match different namespace url" in {
39+
it should "match with same single child" in {
40+
XmlCompare.compare(<test><test2/></test>, <test><test2/></test>) shouldBe XmlEqual
41+
}
42+
43+
it should "not-match with different single child" in {
44+
XmlCompare.compare(<test><test2/></test>, <test><foo/></test>) shouldBe XmlDiffers("different label", "test2", "foo")
45+
}
46+
47+
it should "match with same text contents" in {
48+
XmlCompare.compare(<test>contents</test>, <test>contents</test>) shouldBe XmlEqual
49+
}
50+
51+
it should "not-match different text contents" in {
52+
XmlCompare.compare(<test>contents</test>, <test/>) shouldBe XmlDiffers("different text", "contents", "")
53+
}
54+
55+
it should "match with text content differing only by whitespace" in {
56+
XmlCompare.compare(<test>contents </test>, <test>contents</test>) shouldBe XmlEqual
57+
}
58+
59+
it should "match with child & text content in different order" in {
60+
XmlCompare.compare(<test><test2/>contents</test>, <test>contents<test2/></test>) shouldBe XmlEqual
61+
}
62+
63+
64+
"compare without IgnorePrefix" should "not-match different namespace prefix" in {
3665
XmlCompare.compare(
3766
<t:test xmlns:t="http://example.com"/>,
38-
<t:test xmlns:t="http://foo.com"/>) shouldBe XmlDiffers("different namespace")
67+
<e:test xmlns:e="http://example.com"/>, Set.empty) shouldBe XmlDiffers("different prefix", "t", "e")
3968
}
4069
}

0 commit comments

Comments
 (0)