From f53b0343221b13f361fd2732d93aeb617b789429 Mon Sep 17 00:00:00 2001 From: "Aaron S. Hawley" Date: Tue, 21 Jan 2020 23:08:49 -0500 Subject: [PATCH 1/4] Fix 2.13 collections methods for NodeSeq --- .../scala/xml/ScalaVersionSpecific.scala | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/shared/src/main/scala-2.13+/scala/xml/ScalaVersionSpecific.scala b/shared/src/main/scala-2.13+/scala/xml/ScalaVersionSpecific.scala index bd2eb820d..4258c100f 100644 --- a/shared/src/main/scala-2.13+/scala/xml/ScalaVersionSpecific.scala +++ b/shared/src/main/scala-2.13+/scala/xml/ScalaVersionSpecific.scala @@ -1,7 +1,7 @@ package scala.xml import scala.collection.immutable.StrictOptimizedSeqOps -import scala.collection.{SeqOps, IterableOnce, immutable, mutable} +import scala.collection.{View, SeqOps, IterableOnce, immutable, mutable} import scala.collection.BuildFrom import scala.collection.mutable.Builder @@ -20,6 +20,21 @@ private[xml] trait ScalaVersionSpecificNodeSeq override def fromSpecific(coll: IterableOnce[Node]): NodeSeq = (NodeSeq.newBuilder ++= coll).result() override def newSpecificBuilder: mutable.Builder[Node, NodeSeq] = NodeSeq.newBuilder override def empty: NodeSeq = NodeSeq.Empty + def concat(suffix: IterableOnce[Node]): NodeSeq = + fromSpecific(iterator ++ suffix.iterator) + @inline final def ++ (suffix: Seq[Node]): NodeSeq = concat(suffix) + def appended(base: Node): NodeSeq = + fromSpecific(new View.Appended(this, base)) + def appendedAll(suffix: IterableOnce[Node]): NodeSeq = + concat(suffix) + def prepended(base: Node): NodeSeq = + fromSpecific(new View.Prepended(base, this)) + def prependedAll(prefix: IterableOnce[Node]): NodeSeq = + fromSpecific(prefix.iterator ++ iterator) + def map(f: Node => Node): NodeSeq = + fromSpecific(new View.Map(this, f)) + def flatMap(f: Node => IterableOnce[Node]): NodeSeq = + fromSpecific(new View.FlatMap(this, f)) } private[xml] trait ScalaVersionSpecificNodeBuffer { self: NodeBuffer => From ef25dc3850b2526f132fea178ad803b374dd1a02 Mon Sep 17 00:00:00 2001 From: "Aaron S. Hawley" Date: Tue, 21 Jan 2020 23:31:43 -0500 Subject: [PATCH 2/4] Add test of issue 392 --- .../test/scala/scala/xml/NodeSeqTest.scala | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 shared/src/test/scala/scala/xml/NodeSeqTest.scala diff --git a/shared/src/test/scala/scala/xml/NodeSeqTest.scala b/shared/src/test/scala/scala/xml/NodeSeqTest.scala new file mode 100644 index 000000000..08b7c0d79 --- /dev/null +++ b/shared/src/test/scala/scala/xml/NodeSeqTest.scala @@ -0,0 +1,23 @@ +package scala.xml + +import scala.xml.NodeSeq.seqToNodeSeq + +import org.junit.Test +import org.junit.Assert.assertEquals +import org.junit.Assert.fail + +class NodeSeqTest { + + @Test + def testAppend: Unit = { // Bug #392. + val a: NodeSeq = Hello + val b = Hi + a ++ Hi match { + case res: NodeSeq => assertEquals(2, res.size) + case res: Seq[Node] => fail("Should be NodeSeq") // Unreachable code? + } + val res: NodeSeq = a ++ b + val exp = NodeSeq.fromSeq(Seq(Hello, Hi)) + assertEquals(exp, res) + } +} From edfd90c796e27571254320da8c2eb13e11b0a634 Mon Sep 17 00:00:00 2001 From: "Aaron S. Hawley" Date: Fri, 31 Jan 2020 06:32:54 -0500 Subject: [PATCH 3/4] Add further tests of NodeSeq --- .../test/scala/scala/xml/NodeSeqTest.scala | 80 +++++++++++++++++++ 1 file changed, 80 insertions(+) diff --git a/shared/src/test/scala/scala/xml/NodeSeqTest.scala b/shared/src/test/scala/scala/xml/NodeSeqTest.scala index 08b7c0d79..d8ba4cc70 100644 --- a/shared/src/test/scala/scala/xml/NodeSeqTest.scala +++ b/shared/src/test/scala/scala/xml/NodeSeqTest.scala @@ -20,4 +20,84 @@ class NodeSeqTest { val exp = NodeSeq.fromSeq(Seq(Hello, Hi)) assertEquals(exp, res) } + + @Test + def testAppendedAll: Unit = { // Bug #392. + val a: NodeSeq = Hello + val b = Hi + a :+ Hi match { + case res: Seq[Node] => assertEquals(2, res.size) + case res: NodeSeq => fail("Should be Seq[Node]") // Unreachable code? + } + val res: NodeSeq = a :+ b + val exp = NodeSeq.fromSeq(Seq(Hello, Hi)) + assertEquals(exp, res) + } + + @Test + def testPrepended: Unit = { + val a: NodeSeq = Hello + val b = Hi + a +: Hi match { + case res: Seq[NodeSeq] => assertEquals(2, res.size) + case res: NodeSeq => fail("Should be NodeSeq was Seq[Node]") // Unreachable code? + } + val res: Seq[NodeSeq] = a +: b + val exp = HelloHi + assertEquals(exp, res) + } + + @Test + def testPrependedAll: Unit = { + val a: NodeSeq = Hello + val b = Hi + val c = Hey + a ++: Hi ++: Hey match { + case res: Seq[Node] => assertEquals(3, res.size) + case res: NodeSeq => fail("Should be Seq[Node]") // Unreachable code? + } + val res: NodeSeq = a ++: b ++: c + val exp = NodeSeq.fromSeq(Seq(Hello, Hi, Hey)) + assertEquals(exp, res) + } + + @Test + def testMap: Unit = { + val a: NodeSeq = Hello + val exp: NodeSeq = Seq(Hi) + assertEquals(exp, a.map(_ => Hi)) + assertEquals(exp, for { _ <- a } yield { Hi }) + } + + @Test + def testFlatMap: Unit = { + val a: NodeSeq = Hello + val exp: NodeSeq = Seq(Hi) + assertEquals(exp, a.flatMap(_ => Seq(Hi))) + assertEquals(exp, for { b <- a; _ <- b } yield { Hi }) + assertEquals(exp, for { b <- a; c <- b; _ <- c } yield { Hi }) + } + + @Test + def testStringProjection: Unit = { + val a = + + b + + + e + e + + c + + + val res = for { + b <- a \ "b" + c <- b.child + e <- (c \ "e").headOption + } yield { + e.text.trim + } + assertEquals(Seq("e"), res) + } } From 0a1578d0d80b492a419ed2355528d1bf843f24db Mon Sep 17 00:00:00 2001 From: "Aaron S. Hawley" Date: Fri, 31 Jan 2020 15:37:40 -0500 Subject: [PATCH 4/4] Fix NodeSeqTest for dotty 0.21.0-RC1 -- [E008] Member Not Found Error: shared/src/test/scala/scala/xml/NodeSeqTest.scala:47:4 46 | val exp = HelloHi 47 | assertEquals(exp, res) | ^ | value assertEquals is not a member of scala.xml.NodeBuffer -- [E045] Cyclic Error: shared/src/test/scala/scala/xml/NodeSeqTest.scala:47:17 47 | assertEquals(exp, res) | ^ | Recursive value exp needs type --- .../test/scala/scala/xml/NodeSeqTest.scala | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/shared/src/test/scala/scala/xml/NodeSeqTest.scala b/shared/src/test/scala/scala/xml/NodeSeqTest.scala index d8ba4cc70..7f80b3366 100644 --- a/shared/src/test/scala/scala/xml/NodeSeqTest.scala +++ b/shared/src/test/scala/scala/xml/NodeSeqTest.scala @@ -13,8 +13,8 @@ class NodeSeqTest { val a: NodeSeq = Hello val b = Hi a ++ Hi match { - case res: NodeSeq => assertEquals(2, res.size) - case res: Seq[Node] => fail("Should be NodeSeq") // Unreachable code? + case res: NodeSeq => assertEquals(2, res.size.toLong) + case res: Seq[Node] => fail("Should be NodeSeq was Seq[Node]") // Unreachable code? } val res: NodeSeq = a ++ b val exp = NodeSeq.fromSeq(Seq(Hello, Hi)) @@ -26,8 +26,8 @@ class NodeSeqTest { val a: NodeSeq = Hello val b = Hi a :+ Hi match { - case res: Seq[Node] => assertEquals(2, res.size) - case res: NodeSeq => fail("Should be Seq[Node]") // Unreachable code? + case res: Seq[Node] => assertEquals(2, res.size.toLong) + case res: NodeSeq => fail("Should be Seq[Node] was NodeSeq") // Unreachable code? } val res: NodeSeq = a :+ b val exp = NodeSeq.fromSeq(Seq(Hello, Hi)) @@ -39,11 +39,13 @@ class NodeSeqTest { val a: NodeSeq = Hello val b = Hi a +: Hi match { - case res: Seq[NodeSeq] => assertEquals(2, res.size) - case res: NodeSeq => fail("Should be NodeSeq was Seq[Node]") // Unreachable code? + case res: Seq[Node] => assertEquals(2, res.size.toLong) + case res: NodeSeq => fail("Should be Seq[Node] was NodeSeq") // Unreachable code? } val res: Seq[NodeSeq] = a +: b - val exp = HelloHi + val exp: NodeBuffer = { + HelloHi + } assertEquals(exp, res) } @@ -53,8 +55,8 @@ class NodeSeqTest { val b = Hi val c = Hey a ++: Hi ++: Hey match { - case res: Seq[Node] => assertEquals(3, res.size) - case res: NodeSeq => fail("Should be Seq[Node]") // Unreachable code? + case res: Seq[Node] => assertEquals(3, res.size.toLong) + case res: NodeSeq => fail("Should be Seq[Node] was NodeSeq") // Unreachable code? } val res: NodeSeq = a ++: b ++: c val exp = NodeSeq.fromSeq(Seq(Hello, Hi, Hey))