1+ package scala .xml
2+
3+ import scala .xml .transform ._
4+ import org .junit .Test
5+ import org .junit .Assert .assertTrue
6+ import org .junit .Assert .assertEquals
7+ import org .junit .experimental .theories .Theories
8+ import org .junit .experimental .theories .Theory
9+ import org .junit .experimental .theories .DataPoints
10+ import org .junit .runner .RunWith
11+ /**
12+ * This test verify that after the tranform, the resultant xml node
13+ * uses as many old nodes as possible.
14+ *
15+ * Three transformers class for case -
16+ * One for orginal, one for modified, and one proposed which shows
17+ * all are equivalent when it comes to reusing as many nodes as possible
18+ */
19+ object ReuseNodesTest {
20+
21+ class OriginalTranformr (rules : RewriteRule * ) extends RuleTransformer (rules:_* ) {
22+ override def transform (ns : Seq [Node ]): Seq [Node ] = {
23+ val xs = ns.toStream map transform
24+ val (xs1, xs2) = xs zip ns span { case (x, n) => unchanged(n, x) }
25+
26+ if (xs2.isEmpty) ns
27+ else (xs1 map (_._2)) ++ xs2.head._1 ++ transform(ns drop (xs1.length + 1 ))
28+ }
29+ override def transform (n: Node ): Seq [Node ] = super .transform(n)
30+ }
31+
32+ class ModifiedTranformr (rules : RewriteRule * ) extends RuleTransformer (rules:_* ) {
33+ override def transform (ns : Seq [Node ]): Seq [Node ] = {
34+ val changed = ns flatMap transform
35+
36+ if (changed.length != ns.length || (changed, ns).zipped.exists(_ != _)) changed
37+ else ns
38+ }
39+ override def transform (n: Node ): Seq [Node ] = super .transform(n)
40+ }
41+
42+ class AlternateTranformr (rules : RewriteRule * ) extends RuleTransformer (rules:_* ) {
43+ override def transform (ns : Seq [Node ]): Seq [Node ] = {
44+ val xs = ns.toStream map transform
45+ val (xs1, xs2) = xs zip ns span { case (x, n) => unchanged(n, x) }
46+
47+ if (xs2.isEmpty) ns
48+ else (xs1 map (_._2)) ++ xs2.head._1 ++ transform(ns drop (xs1.length + 1 ))
49+ }
50+ override def transform (n: Node ): Seq [Node ] = super .transform(n)
51+ }
52+
53+ def rewriteRule = new RewriteRule {
54+ override def transform (n : Node ): NodeSeq = n match {
55+ case n if n.label == " change" => Elem (
56+ n.prefix, " changed" , n.attributes, n.scope, n.child.isEmpty, n.child : _* )
57+ case _ => n
58+ }
59+ }
60+
61+ @ DataPoints
62+ def tranformers () = Array (
63+ new OriginalTranformr (rewriteRule),
64+ new ModifiedTranformr (rewriteRule),
65+ new AlternateTranformr (rewriteRule))
66+ }
67+
68+ @ RunWith (classOf [Theories ])
69+ class ReuseNodesTest {
70+
71+ @ Theory
72+ def transformReferentialEquality (rt: RuleTransformer ) = {
73+ val original = <p ><lost /></p >
74+ val tranformed = rt.transform(original)
75+ assertTrue(original eq tranformed)
76+ }
77+
78+ @ Theory
79+ def transformReferentialEqualityOnly (rt: RuleTransformer ) = {
80+ val original = <changed ><change ><lost /><a ><b ><c /></b ></a ></change ><a ><b ><c /></b ></a ></changed >
81+ val transformed = rt.transform(original)
82+ recursiveAssert(original,transformed)
83+ }
84+
85+ def recursiveAssert (original: Seq [Node ], transformed: Seq [Node ]): Unit = {
86+ (original.toList,transformed.toList) match {
87+ case (Nil , Nil ) => {}
88+ case (x:: xs,y:: ys) => {
89+ recursiveAssert(x,y)
90+ recursiveAssert(xs,ys)
91+ }
92+ }
93+ }
94+
95+ def recursiveAssert (original: Node , transformed: Node ): Unit = {
96+ transformed.label match {
97+ case " changed" => // do nothing expect this node to be changed
98+ recursiveAssert(original.child,transformed.child)
99+ case _ => {
100+ assertTrue(original eq transformed)
101+ // No need to check for childrens, node being immuatable
102+ // childs can't be differnt if parents are refertially equal
103+ }
104+ }
105+ }
106+ }
0 commit comments