From bcb83f308a7cf6c635aaf93442517ef5f5765b5a Mon Sep 17 00:00:00 2001 From: "Aaron S. Hawley" Date: Tue, 21 Jan 2020 23:08:49 -0500 Subject: [PATCH 1/3] 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 e7239358da50da6c7fe34de071ed772fc62be698 Mon Sep 17 00:00:00 2001 From: "Aaron S. Hawley" Date: Tue, 21 Jan 2020 23:31:43 -0500 Subject: [PATCH 2/3] 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 df7d18eb85aa7c3880b60de1c88a803f0412372b Mon Sep 17 00:00:00 2001 From: "Aaron S. Hawley" Date: Fri, 31 Jan 2020 06:32:54 -0500 Subject: [PATCH 3/3] 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) + } }