diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 28d8b9f42d..73fcc35f28 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -16,7 +16,10 @@ jobs: fail-fast: false matrix: java: [11, 17, 21] - scala: [2.13.18, 3.3.7] + scala: [3.3.7, 3.8.3] + exclude: + - java: 11 + scala: 3.8.3 runs-on: ubuntu-latest steps: - name: Checkout diff --git a/README.md b/README.md index 884f06c7f2..a5fcc1fc88 100644 --- a/README.md +++ b/README.md @@ -118,9 +118,7 @@ Add Lift to your `pom.xml` like so: 3.3.0 -Where `${scala.version}` is `2.13` for the 4.x series. Individual patch releases of the Scala compiler -(e.g. 2.12.2) are binary compatible with everything in their release series, so you only need the -first two version parts. +Where `${scala.version}` is `3` for the 5.x series. You can learn more about Maven integration [on the wiki](http://www.assembla.com/wiki/show/liftweb/Using_Maven). diff --git a/build.sbt b/build.sbt index b60ac47ffc..698c2c0fba 100644 --- a/build.sbt +++ b/build.sbt @@ -8,11 +8,11 @@ ThisBuild / licenses += ("Apache License, Version 2.0", url("https:/ ThisBuild / startYear := Some(2006) ThisBuild / organizationName := "Lift Committers and Contributors" -val scala213Version = "2.13.18" val scala3LTSVersion = "3.3.7" +val scala3LatestVersion = "3.8.3" -ThisBuild / scalaVersion := scala213Version -ThisBuild / crossScalaVersions := Seq(scala213Version, scala3LTSVersion) +ThisBuild / scalaVersion := scala3LTSVersion +ThisBuild / crossScalaVersions := Seq(scala3LTSVersion, scala3LatestVersion) ThisBuild / libraryDependencies ++= Seq( specs2(scalaVersion.value), @@ -21,7 +21,7 @@ ThisBuild / libraryDependencies ++= Seq( scalactic, scalatest ) -ThisBuild / libraryDependencies ++= specs2XmlDeps(scalaVersion.value) +ThisBuild / libraryDependencies += specs2Xml ThisBuild / scalacOptions ++= Seq("-deprecation") @@ -64,10 +64,7 @@ lazy val common = coreProject("common") .settings( description := "Common Libraries and Utilities", - libraryDependencies ++= Seq(slf4j_api, logback, slf4j_log4j12, scala_xml, scala_parser, scalamock, mockito_scalatest(scalaVersion.value)), - Test / unmanagedSourceDirectories += { - (Test / sourceDirectory).value / ("scala-" + scalaBinaryVersion.value) - } + libraryDependencies ++= Seq(slf4j_api, logback, slf4j_log4j12, scala_xml, scala_parser, scalamock, mockito_scalatest(scalaVersion.value)) ) lazy val actor = @@ -75,10 +72,7 @@ lazy val actor = .dependsOn(common) .settings( description := "Simple Actor", - Test / parallelExecution := false, - Test / unmanagedSourceDirectories += { - (Test / sourceDirectory).value / ("scala-" + scalaBinaryVersion.value) - } + Test / parallelExecution := false ) lazy val markdown = @@ -109,10 +103,7 @@ lazy val util = htmlparser, xerces, json4s_native, - ), - Test / unmanagedSourceDirectories += { - (Test / sourceDirectory).value / ("scala-" + scalaBinaryVersion.value) - } + ) ) // Web Projects @@ -125,10 +116,7 @@ lazy val testkit = .dependsOn(util) .settings( description := "Testkit for Webkit Library", - libraryDependencies ++= Seq(commons_httpclient, servlet_api, json4s_native, json4s_xml), - Test / unmanagedSourceDirectories += { - (Test / sourceDirectory).value / ("scala-" + scalaBinaryVersion.value) - } + libraryDependencies ++= Seq(commons_httpclient, servlet_api, json4s_native, json4s_xml) ) lazy val webkit = @@ -150,26 +138,14 @@ lazy val webkit = jquery, jasmineCore, jasmineAjax, - specs2Mock(scalaVersion.value) + specs2Mock ), - libraryDependencies ++= { - CrossVersion.partialVersion(scalaVersion.value) match { - case Some((2, scalaMajor)) if scalaMajor >= 13 => Seq(scala_parallel_collections) - case _ => Seq.empty - } - }, Test / initialize := { System.setProperty( "net.liftweb.webapptest.src.test.webapp", ((Test / sourceDirectory).value / "webapp").absString ) }, - Compile / unmanagedSourceDirectories += { - (Compile / sourceDirectory).value / ("scala_" + scalaBinaryVersion.value) - }, - Test / unmanagedSourceDirectories += { - (Test / sourceDirectory).value / ("scala_" + scalaBinaryVersion.value) - }, Compile / compile := (Compile / compile).dependsOn(WebKeys.assets).value, /** * This is to ensure that the tests in net.liftweb.webapptest run last diff --git a/core/actor/src/test/scala-2.13/net/liftweb/actor/ActorSpec.scala b/core/actor/src/test/scala-2.13/net/liftweb/actor/ActorSpec.scala deleted file mode 100644 index 1884ef480a..0000000000 --- a/core/actor/src/test/scala-2.13/net/liftweb/actor/ActorSpec.scala +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright 2011-2026 Lift Committers and Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package net.liftweb -package actor - -import org.specs2.mutable.Specification -import scala.concurrent.duration._ -import common._ - - -/** - * Systems under specification for Lift Actor. - */ -class ActorSpec extends Specification { - "Actor Specification".title - sequential - - "A Scala Actor" should { - "support common features" in commonFeatures(new MyScalaActor) - } - - private def commonFeatures(actor: LiftActor) = { - sequential - - "allow setting and getting of a value" in { - val a = actor - a ! Set(33) - a !? Get() - (a.!?(50, Get())) must be_==(Full(Answer(33))).eventually(900, 100.milliseconds) - } - - "allow setting and getting of a value with subclass of Get()" in { - val a = actor - a ! Set(33) - a ! new FunnyGet() - (a.!?(50L, new FunnyGet())) must be_==(Full(Answer(33))).eventually(900, 100.milliseconds) - } - - "allow adding of a value" in { - val a = actor - a ! Set(33) - (a !< Add(44)).get(500) must be_==(Full(Answer(77))) - } - - "allow subtracting of a value" in { - val a = actor - a ! Set(33) - (a !< Sub(11)).get(500) must be_==(Full(Answer(22))) - } - - "properly timeout" in { - val a = actor - (a !< Set(33)).get(50) must be_==(Empty).eventually(900, 100.milliseconds) - } - } - -} - - -case class Add(num: Int) -case class Sub(num: Int) -case class Set(num: Int) - -case class Get() -class FunnyGet() extends Get() - -case class Answer(num: Int) diff --git a/core/actor/src/test/scala-2.13/net/liftweb/actor/LAFutureSpec.scala b/core/actor/src/test/scala-2.13/net/liftweb/actor/LAFutureSpec.scala deleted file mode 100644 index f200bd54e9..0000000000 --- a/core/actor/src/test/scala-2.13/net/liftweb/actor/LAFutureSpec.scala +++ /dev/null @@ -1,145 +0,0 @@ -package net.liftweb.actor - -import net.liftweb.common.{Box, Failure, Full} -import org.specs2.mutable.Specification -import java.util.concurrent.atomic.AtomicBoolean - -class LAFutureSpec extends Specification { - sequential - val timeout = 20000L - LAScheduler - - "LAFuture" should { - val futureSpecScheduler = new LAScheduler { - override def execute(f: ()=>Unit): Unit = f() - } - - "map to failing future if transforming function throws an Exception" in { - val future = LAFuture(() => 1, futureSpecScheduler) - def tranformThrowingException(input: Int) = { - throw new Exception("fail") - } - - val transformedFuture = future.map(tranformThrowingException) - - var notifiedAboutFailure: Boolean = false - transformedFuture.onFail { _ => - notifiedAboutFailure = true - } - - transformedFuture.get(timeout) - notifiedAboutFailure shouldEqual true - } - - "flatMap to failing future if transforming function throws an Exception" in { - val future = LAFuture(() => 1, futureSpecScheduler) - def tranformThrowingException(input: Int): LAFuture[Int] = { - throw new Exception("fail") - } - - val transformedFuture = future.flatMap(tranformThrowingException) - - var notifiedAboutFailure: Boolean = false - transformedFuture.onFail { _ => - notifiedAboutFailure = true - } - - transformedFuture.get(timeout) - notifiedAboutFailure shouldEqual true - } - - "return original Failure after timeout" in { - val future = new LAFuture() - val givenFailure = Failure("fooFailure") - LAScheduler.execute { () => - Thread.sleep(500) - future.fail(givenFailure) - } - - val result = future.get(timeout) - - result shouldEqual givenFailure - } - - "when collecting results with LAFuture.collect" in { - "collect one future result" in { - val givenOneResult = 123 - val one = LAFuture(() => givenOneResult) - LAFuture.collect(one).get(timeout) shouldEqual List(givenOneResult) - } - - "collect more future results in correct order" in { - val givenOneResult = 123 - val givenTwoResult = 234 - val one = LAFuture(() => givenOneResult) - val two = LAFuture(() => givenTwoResult) - LAFuture.collect(one, two).get(timeout) shouldEqual List(givenOneResult, givenTwoResult) - } - - "collect empty list immediately" in { - val collectResult = LAFuture.collect(Nil: _*) - collectResult.isSatisfied shouldEqual true - collectResult.get(timeout) shouldEqual Nil - } - - "report a failed LAFuture as a failure for the overall future" in { - val one: LAFuture[Int] = new LAFuture - val two: LAFuture[Int] = LAFuture(() => 5) - - one.fail(Failure("boom boom boom!")) - - val collectResult = LAFuture.collect(one, two) - collectResult.get(timeout) shouldEqual Failure("boom boom boom!") - } - } - - "when collecting Boxed results with collectAll" in { - "collectAll collects an EmptyBox immediately" in { - val one: LAFuture[Box[Int]] = LAFuture(() => { Failure("whoops"): Box[Int] }) - val two: LAFuture[Box[Int]] = LAFuture(() => { Thread.sleep(10000); Full(1) }) - - val collectResult = LAFuture.collectAll(one, two) - collectResult.get(5000) shouldEqual Failure("whoops") - } - - "collectAll collects a set of Fulls" in { - val one: LAFuture[Box[Int]] = LAFuture(() => Full(1): Box[Int]) - val two: LAFuture[Box[Int]] = LAFuture(() => Full(2): Box[Int]) - val three: LAFuture[Box[Int]] = LAFuture(() => Full(3): Box[Int]) - - val collectResult = LAFuture.collectAll(one, two, three) - collectResult.get(timeout) should beLike { - case Full(Full(results)) => - results should contain(allOf(1, 2, 3)) - } - } - - "collectAll reports a failed LAFuture as a failure for the overall future" in { - val one: LAFuture[Box[Int]] = new LAFuture - val two: LAFuture[Box[Int]] = LAFuture(() => Full(5): Box[Int]) - - one.fail(Failure("boom boom boom!")) - - val collectResult = LAFuture.collectAll(one, two) - collectResult.get(timeout) shouldEqual Failure("boom boom boom!") - } - - "collectAll empty list immediately" in { - val collectResult = LAFuture.collectAll(Nil : _*) - collectResult.isSatisfied shouldEqual true - collectResult.get(timeout) shouldEqual Nil - } - - "report a failed LAFuture as a failure for the overall future" in { - val one: LAFuture[Box[Int]] = new LAFuture - val two: LAFuture[Box[Int]] = LAFuture(() => Full(5): Box[Int]) - - one.fail(Failure("boom boom boom!")) - - val collectResult = LAFuture.collectAll(one, two) - collectResult.get(timeout) shouldEqual Failure("boom boom boom!") - } - } - } - -} diff --git a/core/actor/src/test/scala-2.13/net/liftweb/actor/MockLiftActorSpec.scala b/core/actor/src/test/scala-2.13/net/liftweb/actor/MockLiftActorSpec.scala deleted file mode 100644 index defd9dadf1..0000000000 --- a/core/actor/src/test/scala-2.13/net/liftweb/actor/MockLiftActorSpec.scala +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright 2011-2026 Lift Committers and Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package net.liftweb -package actor - -import org.specs2.mutable.Specification - -class MockLiftActorSpec extends Specification { - "Mock Actor Specification".title - - sealed trait MockSpecActorMessage - case object MockSpecActorMessage1 extends MockSpecActorMessage - case object MockSpecActorMessage2 extends MockSpecActorMessage - case object MockSpecActorMessage3 extends MockSpecActorMessage - - "A MockSpecializedLiftActor" should { - "correctly indicate when it has received a message" in { - val mockActor = new MockSpecializedLiftActor[MockSpecActorMessage] - - mockActor ! MockSpecActorMessage1 - mockActor ! MockSpecActorMessage2 - - mockActor.hasReceivedMessage_?(MockSpecActorMessage1) must beTrue - } - - "correctly indicate when it has not received a message" in { - val mockActor = new MockSpecializedLiftActor[MockSpecActorMessage] - - mockActor ! MockSpecActorMessage1 - mockActor ! MockSpecActorMessage2 - - mockActor.hasReceivedMessage_?(MockSpecActorMessage3) must beFalse - } - - "correctly indicate the number of messages it has received" in { - val mockActor = new MockSpecializedLiftActor[MockSpecActorMessage] - - mockActor ! MockSpecActorMessage1 - mockActor ! MockSpecActorMessage2 - mockActor ! MockSpecActorMessage3 - - mockActor.messageCount must_== 3 - } - - "correctly list the messages it has received" in { - val mockActor = new MockSpecializedLiftActor[MockSpecActorMessage] - - mockActor ! MockSpecActorMessage1 - mockActor ! MockSpecActorMessage2 - mockActor ! MockSpecActorMessage3 - - mockActor.messages must_== List( - MockSpecActorMessage3, - MockSpecActorMessage2, - MockSpecActorMessage1 - ) - } - } - - "A MockLiftActor" should { - "correctly indicate when it has received a message" in { - val mockActor = new MockLiftActor - - mockActor ! MockSpecActorMessage1 - mockActor ! MockSpecActorMessage2 - - mockActor.hasReceivedMessage_?(MockSpecActorMessage1) must beTrue - } - - "correctly indicate when it has not received a message" in { - val mockActor = new MockLiftActor - - mockActor ! MockSpecActorMessage1 - mockActor ! MockSpecActorMessage2 - - mockActor.hasReceivedMessage_?(MockSpecActorMessage3) must beFalse - } - - "correctly indicate the number of messages it has received" in { - val mockActor = new MockLiftActor - - mockActor ! MockSpecActorMessage1 - mockActor ! MockSpecActorMessage2 - mockActor ! MockSpecActorMessage3 - - mockActor.messageCount must_== 3 - } - - "correctly list the messages it has received" in { - val mockActor = new MockLiftActor - - mockActor ! MockSpecActorMessage1 - mockActor ! MockSpecActorMessage2 - mockActor ! MockSpecActorMessage3 - - mockActor.messages must_== List( - MockSpecActorMessage3, - MockSpecActorMessage2, - MockSpecActorMessage1 - ) - } - } -} diff --git a/core/actor/src/test/scala-3/net/liftweb/actor/ActorSpec.scala b/core/actor/src/test/scala/net/liftweb/actor/ActorSpec.scala similarity index 100% rename from core/actor/src/test/scala-3/net/liftweb/actor/ActorSpec.scala rename to core/actor/src/test/scala/net/liftweb/actor/ActorSpec.scala diff --git a/core/actor/src/test/scala-3/net/liftweb/actor/LAFutureSpec.scala b/core/actor/src/test/scala/net/liftweb/actor/LAFutureSpec.scala similarity index 100% rename from core/actor/src/test/scala-3/net/liftweb/actor/LAFutureSpec.scala rename to core/actor/src/test/scala/net/liftweb/actor/LAFutureSpec.scala diff --git a/core/actor/src/test/scala-3/net/liftweb/actor/MockLiftActorSpec.scala b/core/actor/src/test/scala/net/liftweb/actor/MockLiftActorSpec.scala similarity index 100% rename from core/actor/src/test/scala-3/net/liftweb/actor/MockLiftActorSpec.scala rename to core/actor/src/test/scala/net/liftweb/actor/MockLiftActorSpec.scala diff --git a/core/common/src/test/scala-2.13/net/liftweb/common/BoxLoggingSpec.scala b/core/common/src/test/scala-2.13/net/liftweb/common/BoxLoggingSpec.scala deleted file mode 100644 index 285b812b7d..0000000000 --- a/core/common/src/test/scala-2.13/net/liftweb/common/BoxLoggingSpec.scala +++ /dev/null @@ -1,455 +0,0 @@ -package net.liftweb -package common - -import org.slf4j.{Logger=>SLF4JLogger} - -import org.scalamock.specs2.MockContext -import org.specs2.mutable.Specification - -class BoxLoggingSpec extends Specification { - class MockBoxLoggingClass extends BoxLogging { - var loggedErrors = List[(String, Option[Throwable])]() - var loggedWarns = List[(String, Option[Throwable])]() - var loggedInfos = List[(String, Option[Throwable])]() - var loggedDebugs = List[(String, Option[Throwable])]() - var loggedTraces = List[(String, Option[Throwable])]() - - protected def logBoxError(message: String, throwable: Option[Throwable]): Unit = { - loggedErrors ::= (message, throwable) - } - protected def logBoxWarn(message: String, throwable: Option[Throwable]): Unit = { - loggedWarns ::= (message, throwable) - } - protected def logBoxInfo(message: String, throwable: Option[Throwable]): Unit = { - loggedInfos ::= (message, throwable) - } - protected def logBoxDebug(message: String, throwable: Option[Throwable]): Unit = { - loggedDebugs ::= (message, throwable) - } - protected def logBoxTrace(message: String, throwable: Option[Throwable]): Unit = { - loggedTraces ::= (message, throwable) - } - } - - "BoxLogging" should { - "when logging empty boxes" in { - def verifyContentList(list: List[(String, Option[Throwable])]) = { - list must beLike { - case (paramFailure4, None) :: - (paramFailure3, None) :: - (paramFailure2, None) :: - (paramFailure1, Some(paramExp)) :: - (chained1, None) :: - (chained2, None) :: - (level1, None) :: - (level2, Some(exp2)) :: - (level3, None) :: - (level4, Some(exp4)) :: - (emptyMessage, None) :: - (fullParamMessage, Some(paramException)) :: - (paramMessage, None) :: - (exceptedMessage, Some(failureException)) :: - (failureMessage, None) :: - Nil => - (failureMessage must startWith("Second")) and - (failureMessage must contain("Failed")) and - (exceptedMessage must startWith("Third")) and - (exceptedMessage must contain("Excepted")) and - (failureException.getMessage must_== "uh-oh") and - (paramMessage must startWith("Fourth")) and - (paramMessage must contain("ParamFailed")) and - (paramMessage must contain("BoxLoggingSpec")) and - (fullParamMessage must startWith("Fifth")) and - (fullParamMessage must contain("ParamExcepted")) and - (fullParamMessage must contain("BoxLoggingSpec")) and - (paramException.getMessage must_== "param uh-oh") and - (emptyMessage must startWith("Sixth")) and - (emptyMessage must contain("Empty")) and - (level1 must contain("Failure level 3 caused by: Failure level 4")) and - (level2 must contain("Failure level 2 caused by: Failure level 3")) and - (exp2 must beAnInstanceOf[IllegalArgumentException]) and - (level3 must contain("Failure level 1 caused by: Failure level 2")) and - (level4 must contain("Multilevel failure: Failure level 1")) and - (exp4 must beAnInstanceOf[NullPointerException]) and - (chained1 must contain("Chained failure caused by: Boom")) and - (chained2 must contain("Chain all failures: Chained failure")) and - (paramFailure4 must contain("Param Failure lvl 3 with param Param 3 caused by: Param Failure lvl 4 with param Param 4")) and - (paramFailure3 must contain("Failure lvl 2 caused by: Param Failure lvl 3 with param Param 3")) and - (paramFailure2 must contain("Param Failure lvl 1 with param Param 1 caused by: Failure lvl 2")) and - (paramFailure1 must contain("Param failure: Param Failure lvl 1 with param Param 1")) and - (paramExp must beAnInstanceOf[IllegalArgumentException]) - } - } - - "log correctly on ERROR level" in { - val results = - new MockBoxLoggingClass { - Full("Not empty").logEmptyBox("First") - Failure("Failed").logEmptyBox("Second") - Failure("Excepted", Full(new Exception("uh-oh")), Empty).logEmptyBox("Third") - ParamFailure("ParamFailed", this).logEmptyBox("Fourth") - ParamFailure( - "ParamExcepted", - Full(new Exception("param uh-oh")), - Empty, - this - ).logEmptyBox("Fifth") - (Empty).logEmptyBox("Sixth") - Failure( - "Failure level 1", Full(new NullPointerException), Full(Failure( - "Failure level 2", Empty, Full(Failure( - "Failure level 3", Full(new IllegalArgumentException), Full(Failure( - "Failure level 4" - ))) - )) - ) - ).logEmptyBox("Multilevel failure") - (Failure("Boom") ?~! "Chained failure").logEmptyBox("Chain all failures") - ParamFailure( - "Param Failure lvl 1", Full(new IllegalArgumentException), Full(Failure( - "Failure lvl 2", Empty, Full(ParamFailure( - "Param Failure lvl 3", Empty, Full(ParamFailure( - "Param Failure lvl 4", - "Param 4" - )), - "Param 3" - )) - )), - "Param 1" - ).logEmptyBox("Param failure") - } - - verifyContentList(results.loggedErrors) - } - - "log correctly on WARN level" in { - val results = - new MockBoxLoggingClass { - Full("Not empty").warnLogEmptyBox("First") - Failure("Failed").warnLogEmptyBox("Second") - Failure("Excepted", Full(new Exception("uh-oh")), Empty).warnLogEmptyBox("Third") - ParamFailure("ParamFailed", this).warnLogEmptyBox("Fourth") - ParamFailure( - "ParamExcepted", - Full(new Exception("param uh-oh")), - Empty, - this - ).warnLogEmptyBox("Fifth") - (Empty).warnLogEmptyBox("Sixth") - Failure( - "Failure level 1", Full(new NullPointerException), Full(Failure( - "Failure level 2", Empty, Full(Failure( - "Failure level 3", Full(new IllegalArgumentException), Full(Failure( - "Failure level 4" - ))) - )) - ) - ).warnLogEmptyBox("Multilevel failure") - (Failure("Boom") ?~! "Chained failure").warnLogEmptyBox("Chain all failures") - ParamFailure( - "Param Failure lvl 1", Full(new IllegalArgumentException), Full(Failure( - "Failure lvl 2", Empty, Full(ParamFailure( - "Param Failure lvl 3", Empty, Full(ParamFailure( - "Param Failure lvl 4", - "Param 4" - )), - "Param 3" - )) - )), - "Param 1" - ).warnLogEmptyBox("Param failure") - } - - verifyContentList(results.loggedWarns) - } - - "log correctly on INFO level" in { - val results = - new MockBoxLoggingClass { - Full("Not empty").infoLogEmptyBox("First") - Failure("Failed").infoLogEmptyBox("Second") - Failure("Excepted", Full(new Exception("uh-oh")), Empty).infoLogEmptyBox("Third") - ParamFailure("ParamFailed", this).infoLogEmptyBox("Fourth") - ParamFailure( - "ParamExcepted", - Full(new Exception("param uh-oh")), - Empty, - this - ).infoLogEmptyBox("Fifth") - (Empty).infoLogEmptyBox("Sixth") - Failure( - "Failure level 1", Full(new NullPointerException), Full(Failure( - "Failure level 2", Empty, Full(Failure( - "Failure level 3", Full(new IllegalArgumentException), Full(Failure( - "Failure level 4" - ))) - )) - ) - ).infoLogEmptyBox("Multilevel failure") - (Failure("Boom") ?~! "Chained failure").infoLogEmptyBox("Chain all failures") - ParamFailure( - "Param Failure lvl 1", Full(new IllegalArgumentException), Full(Failure( - "Failure lvl 2", Empty, Full(ParamFailure( - "Param Failure lvl 3", Empty, Full(ParamFailure( - "Param Failure lvl 4", - "Param 4" - )), - "Param 3" - )) - )), - "Param 1" - ).infoLogEmptyBox("Param failure") - } - - verifyContentList(results.loggedInfos) - } - - "log correctly on DEBUG level" in { - val results = - new MockBoxLoggingClass { - Full("Not empty").debugLogEmptyBox("First") - Failure("Failed").debugLogEmptyBox("Second") - Failure("Excepted", Full(new Exception("uh-oh")), Empty).debugLogEmptyBox("Third") - ParamFailure("ParamFailed", this).debugLogEmptyBox("Fourth") - ParamFailure( - "ParamExcepted", - Full(new Exception("param uh-oh")), - Empty, - this - ).debugLogEmptyBox("Fifth") - (Empty).debugLogEmptyBox("Sixth") - Failure( - "Failure level 1", Full(new NullPointerException), Full(Failure( - "Failure level 2", Empty, Full(Failure( - "Failure level 3", Full(new IllegalArgumentException), Full(Failure( - "Failure level 4" - ))) - )) - ) - ).debugLogFailure("Multilevel failure") - (Failure("Boom") ?~! "Chained failure").debugLogFailure("Chain all failures") - ParamFailure( - "Param Failure lvl 1", Full(new IllegalArgumentException), Full(Failure( - "Failure lvl 2", Empty, Full(ParamFailure( - "Param Failure lvl 3", Empty, Full(ParamFailure( - "Param Failure lvl 4", - "Param 4" - )), - "Param 3" - )) - )), - "Param 1" - ).debugLogFailure("Param failure") - } - - verifyContentList(results.loggedDebugs) - } - - "log correctly on TRACE level" in { - val results = - new MockBoxLoggingClass { - Full("Not empty").traceLogEmptyBox("First") - Failure("Failed").traceLogEmptyBox("Second") - Failure("Excepted", Full(new Exception("uh-oh")), Empty).traceLogEmptyBox("Third") - ParamFailure("ParamFailed", this).traceLogEmptyBox("Fourth") - ParamFailure( - "ParamExcepted", - Full(new Exception("param uh-oh")), - Empty, - this - ).traceLogEmptyBox("Fifth") - (Empty).traceLogEmptyBox("Sixth") - Failure( - "Failure level 1", Full(new NullPointerException), Full(Failure( - "Failure level 2", Empty, Full(Failure( - "Failure level 3", Full(new IllegalArgumentException), Full(Failure( - "Failure level 4" - ))) - )) - ) - ).traceLogEmptyBox("Multilevel failure") - (Failure("Boom") ?~! "Chained failure").traceLogEmptyBox("Chain all failures") - ParamFailure( - "Param Failure lvl 1", Full(new IllegalArgumentException), Full(Failure( - "Failure lvl 2", Empty, Full(ParamFailure( - "Param Failure lvl 3", Empty, Full(ParamFailure( - "Param Failure lvl 4", - "Param 4" - )), - "Param 3" - )) - )), - "Param 1" - ).traceLogEmptyBox("Param failure") - } - - verifyContentList(results.loggedTraces) - } - } - - "when logging only failures" in { - def verifyContentList(list: List[(String, Option[Throwable])]) = { - list must beLike { - case (fullParamMessage, Some(paramException)) :: - (paramMessage, None) :: - (exceptedMessage, Some(failureException)) :: - (failureMessage, None) :: - Nil => - (failureMessage must startWith("Second")) and - (failureMessage must contain("Failed")) and - (exceptedMessage must startWith("Third")) and - (exceptedMessage must contain("Excepted")) and - (failureException.getMessage must_== "uh-oh") and - (paramMessage must startWith("Fourth")) and - (paramMessage must contain("ParamFailed")) and - (paramMessage must contain("BoxLoggingSpec")) and - (fullParamMessage must startWith("Fifth")) and - (fullParamMessage must contain("ParamExcepted")) and - (fullParamMessage must contain("BoxLoggingSpec")) and - (paramException.getMessage must_== "param uh-oh") - } - } - - "log correctly on ERROR level" in { - val results = - new MockBoxLoggingClass { - Full("Not empty").logFailure("First") - Failure("Failed").logFailure("Second") - Failure("Excepted", Full(new Exception("uh-oh")), Empty).logFailure("Third") - ParamFailure("ParamFailed", this).logFailure("Fourth") - ParamFailure( - "ParamExcepted", - Full(new Exception("param uh-oh")), - Empty, - this - ).logFailure("Fifth") - (Empty).logFailure("Sixth") - } - - verifyContentList(results.loggedErrors) - } - - "log correctly on WARN level" in { - val results = - new MockBoxLoggingClass { - Full("Not empty").warnLogFailure("First") - Failure("Failed").warnLogFailure("Second") - Failure("Excepted", Full(new Exception("uh-oh")), Empty).warnLogFailure("Third") - ParamFailure("ParamFailed", this).warnLogFailure("Fourth") - ParamFailure( - "ParamExcepted", - Full(new Exception("param uh-oh")), - Empty, - this - ).warnLogFailure("Fifth") - (Empty).warnLogFailure("Sixth") - } - - verifyContentList(results.loggedWarns) - } - - "log correctly on INFO level" in { - val results = - new MockBoxLoggingClass { - Full("Not empty").infoLogFailure("First") - Failure("Failed").infoLogFailure("Second") - Failure("Excepted", Full(new Exception("uh-oh")), Empty).infoLogFailure("Third") - ParamFailure("ParamFailed", this).infoLogFailure("Fourth") - ParamFailure( - "ParamExcepted", - Full(new Exception("param uh-oh")), - Empty, - this - ).infoLogFailure("Fifth") - (Empty).infoLogFailure("Sixth") - } - - verifyContentList(results.loggedInfos) - } - - "log correctly on DEBUG level" in { - val results = - new MockBoxLoggingClass { - Full("Not empty").debugLogFailure("First") - Failure("Failed").debugLogFailure("Second") - Failure("Excepted", Full(new Exception("uh-oh")), Empty).debugLogFailure("Third") - ParamFailure("ParamFailed", this).debugLogFailure("Fourth") - ParamFailure( - "ParamExcepted", - Full(new Exception("param uh-oh")), - Empty, - this - ).debugLogFailure("Fifth") - (Empty).debugLogFailure("Sixth") - } - - verifyContentList(results.loggedDebugs) - } - - "log correctly on TRACE level" in { - val results = - new MockBoxLoggingClass { - Full("Not empty").traceLogFailure("First") - Failure("Failed").traceLogFailure("Second") - Failure("Excepted", Full(new Exception("uh-oh")), Empty).traceLogFailure("Third") - ParamFailure("ParamFailed", this).traceLogFailure("Fourth") - ParamFailure( - "ParamExcepted", - Full(new Exception("param uh-oh")), - Empty, - this - ).traceLogFailure("Fifth") - (Empty).traceLogFailure("Sixth") - } - - verifyContentList(results.loggedTraces) - } - } - - "when logging in a Loggable" in { - import net.liftweb.common.Logger - import org.slf4j.{Logger => SLF4JLogger} - - "log to the Lift logger" in new MockContext { - val mockLogger = mock[SLF4JLogger] - (mockLogger.isErrorEnabled: () => Boolean).expects().returning(true).anyNumberOfTimes() - - class MyLoggable extends LoggableBoxLogging { - override val logger = new Logger { - override protected def _logger = mockLogger - } - } - - (mockLogger.error(_: String)).expects(*).once() - (mockLogger.error(_: String, _: Throwable)).expects(*, *).once() - - val result = - new MyLoggable { - Failure("Failed").logFailure("Second") - Failure("Excepted", Full(new Exception("uh-oh")), Empty).logFailure("Third") - } - } - } - - "when logging with in SLF4J context" in { - import org.slf4j.{Logger => SLF4JLogger} - - "log to the SLF4J logger" in new MockContext { - val mockLogger = mock[SLF4JLogger] - (mockLogger.isErrorEnabled: () => Boolean).expects().returning(true).anyNumberOfTimes() - - class TestClass extends SLF4JBoxLogging { - val logger = mockLogger - } - - (mockLogger.error(_: String)).expects(*).once() - (mockLogger.error(_: String, _: Throwable)).expects(*, *).once() - - new TestClass { - Failure("Failed").logFailure("Second") - Failure("Excepted", Full(new Exception("uh-oh")), Empty).logFailure("Third") - } - } - } - } -} diff --git a/core/common/src/test/scala-2.13/net/liftweb/common/BoxSpec.scala b/core/common/src/test/scala-2.13/net/liftweb/common/BoxSpec.scala deleted file mode 100644 index 7ff449f05b..0000000000 --- a/core/common/src/test/scala-2.13/net/liftweb/common/BoxSpec.scala +++ /dev/null @@ -1,579 +0,0 @@ -/* - * Copyright 2007-2026 Lift Committers and Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package net.liftweb -package common - -import org.specs2.mutable.Specification -import org.specs2.ScalaCheck -import org.scalacheck.{Arbitrary, Gen} -import Gen._ - -import Box._ - - -/* commented out because it tests the compilation phase and we want the compiler to "do the right thing" -class TypeBoundsTest extends Specification with ScalaCheck { - "Type Bounds Spec".title - - "Type bounds" can { - "do type testing" in { - def foo[T: ExcludeThisType.exclude[Nothing]#other](a: T) = a.toString - foo(33.0) - foo(throw new Exception("foo")) - - true == true - } - } -} - -*/ - -/** - * System under specification for Box. - */ -class BoxSpec extends Specification with ScalaCheck with BoxGenerator { - - "A Box" can { - "be created from a Option. It is Empty if the option is None" in { - Box(None) must be_==(Empty) - } - "be created from a Option. It is Full(x) if the option is Some(x)" in { - Box(Some(1)) must_== Full(1) - } - "be created from a List containing one element. It is Empty if the list is empty" in { - Box(Nil) must be_==(Empty) - } - "be created from a List containing one element. It is Full(x) if the list is List(x)" in { - Box(List(1)) must_== Full(1) - } - "be created from a List containing more than one element. It is Full(x) if the list is x::rest" in { - Box(List(1, 2, 3)) must_== Full(1) - } - "be used as an iterable" in { - Full(1) reduceLeft {(x: Int, y: Int) => x + y} must_== 1 - } - "be used as an Option" in { - Full(1) orElse Some(2) must beSome(1) - Empty orElse Some(2) must beSome(2) - } - "be implicitly defined from an Option. The openOrThrowException method can be used on an Option for example" in { - Some(1).openOrThrowException("This is a test") must_== 1 - } - "be defined from some legacy code (possibly passing null values). If the passed value is not null, a Full(value) is returned" in { - Box.legacyNullTest("s") must_== Full("s") - } - "be defined from some legacy code (possibly passing null values). If the passed value is null, an Empty is returned" in { - Box.legacyNullTest(null) must_== Empty - } - } - - "A Box" should { - "provide a 'choice' method to either apply a function to the Box value or return another default can" in { - def gotIt = (x: Int) => Full("got it: " + x.toString) - - Full(1).choice(gotIt)(Full("nothing")) must_== Full("got it: 1") - Empty.choice(gotIt)(Full("nothing")) must_== Full("nothing") - } - } - - "A Full Box" should { - "not beEmpty" in { - Full(1).isEmpty must beFalse - } - "be defined" in { - Full(1).isDefined must beTrue - } - "return its value when opened" in { - Full(1).openOrThrowException("This is a test") must_== 1 - } - "return its value when opened with openOr(default value)" in { - Full(1) openOr 0 must_== 1 - } - "return itself when or'ed with another Box" in { - Full(1) or Full(2) must_== Full(1) - } - "define an 'exists' method returning true if the Box value satisfies the function" in { - Full(1) exists {_ > 0} must beTrue - } - "define an exists method returning false if the Box value doesn't satisfy the function" in { - Full(0) exists {_ > 0} must beFalse - } - "define a forall method returning true if the Box value satisfies the function" in { - Full(1) forall {_ > 0} must beTrue - } - "define a forall method returning false if the Box value doesn't satisfy the function" in { - Full(0) forall {_ > 0} must beFalse - } - "define a 'filter' method, returning a Full Box if the filter is satisfied" in { - Full(1) filter {_ > 0} must_== Full(1) - } - "define a 'filter' method, returning Empty if the filter is not satisfied" in { - Full(1) filter {_ == 0} must be_==(Empty) - } - "define a 'filterMsg' method, returning a Failure if the filter predicate is not satisfied" in { - Full(1).filterMsg("not equal to 0")(_ == 0) must_== Failure("not equal to 0", Empty, Empty) - } - "define a 'foreach' method using its value (to display it for instance)" in { - var total = 0 - Full(1) foreach { total += _ } - total must_== 1 - } - "define a 'map' method to transform its value" in { - Full(1) map { _.toString } must_== Full("1") - } - "define a 'flatMap' method transforming its value in another Box. If the value is transformed in a Full box, the total result is a Full box" in { - Full(1) flatMap { (x: Int) => if (x > 0) Full("full") else Empty } must_== Full("full") - } - "define a 'flatMap' method transforming its value in another Box. If the value is transformed in an Empty box, the total result is an Empty box" in { - Full(0) flatMap { (x: Int) => if (x > 0) Full("full") else Empty } must be_==(Empty) - } - "define a 'flatten' method if it contains another Box." in { - "If the inner box is a Full box, the final result is identical to that box" in { - Full(Full(1)).flatten must_== Full(1) - } - "If the inner box is a Failure, the final result is identical to that box" in { - Full(Failure("error", Empty, Empty)).flatten must_== Failure("error", Empty, Empty) - } - "If the inner box is an Empty box, the final result is identical to that box" in { - Full(Empty).flatten must_== Empty - } - } - "define a 'collect' method that takes a PartialFunction to transform its contents" in { - "If the partial-function is defined for the contents of this box, returns a full box containing the result of applying that partial function to this Box's contents" in { - Full("Albus") collect { case "Albus" => "Dumbledore"} must_== Full("Dumbledore") - } - "If the partial-function is not defined for the contents of this box, returns Empty" in { - Full("Hermione") collect { case "Albus" => "Dumbledore"} must be_==(Empty) - } - } - "define a 'transform' method that takes a PartialFunction to transform this box into another box" in { - "If the partial-function is defined for this box, returns the result of applying the partial function to it" in { - Full(404) transform { - case Full(x: Int) if x != 200 => Failure("Server error") - } must_== Failure("Server error") - } - "If the partial-function is not defined for this box, returns itself unchanged" in { - Full("Intended Result") transform { - case _: EmptyBox => Full("Alternative") - case Full("Unexpected Result") => Full("Alternative") - } must_== Full("Intended Result") - } - } - "define a 'flip' method returning Empty" in { - Full(1) flip { _ => "No data found" } mustEqual Empty - } - "define an 'elements' method returning an iterator containing its value" in { - Full(1).elements.next() must_== 1 - } - "define a 'toList' method returning a List containing its value" in { - Full(1).toList must_== List(1) - } - "define a 'toOption' method returning a Some object containing its value" in { - Full(1).toOption must beSome(1) - } - "return itself if asked for its status with the operator ?~" in { - Full(1) ?~ "error" must_== Full(1) - } - "return itself if asked for its status with the operator ?~!" in { - Full(1) ?~! "error" must_== Full(1) - } - "define a 'pass' method passing the can to a function and returning itself (alias: $)" in { - var empty = false - def emptyString(s: Box[String]) = s foreach {(c: String) => empty = c.isEmpty} - Full("") $ emptyString _ - empty must beTrue - } - "define a 'run' method either returning a default value or applying a user-defined function on it" in { - def appendToString(s: String, x: Int) = s + x.toString - Full(1).run("string")(appendToString) must_== "string1" - } - "define a 'isA' method returning a Full(value) if the value is the instance of a given class" in { - Full("s").isA(classOf[String]) must_== Full("s") - } - "define a 'isA' method returning Empty if the value is not the instance of a given class" in { - Full("s").isA(classOf[Double]) must_== Empty - } - "define a 'asA' method returning a Full(value) if the value is the instance of a given type" in { - Full("s").asA[String] must_== Full("s") - } - "define a 'asA' method returning Empty if the value is not the instance of a given type" in { - Full("s").asA[Double] must_== Empty - } - - "define a 'asA' method must work with Boolean" in { - Full(true).asA[Boolean] must_== Full(true) - Full(3).asA[Boolean] must_== Empty - } - - "define a 'asA' method must work with Character" in { - Full('a').asA[Char] must_== Full('a') - Full('a').asA[Boolean] must_== Empty - } - - "define a 'asA' method must work with Byte" in { - Full(3.toByte).asA[Byte] must_== Full(3.toByte) - Full(3.toByte).asA[Boolean] must_== Empty - } - - "define a 'asA' method must work with Double" in { - Full(44d).asA[Double] must_== Full(44D) - Full(44d).asA[Boolean] must_== Empty - } - - "define a 'asA' method must work with Float" in { - Full(32f).asA[Float] must_== Full(32f) - Full(33f).asA[Boolean] must_== Empty - } - - "define a 'asA' method must work with Integer" in { - Full(3).asA[Int] must_== Full(3) - Full(3).asA[Boolean] must_== Empty - } - - "define a 'asA' method must work with Long" in { - Full(32L).asA[Long] must_== Full(32L) - Full(32L).asA[Boolean] must_== Empty - } - - "define a 'asA' method must work with Short" in { - Full(8.toShort).asA[Short] must_== Full(8.toShort) - Full(8.toShort).asA[Boolean] must_== Empty - } - - "not invoke a call-by-name parameter to openOrThrowException" in { - var sideEffect = false - def sideEffecting = { - sideEffect = true - "This shouldn't have been invoked." - } - - try { - Full("hi mom").openOrThrowException(sideEffecting) - } catch { - case e: Exception => - } - - sideEffect must_== false - } - - } - - "An Empty Box" should { - "beEmpty" in { - Empty.isEmpty must beTrue - } - "not be defined" in { - Empty.isDefined must beFalse - } - "throw an exception if opened" in { - {Empty.openOrThrowException("See what happens?, at least we expect it in this case :)"); ()} must throwA[NullPointerException] - } - "return a default value if opened with openOr" in { - Empty.openOr(1) must_== 1 - } - "return the other Box if or'ed with another Box" in { - Empty.or(Full(1)) must_== Full(1) - } - "return itself if filtered with a predicate" in { - val empty: Box[Int] = Empty - empty.filter {_ > 0} must be_==(Empty) - } - "define an 'exists' method returning false" in { - val empty: Box[Int] = Empty - empty exists {_ > 0} must beFalse - } - "define a 'forall' method returning true" in { - val empty: Box[Int] = Empty - empty forall {_ > 0} must beTrue - } - "define a 'filter' method, returning Empty" in { - val empty: Box[Int] = Empty - empty filter {_ > 0} must be_==(Empty) - } - "define a 'filterMsg' method, returning a Failure" in { - Empty.filterMsg("not equal to 0")(_ == 0) must_== Failure("not equal to 0", Empty, Empty) - } - "define a 'foreach' doing nothing" in { - var total = 0 - val empty: Box[Int] = Empty - empty foreach {total += _} - total must_== 0 - } - "define a 'map' method returning Empty" in { - Empty map {_.toString} must be_==(Empty) - } - "define a 'flatMap' method returning Empty" in { - Empty flatMap {(x: Int) => Full("full")} must be_==(Empty) - } - "define a 'flatten' method returning Empty" in { - Empty.flatten must be_==(Empty) - } - "define a 'collect' method returning Empty" in { - Empty collect { case _ => "Some Value" } must be_==(Empty) - } - "define a 'transform' method that takes a PartialFunction to transform this Empty box into another box" in { - "If the partial-function is defined for Empty, returns the result of applying the partial function to it" in { - Empty transform { - case Failure("error", Empty, Empty) => Full("failure-alternative") - case Empty => Full("alternative") - } must_== Full("alternative") - } - "If the partial-function is not defined for Empty, returns Empty" in { - Empty transform { case Failure("The Phantom Menace", Empty, Empty) => Full("Return Of The Jedi") } must_== Empty - } - } - "define a 'flip' method returning a Full box" in { - Empty flip { - case Empty => "flipped-empty" - case _ => "flipped-failure" - } mustEqual Full("flipped-empty") - } - "define an 'elements' method returning an empty iterator" in { - Empty.elements.hasNext must beFalse - } - "define a 'toList' method returning Nil" in { - Empty.toList must_== Nil - } - "define a 'toOption' method returning None" in { - Empty.toOption must beNone - } - "return a failure with a message if asked for its status with the operator ?~" in { - Empty ?~ "nothing" must_== Failure("nothing", Empty, Empty) - } - "return a failure with a message if asked for its status with the operator ?~!" in { - Empty ?~! "nothing" must_== Failure("nothing", Empty, Empty) - } - "define a 'isA' method returning Empty" in { - Empty.isA(classOf[Double]) must_== Empty - } - "define a 'asA' method returning Empty" in { - Empty.asA[Double] must_== Empty - } - - "invoke a call-by-name parameter to openOrThrowException" in { - var sideEffect = false - def sideEffecting = { - sideEffect = true - "This should have been invoked." - } - - try { - Empty.openOrThrowException(sideEffecting) - } catch { - case e: Exception => - } - - sideEffect must_== true - } - } - - "A Failure is an Empty Box which" can { - "return its cause as an exception" in { - case class LiftException(m: String) extends Exception - Failure("error", Full(new LiftException("broken")), Empty).exception must_== Full(new LiftException("broken")) - } - "return a chained list of causes" in { - Failure("error", - Full(new Exception("broken")), - Full(Failure("nested cause", Empty, Empty))).chain must_== Full(Failure("nested cause", Empty, Empty)) - } - "be converted to a ParamFailure" in { - Failure("hi mom") ~> 404 must_== ParamFailure("hi mom", Empty, Empty, 404) - } - } - - "A Failure is an Empty Box which" should { - "return itself if mapped, flatMapped or flattened" in { - Failure("error", Empty, Empty) map {_.toString} must_== Failure("error", Empty, Empty) - Failure("error", Empty, Empty) flatMap {(x: String) => Full(x.toString)} must_== Failure("error", Empty, Empty) - Failure("error", Empty, Empty).flatten must_== Failure("error", Empty, Empty) - } - "define a 'collect' method returning itself" in { - Failure("error", Empty, Empty) collect { case _ => "Some Value" } must_== Failure("error", Empty, Empty) - } - "define a 'transform' method that takes a PartialFunction to transform this Failure into another box" in { - "If the partial-function is defined for this Failure, returns the result of applying the partial function to it" in { - Failure("The Phantom Menace") transform { - case Failure("The Phantom Menace", Empty, Empty) => Full("Return Of The Jedi") - } must_== Full("Return Of The Jedi") - - Failure("The Phantom Menace") transform { - case Failure("The Phantom Menace", Empty, Empty) => Failure("Clones") - case _ => Full("Jedi") - } must_== Failure("Clones") - } - "If the partial-function is not defined for this Failure, returns itself unchanged" in { - Failure("Clones") transform { case Failure("The Phantom Menace", Empty, Empty) => Full("Jedi") } must_== Failure("Clones") - } - } - "define a 'flip' method returning a Full box" in { - Failure("error", Empty, Empty) flip { - case Empty => "flipped-empty" - case _: Failure => "flipped-failure" - } must_== Full("flipped-failure") - } - "return itself when asked for its status with the operator ?~" in { - Failure("error", Empty, Empty) ?~ "nothing" must_== Failure("error", Empty, Empty) - } - "create a new failure with a chained message if asked for its status with the operator ?~!" in { - Failure("error", Empty, Empty) ?~! "error2" must_== Failure("error2", Empty, Full(Failure("error", Empty, Empty))) - } - "return false for exist method" in { - Failure("error", Empty, Empty) exists {_ => true } must beFalse - } - "return true for forall method" in { - Failure("error", Empty, Empty) forall {_ => false } must beTrue - } - } - - "A ParamFailure is a failure which" should { - "appear in the chain when ~> is invoked on it" in { - Failure("Apple") ~> 404 ~> "apple" must_== - ParamFailure("Apple", Empty, Full( - ParamFailure("Apple", Empty, Empty, 404) - ), "apple") - } - } - - "A Box equals method" should { - - "return true with comparing two identical Box messages" in prop { - (c1: Box[Int], c2: Box[Int]) => (c1, c2) match { - case (Empty, Empty) => c1 must_== c2 - case (Full(x), Full(y)) => (c1 == c2) must_== (x == y) - case (Failure(m1, e1, l1), Failure(m2, e2, l2)) => (c1 == c2) must_== ((m1, e1, l1) == (m2, e2, l2)) - case _ => c1 must be_!=(c2) - } - } - - "return false with comparing one Full and another object" in { - Full(1) must be_!=("hello") - } - - "return false with comparing one Empty and another object" in { - Empty must be_!=("hello") - } - - "return false with comparing one Failure and another object" in { - Failure("", Empty, Empty) must be_!=("hello") - } - } - - "A List[Box[T]]" should { - "be convertable to a Box[List[T]] when all are Full" in { - val someBoxes: List[Box[String]] = List(Full("bacon"), Full("sammich")) - val singleBox = someBoxes.toSingleBox("Box failed!") - - singleBox must_== Full(List("bacon", "sammich")) - } - - "be convertable to a Box[List[T]] when some are Full and some are Empty" in { - val someBoxes: List[Box[String]] = List(Full("bacon"), Full("sammich"), Empty) - val singleBox = someBoxes.toSingleBox("Box failed!") - - singleBox must_== Full(List("bacon", "sammich")) - } - - "be convertable to a ParamFailure[Box[List[T]]] when any are Failure" in { - val someBoxes: List[Box[String]] = List(Full("bacon"), Full("sammich"), Failure("I HATE BACON")) - val singleBox = someBoxes.toSingleBox("This should be in the param failure.") - - singleBox must beLike { - case ParamFailure(message, _, _, _) => - message must_== "This should be in the param failure." - } - } - - "chain the ParamFailure to the failures in the list when any are Failure" in { - val someBoxes: List[Box[String]] = List(Full("bacon"), Failure("I HATE BACON"), Full("sammich"), Failure("MORE BACON FAIL"), Failure("BACON WHY U BACON")) - - val singleBox = someBoxes.toSingleBox("Failure.") - - val expectedChain = - Failure("I HATE BACON", Empty, - Full(Failure("MORE BACON FAIL", Empty, - Full(Failure("BACON WHY U BACON"))))) - - singleBox must beLike { - case ParamFailure(_, _, chain, _) => - chain must_== Full(expectedChain) - } - } - } - - "A Box tryo method" should { - "return Full" in { - Box.tryo(1) must_== Full(1) - } - - "return Failure(_, Full(NPE), _) in case of NPE" in { - val obj: Object = null - - Box.tryo(obj.toString) must beLike { - case Failure(_, Full(ex), _) => ex.getClass must_== classOf[NullPointerException] - } - } - - "return Empty in case of NPE and ignore list with NPE" in { - val ignore: List[Class[_]] = List(classOf[NullPointerException]) - - Box.tryo(ignore)(throw new NullPointerException) must_== Empty - } - - "return Failure(_, Full(NPE), _) in case of non empty ignore list without NPE" in { - val ignore: List[Class[_]] = List(classOf[IllegalArgumentException]) - - Box.tryo(ignore)(throw new NullPointerException) must beLike { - case Failure(_, Full(ex), _) => ex.getClass must_== classOf[NullPointerException] - } - } - - "not throw NPE in case of nullable ignore list" in { - val ignore: List[Class[_]] = null - - Box.tryo(ignore)(throw new IllegalArgumentException) must beLike { - case Failure(_, Full(ex), _) => ex.getClass must_== classOf[IllegalArgumentException] - } - } - } -} - - -trait BoxGenerator { - - implicit def genThrowable: Arbitrary[Throwable] = Arbitrary[Throwable] { - case object UserException extends Throwable - const(UserException) - } - - implicit def genBox[T](implicit a: Arbitrary[T]): Arbitrary[Box[T]] = Arbitrary[Box[T]] { - frequency( - (3, const(Empty)), - (3, a.arbitrary.map(Full[T])), - (1, genFailureBox) - ) - } - - def genFailureBox: Gen[Failure] = for { - msgLen <- choose(0, 4) - msg <- listOfN(msgLen, alphaChar) - exception <- const(Full(new Exception(""))) - chainLen <- choose(1, 5) - chain <- frequency((1, listOfN(chainLen, genFailureBox)), (3, const(Nil))) - } yield Failure(msg.mkString, exception, Box(chain.headOption)) - -} diff --git a/core/common/src/test/scala-2.13/net/liftweb/common/ConversionsSpec.scala b/core/common/src/test/scala-2.13/net/liftweb/common/ConversionsSpec.scala deleted file mode 100644 index 72c803a58e..0000000000 --- a/core/common/src/test/scala-2.13/net/liftweb/common/ConversionsSpec.scala +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright 2010-2026 Lift Committers and Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package net.liftweb -package common - -import scala.xml.{NodeSeq, Text} -import org.specs2.matcher.XmlMatchers -import org.specs2.mutable.Specification - -import scala.annotation.nowarn - - -/** - * System under specification for Conversions. - */ -@nowarn("msg=.* NodeSeqFunc in package common.* is deprecate.*") -class ConversionsSpec extends Specification with XmlMatchers { - - "A StringOrNodeSeq" should { - - "convert from a String" in { - val sns: StringOrNodeSeq = "Hello" - sns.nodeSeq must_== Text("Hello") - } - - "convert from an Elem" in { - val sns: StringOrNodeSeq = - sns.nodeSeq must ==/ () - } - - "convert from a Seq[Node]" in { - val sns: StringOrNodeSeq = List(, ) - sns.nodeSeq must ==/ (List(, ) : NodeSeq) - } - } - - "A StringFunc" should { - - "be created by a String constant" in { - val sf: StringFunc = "Foo" - - sf.func() must_== "Foo" - } - - "be created by a String Function" in { - val sf: StringFunc = () => "Bar" - - sf.func() must_== "Bar" - } - - "be created by a constant that can be converted to a String" in { - implicit def intToString(in: Int): String = in.toString - val sf: StringFunc = 55 - - sf.func() must_== "55" - } - - "be created by a function that can be converted to a String" in { - implicit def intToString(in: Int): String = in.toString - val sf: StringFunc = () => 55 - - sf.func() must_== "55" - } - - } - - "A NodeSeqFunc" should { - - "be created by a NodeSeq constant" in { - val sf: NodeSeqFunc = Foo - - sf.func() must ==/ (Foo) - } - - "be created by a NodeSeq Function" in { - val sf: NodeSeqFunc = () => Bar - - sf.func() must ==/ (Bar) - } - - "be created by a constant that can be converted to a NodeSeq" in { - implicit def intToNS(in: Int): NodeSeq = {in} - val sf: NodeSeqFunc = 55 - - sf.func() must ==/ (55) - } - - "be created by a function that can be converted to a NodeSeq" in { - implicit def intToNodeSeq(in: Int): NodeSeq = {in} - val sf: NodeSeqFunc = () => 55 - - sf.func() must ==/ (55) - } - - } - -} - diff --git a/core/common/src/test/scala-2.13/net/liftweb/common/HListSpec.scala b/core/common/src/test/scala-2.13/net/liftweb/common/HListSpec.scala deleted file mode 100644 index 6654ca9c78..0000000000 --- a/core/common/src/test/scala-2.13/net/liftweb/common/HListSpec.scala +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright 2010-2026 Lift Committers and Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package net.liftweb -package common - -import org.specs2.mutable.Specification - - -/** - * System under specification for Heterogeneous List. - */ -class HListSpec extends Specification { - - "An HList" should { - - "get the types right" in { - import HLists._ - - val x = 1 :+: "Foo" :+: HNil - - val head: Int = x.head - val head2: String = x.tail.head - - x.head must_== 1 - x.tail.head must_== "Foo" - } - - "properly report its length" in { - import HLists._ - - val x = 1 :+: "Foo" :+: HNil - - HNil.length must_== 0 - x.length must_== 2 - ("Bam" :+: x).length must_== 3 - } - } - - "A combinable box" should { - - "have a box built with a failure result in a failure" in { - import CombinableBox._ - - val x = Full("a") :&: Full(1) :&: Empty - - // result in a failure - x match { - case Left(_) => success - case _ => failure - } - } - - "be able to build a box with all the Full elements matching" in { - import CombinableBox._ - import HLists._ - - val x = Full("a") :&: Full(1) :&: Full(List(1,2,3)) - - // result in a failure - x match { - case Right(a :+: one :+: lst :+:HNil) => { - // val a2: Int = a fails... not type safe - - val as: String = a - val onei: Int = one - val lstl: List[Int] = lst - - success - } - - case Right(_) => failure - case Left(_) => failure - } - } - - "be usable in for comprehension" in { - import CombinableBox._ - import HLists._ - - val res = for { - a :+: one :+: lst :+: _ <- - (Full("a") ?~ "Yak" :&: Full(1) :&: Full(List(1,2,3))) ?~! "Dude" - } yield a.length * one * lst.foldLeft(1)(_ * _) - - res must_== Full(6) - } - } - -} - diff --git a/core/common/src/test/scala-2.13/net/liftweb/common/LoggingSpec.scala b/core/common/src/test/scala-2.13/net/liftweb/common/LoggingSpec.scala deleted file mode 100644 index 05df4f81ad..0000000000 --- a/core/common/src/test/scala-2.13/net/liftweb/common/LoggingSpec.scala +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Copyright 2010-2026 Lift Committers and Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package net.liftweb -package common - -import org.specs2.mutable.Specification - - -/** - * System under specification for Logging. - * - * Tests rely on logback being in the classpath, so no configuration should be necessary. - */ -class LoggingSpec extends Specification { - "Logging" can { - "be mixed directly into object" in { - object MyObj extends Logger { - info("direct Hello") - val x = 2 - } - MyObj.x must_== 2 - - (new MyTopClass).x must_== 1 - MyTopObj.x must_==1 - } - - "be nested in object" in { - object MyObj extends Loggable { - logger.info("nested Hello") - val x = 2 - } - - MyObj.x must_== 2 - - } - - "create named loggers" in { - val logger = Logger("MyLogger") - - logger.info("Logged with my named logger") - success - } - - "log static MDC values" in { - val logger = Logger("StaticMDC") - - logger.info("Logged with no MDC") - MDC.put("mdc1" -> (1,2)) - logger.info("Logged with mdc1=(1,2)") - MDC.put("mdc2" -> "yy") - logger.info("Logged with mdc1=(1,2), mdc2=yy") - MDC.put("mdc1" -> 99) - logger.info("Logged with mdc1=99, mdc2=yy") - MDC.remove("mdc1") - logger.info("Logged with mdc2=yy") - MDC.clear() - logger.info("Logged with no MDC") - success - } - - "save MDC context with logWith" in { - val logger = Logger("logWith") - - logger.info("Logged with no MDC") - MDC.put("mdc1" -> (1,2), "mdc2" -> "yy") - logger.info("Logged with mdc1=(1,2), mdc2=yy") - Logger.logWith("mdc2" -> "xx") { - logger.info("Logged with mdc1=(1,2), mdc2=xx") - Logger.logWith("mdc1" -> 99) { - logger.info("Logged with mdc1=99, mdc2=xx") - } - logger.info("Logged with mdc1=(1,2), mdc2=xx") - } - logger.info("Logged with mdc1=(1,2), mdc2=yy") - MDC.clear() - logger.info("No MDC values") - success - } - "trace function results" in { - object MyObj extends Logger { - val l = 1 to 10 - info("Starting test") - trace("result",l.foldLeft(0)(trace("lhs",_) + trace("rhs",_))) must_== l.foldLeft(0)(_+_) - val x = 1 - } - MyObj - success - } - - "be used in different levels and yield different loggers" in { - class First { - First.info("In first") - } - object First extends Logger - - trait Second { - private val logger = Logger(classOf[Second]) - logger.info("In second") - } - - class C extends First with Second with Logger { - info("In C") - val x = 2 - } - (new C).x must_== 2 - } - } -} - - -class MyTopClass extends Logger { - val x=1 - debug("Top level class logging") -} - - -object MyTopObj extends Logger { - val x=1 - debug("Top level object logging") -} - diff --git a/core/common/src/test/scala-2.13/net/liftweb/common/LruMapSpec.scala b/core/common/src/test/scala-2.13/net/liftweb/common/LruMapSpec.scala deleted file mode 100644 index 92c66de6d2..0000000000 --- a/core/common/src/test/scala-2.13/net/liftweb/common/LruMapSpec.scala +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright 2010-2026 Lift Committers and Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package net.liftweb -package common - -import org.specs2.mutable.Specification - - -/** - * Systems under specification for LRU Map. - */ -class LruMapSpec extends Specification { - - "An LRU Map" should { - - "never grow beyond the given size" in { - val lru = new LRUMap[Int, Int](10) - for (i <- 1 to 20) lru(i) = i - - lru.size must_== 10 - } - - "have the last N elements (where N is the initial MaxSize)" in { - val lru = new LRUMap[Int, Int](10) - for (i <- 1 to 20) lru(i) = i - - lru.size must_== 10 - ((i:Int) => lru(i) must_== i).forall(11 to 20) - } - - "expire elements to func" in { - var expCnt = 0 - val lru = new LRUMap[Int, Int](10, Empty, (k, v) => {expCnt += 1; k must_== v; k must be > 0; v must be < 11}) - for (i <- 1 to 20) lru(i) = i - - lru.size must_== 10 - expCnt must_== 10 - ((i:Int) => lru(i) must_== i).forall(11 to 20) - } - - "not expire the recently accessed elements" in { - var expCnt = 0 - val lru = new LRUMap[Int, Int](10, Empty, (k, v) => {expCnt += 1; k must_== v; k must be > 0}) - for (i <- 1 to 20) { - for (q <- 1 to 10) lru.get(q) - lru(i) = i - } - - lru.size must_== 10 - for (i <- 2 to 10) lru(i) must_== i - lru(20) must_== 20 - } - - } - -} - diff --git a/core/common/src/test/scala-3/net/liftweb/common/BoxLoggingSpec.scala b/core/common/src/test/scala/net/liftweb/common/BoxLoggingSpec.scala similarity index 100% rename from core/common/src/test/scala-3/net/liftweb/common/BoxLoggingSpec.scala rename to core/common/src/test/scala/net/liftweb/common/BoxLoggingSpec.scala diff --git a/core/common/src/test/scala-3/net/liftweb/common/BoxSpec.scala b/core/common/src/test/scala/net/liftweb/common/BoxSpec.scala similarity index 100% rename from core/common/src/test/scala-3/net/liftweb/common/BoxSpec.scala rename to core/common/src/test/scala/net/liftweb/common/BoxSpec.scala diff --git a/core/common/src/test/scala-3/net/liftweb/common/ConversionsSpec.scala b/core/common/src/test/scala/net/liftweb/common/ConversionsSpec.scala similarity index 100% rename from core/common/src/test/scala-3/net/liftweb/common/ConversionsSpec.scala rename to core/common/src/test/scala/net/liftweb/common/ConversionsSpec.scala diff --git a/core/common/src/test/scala-3/net/liftweb/common/HListSpec.scala b/core/common/src/test/scala/net/liftweb/common/HListSpec.scala similarity index 100% rename from core/common/src/test/scala-3/net/liftweb/common/HListSpec.scala rename to core/common/src/test/scala/net/liftweb/common/HListSpec.scala diff --git a/core/common/src/test/scala-3/net/liftweb/common/LoggingSpec.scala b/core/common/src/test/scala/net/liftweb/common/LoggingSpec.scala similarity index 100% rename from core/common/src/test/scala-3/net/liftweb/common/LoggingSpec.scala rename to core/common/src/test/scala/net/liftweb/common/LoggingSpec.scala diff --git a/core/common/src/test/scala-3/net/liftweb/common/LruMapSpec.scala b/core/common/src/test/scala/net/liftweb/common/LruMapSpec.scala similarity index 100% rename from core/common/src/test/scala-3/net/liftweb/common/LruMapSpec.scala rename to core/common/src/test/scala/net/liftweb/common/LruMapSpec.scala diff --git a/core/util/src/main/scala/net/liftweb/util/JsonCmd.scala b/core/util/src/main/scala/net/liftweb/util/JsonCmd.scala index 38f2997fed..d2deeb562c 100644 --- a/core/util/src/main/scala/net/liftweb/util/JsonCmd.scala +++ b/core/util/src/main/scala/net/liftweb/util/JsonCmd.scala @@ -39,21 +39,16 @@ import org.json4s.native.JsonMethods._ * make some sense of it. */ object JsonCommand { - import scala.language.implicitConversions - - implicit def iterableToOption[X](in: Iterable[X]): Option[X] = in.toSeq.headOption - - def unapply(in: JValue): Option[(String, Option[String], JValue)] = - for { - JString(command) <- in \ "command" - params <- in \ "params" - if params != JNothing - } yield { - val target = (in \ "target") match { - case JString(t) => Some(t) - case _ => None + def unapply(in: JValue): Option[(String, Option[String], JValue)] = { + val command = (in \ "command") match { case JString(c) => Some(c); case _ => None } + val params = in \ "params" + for { + c <- command + if params != JNothing + } yield { + val target = (in \ "target") match { case JString(t) => Some(t); case _ => None } + (c, target, params) } - (command, target, params) } // Some((in.command, in.target, in.params, in.all)) } diff --git a/core/util/src/test/scala-2.13/net/liftweb/util/BasicTypesHelpersSpec.scala b/core/util/src/test/scala-2.13/net/liftweb/util/BasicTypesHelpersSpec.scala deleted file mode 100644 index dfabe3dfc6..0000000000 --- a/core/util/src/test/scala-2.13/net/liftweb/util/BasicTypesHelpersSpec.scala +++ /dev/null @@ -1,193 +0,0 @@ -/* - * Copyright 2006-2026 Lift Committers and Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package net.liftweb -package util - -import java.io.ByteArrayInputStream - -import org.specs2.mutable.Specification -import org.specs2.matcher.DataTables - -import common._ -import BasicTypesHelpers._ - - -/** - * Systems under specification for BasicTypesHelpers. - */ -class BasicTypesHelpersSpec extends Specification with DataTables { - "BasicTypesHelpers Specification".title - - "Basic types helpers" should { - - "be lazy" in { - (false.?[Int]({throw new Exception("Bummer")}).|(3)) must_== 3 - (true.?[Int](3).|({throw new Exception("Bummer")})) must_== 3 - } - - "provide a ternary operator: (condition) ? A | B" in { - (1 == 2) ? "a" | "b" must_== "b" - } - - "provide a ?> operator to add an element to a list if an expression is true" in { - (1 == 1) ?> "a" ::: List("b") must_== List("a", "b") - (1 == 2) ?> "a" ::: List("b") must_== List("b") - } - val failure = Failure(null, null, null) - "have a toBoolean method converting any object to a reasonable Boolean value" in { - toBoolean(null) must_== false - "object value" ||"boolean value" | - (0: Any) !!false | - 1 !!true | - true !!true | - false !!false | - "" !!false | - "string" !!false | - "t" !!true | - "total" !!false | - "T" !!true | - "This" !!false | - "0" !!false | - "on" !!true | - None !!false | - Some("t") !!true | - Empty !!false | - Full("t") !!true | - failure !!false | - List("t", "f") !!true |> { - (o: Any, result: Boolean) => toBoolean(o) must_== result - } - } - - "have a AsBoolean extractor converting any object to a reasonable Boolean value" in { - "object value" ||"boolean value" |> - "t" !!Some(true) | - "" !!None | - "string" !!None | - "total" !!None | - "T" !!Some(true) | - "This" !!None | - "0" !!Some(false) | { - (o: String, result: Option[Boolean]) => AsBoolean.unapply(o) must_== result - } - } - - "have an AsInt extractor converting any String to a reasonable Int value" in { - "object value" ||"int value" |> - "3" !!Some(3) | - "n" !!None | { - (o: String, result: Option[Int]) => AsInt.unapply(o) must_== result - } - } - - "have an AsLong extractor converting any String to a reasonable Long value" in { - "object value" ||"long value" |> - "3" !!Some(3L) | - "n" !!None | { - (o: String, result: Option[Long]) => AsLong.unapply(o) must_== result - } - } - - "have a toInt method converting any object to a reasonable Int value" in { - def date(t: Int) = new _root_.java.util.Date(t) - toInt(null) must_== 0 - "object value" ||"int value" |> - 1 !!1 | - 1L !!1 | - List(1, 2) !!1 | - Some(1) !!1 | - Full(1) !!1 | - None !!0 | - Empty !!0 | - failure !!0 | - "3" !!3 | - "n" !!0 | - date(3000) !!3 | { - (o: Any, result: Int) => toInt(o) must_== result - } - } - - "have a toLong method converting any object to a reasonable Long value" in { - def date(t: Int) = new _root_.java.util.Date(t) - toLong(null) must_== 0L - "object value" ||"long value" |> - 1 !!1L | - 1L !!1L | - List(1, 2) !!1L | - Some(1) !!1L | - Full(1) !!1L | - None !!0L | - Empty !!0L | - failure !!0L | - "3" !!3L | - "n" !!0L | - date(3000) !!3000L | { - (o: Any, result: Long) => toLong(o) must_== result - } - } - - "have a toByteArrayInputStream reading an InputStream to a ByteArrayInputStream" in { - var array: Array[Byte] = Array(12, 14) - val input = new ByteArrayInputStream(array) - val result = toByteArrayInputStream(input) - result.read must_== 12 - result.read must_== 14 - } - "have a isEq method comparing 2 Byte arrays and returning true if they contain the same elements" in { - var a: Array[Byte] = Array(12, 14) - var b: Array[Byte] = Array(12, 14) - var c: Array[Byte] = Array(12, 13) - isEq(a, b) must beTrue - isEq(a, c) must beFalse - } - "have a notEq method comparing 2 Byte arrays and returning true if they don't contain the same elements" in { - var a: Array[Byte] = Array(12, 14) - var b: Array[Byte] = Array(12, 13) - BasicTypesHelpers.notEq(a, b) must beTrue - } - } - - "PartialFunction guard" should { - - "put a guard around a partial function" in { - val pf1: PartialFunction[String, Unit] = { - case s if s.startsWith("s") => - } - - val pf2: PartialFunction[String, Boolean] = { - case "snipe" => true - case "bipe" => false - } - - val pf3 = pf1.guard(pf2) - val pf4: PartialFunction[String, Boolean] = pf1.guard(pf3) - - pf3.isDefinedAt("bipe") must_== false - pf3.isDefinedAt("snipe") must_== true - } - } - - "AvoidTypeErasure implicit value" should { - "be in scope" in { - def f(i:Int)(implicit d: AvoidTypeErasureIssues1) = i+1 - - f(2) must_== 3 - } - } - -} - diff --git a/core/util/src/test/scala-2.13/net/liftweb/util/BundleBuilderSpec.scala b/core/util/src/test/scala-2.13/net/liftweb/util/BundleBuilderSpec.scala deleted file mode 100644 index cfe8cccffa..0000000000 --- a/core/util/src/test/scala-2.13/net/liftweb/util/BundleBuilderSpec.scala +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright 2010-2026 Lift Committers and Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package net.liftweb -package util - -import java.util.Locale - -import scala.xml.NodeSeq - -import org.specs2.matcher.XmlMatchers -import org.specs2.mutable.Specification - - -/** - * Systems under specification for BundleBuilder. - */ -class BundleBuilderSpec extends Specification with XmlMatchers { - "BundleBuilder Specification".title - - "BundleBuilder" should { - "Build a Bundle" in { - val b = BundleBuilder.convert(
-
Dog
-
Chien
-
hi
-
, Locale.US).openOrThrowException("Test") - - b.getObject("dog") must_== "Dog" - b.getObject("cat").asInstanceOf[NodeSeq] must ==/ (
hi
) - } - - "Build a Bundle must support default" in { - val b = BundleBuilder.convert(
-
Dog
-
Chien
-
hi
-
, Locale.US).openOrThrowException("Test") - - b.getObject("dog") must_== "Chien" - b.getObject("cat").asInstanceOf[NodeSeq] must ==/ (
hi
) - } - - } -} - diff --git a/core/util/src/test/scala-2.13/net/liftweb/util/CanResolveAsyncSpec.scala b/core/util/src/test/scala-2.13/net/liftweb/util/CanResolveAsyncSpec.scala deleted file mode 100644 index 14d156d98e..0000000000 --- a/core/util/src/test/scala-2.13/net/liftweb/util/CanResolveAsyncSpec.scala +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 2015-2026 Lift Committers and Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package net.liftweb -package util - -import scala.concurrent.{Future, Promise} -import scala.concurrent.ExecutionContext.Implicits.global - -import org.specs2.mutable.Spec - -import actor.LAFuture - -object CanResolveAsyncSpec extends Spec { - "CanResolveAsync" should { - "resolve Scala Futures" in { - val myPromise = Promise[String]() - - val resolver = implicitly[CanResolveAsync[Future[String], String]] - - val receivedResolution = new LAFuture[String] - resolver.resolveAsync(myPromise.future, receivedResolution.satisfy _) - - myPromise.success("All done!") - - receivedResolution.get must_== "All done!" - } - - "resolve LAFutures" in { - val myFuture = new LAFuture[String] - - val resolver = implicitly[CanResolveAsync[LAFuture[String], String]] - - val receivedResolution = new LAFuture[String] - resolver.resolveAsync(myFuture, receivedResolution.satisfy _) - - myFuture.satisfy("Got it!") - - receivedResolution.get must_== "Got it!" - } - } -} diff --git a/core/util/src/test/scala-2.13/net/liftweb/util/ClassHelpersSpec.scala b/core/util/src/test/scala-2.13/net/liftweb/util/ClassHelpersSpec.scala deleted file mode 100644 index 072a118d1e..0000000000 --- a/core/util/src/test/scala-2.13/net/liftweb/util/ClassHelpersSpec.scala +++ /dev/null @@ -1,185 +0,0 @@ -/* - * Copyright 2006-2026 Lift Committers and Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package net.liftweb -package util - -import org.specs2.mutable.Specification - -import common._ -import ClassHelpers._ - - -/** - * Systems under specification for ClassHelpers. - */ -class ClassHelpersSpec extends Specification { - "ClassHelpers Specification".title - - "The findType function" should { - "return a Full can with the found class when given the type, the name, and a list of packages to conform to" in { - findType[java.util.List[Object]]("ArrayList", List("java.util")) must_== Full(classOf[java.util.ArrayList[Object]]) - } - "return an Empty can if the class cannot be coerced to the expected type" in { - findType[String]("ClassHelpers", List("net.liftweb.util")) must_== Empty - } - } - "the findClass function" should { - "return a Full can with the found class when given the name and package" in { - findClass("ClassHelpers", List("net.liftweb.util")) must_== Full(classOf[ClassHelpers]) - } - "return a Full can with the found class when given the name and package, with an underscored name instead of CamelCased" in { - findClass("class_helpers", List("net.liftweb.util")) must_== Full(classOf[ClassHelpers]) - } - "return a Full can with the found class when given the name and a list of packages" in { - findClass("ClassHelpers", List("net.liftweb.util", "java.util")) must_== Full(classOf[ClassHelpers]) - findClass("ArrayList", List("net.liftweb.util", "java.util")) must_== Full(classOf[java.util.ArrayList[_]]) - } - "return a Full can with the found class when given the name, a list of packages and a target type to conform to" in { - findClass("ArrayList", List("java.util"), classOf[java.util.List[Object]]) must_== Full(classOf[java.util.ArrayList[Object]]) - } - "return an Empty can if no class is found given a name and package" in { - findClass("ClassHelpers", List("net.liftweb.nothere")) must_== Empty - } - "return an Empty can if the class cannot be coerced to the expected type" in { - findClass("ClassHelpers", List("net.liftweb.util"), classOf[String]) must_== Empty - } - } - - "The findClass function" should { - "return a Full can with the found class when given a list of names and corresponding packages" in { - findClass(List(("wrong name", List("net.liftweb.util", "other.package")), - ("ClassHelpers", List("net.liftweb.util", "other.package")))) must_== Full(classOf[ClassHelpers]) - } - "use a list of modifiers functions to try to modify the original name in order to find the class" in { - findClass("classHelpers", List("net.liftweb.util"), List((n: String) => n.capitalize)) must_== Full(classOf[ClassHelpers]) - } - } - - "The callableMethod_? function" should { - "return true if the method is public and has no parameters" in { - val publicParameterLess = classOf[String].getMethod("length") - callableMethod_?(publicParameterLess) must beTrue - } - "return false if the method is public and has parameters" in { - val publicWithParameters = classOf[String].getMethod("indexOf", classOf[String]) - callableMethod_?(publicWithParameters) must beFalse - } - "return false if the method is private" in { - val privateMethod = classOf[java.util.ArrayList[Object]].getDeclaredMethod("readObject", classOf[java.io.ObjectInputStream]) - callableMethod_?(privateMethod) must beFalse - } - "return false if the method is null" in { - callableMethod_?(null) must beFalse - } - } - - "The containsClass function" should { - "return false if the list to match is null or empty" in { - containsClass(classOf[String], null) must beFalse - containsClass(classOf[String], Nil) must beFalse - } - "return false if the list to match doesn't contain any class assignable by the tested class" in { - containsClass(classOf[String], List(classOf[Float], classOf[java.lang.Integer])) must beFalse - } - } - - "The classHasControllerMethod function" should { - "return true if the class has 'name' as a callable method" in { - classHasControllerMethod(classOf[String], "length") must beTrue - } - "return false if the class doesn't have 'name' as a method" in { - classHasControllerMethod(classOf[String], "isNotEmpty") must beFalse - } - "return false if the class has a method but it is not callable" in { - classHasControllerMethod(classOf[java.util.ArrayList[Object]], "readObject") must beFalse - } - "return false if the class is null" in { - classHasControllerMethod(null, "readObject") must beFalse - } - } - - "The invokeControllerMethod function" should { - "return the result of calling the method on a new instance of the class" in { - invokeControllerMethod(classOf[String], "length") must_== 0 - } - "throw an exception when the method is not callable" in { - invokeControllerMethod(classOf[String], "isNotEmpty") must throwA[NoSuchMethodException] - } - "throw an exception if the class is null" in { - invokeControllerMethod(null, "length") must throwA[NullPointerException] - } - } - - "The invokeMethod function" should { - "return a Failure if the class is null" in { - invokeMethod(null, "", "length") must beLike { case Failure(_, _, _) => 1 must_== 1 } - } - "return a Failure if the instance is null" in { - invokeMethod(classOf[String], null, "length") must beLike { case Failure(_, _, _) => 1 must_== 1 } - } - "return a Failure if the method name is null" in { - invokeMethod(classOf[String], "", null) must beLike { case Failure(_, _, _) => 1 must_== 1 } - } - "return a Failure if the method doesnt exist on the class" in { - invokeMethod(classOf[String], "", "isNotEmpty") must beLike { case Failure(_, _, _) => 1 must_== 1 } - } - "return a Full can with the result if the method exist on the class" in { - invokeMethod(classOf[String], "", "length") must_== Full(0) - } - "return a Full can with the result if the method is an existing static method on the class" in { - invokeMethod(classOf[java.util.Calendar], null, "getInstance").isEmpty must_== false - } - "throw an exception if the method throws an exception" in { - class SpecificException extends Exception - class TestSnippet { def throwException = throw new SpecificException } - val testSnippet = new TestSnippet - invokeMethod(testSnippet.getClass, testSnippet, "throwException") must throwA[SpecificException] - } - } - - "The invokeMethod function" can { - "call a method with its parameters" in { - invokeMethod(classOf[String], "", "valueOf", Array("1")) must_== Full("1") - } - "call a method with its parameters and parameter types" in { - invokeMethod(classOf[String], "", "valueOf", Array("c"), Array(classOf[String])) must_== Full("c") - } - } - - "The instantiate function" should { - "return a full can if a class can be instantiated with a new instance" in { - instantiate(classOf[String]) must_== Full("") - } - "return a failure if a class can not be instantiated with a new instance" in { - instantiate(classOf[java.util.Calendar]) must beLike { case Failure(_, _, _) => 1 must_== 1 } - } - } - - "The createInvoker function" should { - "return Empty if the instance is null" in { - createInvoker("length", null) must_== Empty - } - "return a Full Box with the function from Unit to a Box containing the result of the method to invoke" in { - createInvoker("length", "").openOrThrowException("Test").apply() must_== Full(0) - } - "The invoker function will throw the cause exception if the method can't be called" in { - (() => createInvoker("get", "").openOrThrowException("Test").apply())() must throwA[Exception] - } - } - -} - diff --git a/core/util/src/test/scala-2.13/net/liftweb/util/CombParserHelpersSpec.scala b/core/util/src/test/scala-2.13/net/liftweb/util/CombParserHelpersSpec.scala deleted file mode 100644 index 447d4b0e84..0000000000 --- a/core/util/src/test/scala-2.13/net/liftweb/util/CombParserHelpersSpec.scala +++ /dev/null @@ -1,181 +0,0 @@ -/* - * Copyright 2007-2026 Lift Committers and Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package net.liftweb -package util - -import scala.util.parsing.combinator.Parsers - -import org.specs2.mutable.Specification -import org.specs2.ScalaCheck -import org.scalacheck.{Arbitrary, Gen, Prop} -import Gen._ -import Prop._ - - -class CombParserHelpersSpec extends Specification with ScalaCheck { - "CombParserHelpers Specification".title - - object ParserHelpers extends CombParserHelpers with Parsers - import ParserHelpers._ - - "The parser helpers" should { - "provide an isEof function returning true iff a char is end of file" in { - isEof('\u001a') must beTrue - } - "provide an notEof function returning true iff a char is not end of file" in { - notEof('\u001a') must beFalse - } - "provide an isNum function returning true iff a char is a digit" in { - isNum('0') must beTrue - } - "provide an notNum function returning true iff a char is not a digit" in { - notNum('0') must beFalse - } - "provide an wsc function returning true iff a char is a space character" in { - List(' ', '\t', '\r', '\n') foreach {wsc(_) must beTrue} - wsc('a') must beFalse - } - "provide a whitespace parser: white. Alias: wsc" in { - import WhiteStringGen._ - val whiteParse = (s: String) => wsc(s).isInstanceOf[Success[_]] - forAll(whiteParse) - } - "provide a whiteSpace parser always succeeding and discarding its result" in { - import StringWithWhiteGen._ - val whiteSpaceParse = - (s: String) => whiteSpace(s) must beLike { - case Success(x, y) => x.toString must_== "()" - } - forAll(whiteSpaceParse) - } - "provide an acceptCI parser to parse whatever string matching another string ignoring case" in { - import AbcdStringGen._ - val ignoreCaseStringParse: Function2[String, String, Boolean] = - (s: String, s2: String) => acceptCI(s).apply(s2) match { - case Success(x, y) => s2.toUpperCase must startWith(s.toUpperCase) - case _ => true - } - forAll(ignoreCaseStringParse) - } - - "provide a digit parser - returning a String" in { - val isDigit: String => Boolean = - (s: String) => digit(s) match { - case Success(x, y) => s must beMatching ("(?s)\\p{Nd}.*") - case _ => true - } - forAll(isDigit) - } - "provide an aNumber parser - returning an Int if succeeding" in { - val number: String => Boolean = - (s: String) => { - aNumber(s) match { - case Success(x, y) => s must beMatching ("(?s)\\p{Nd}+.*") - case _ => true - } - } - forAll(number) - } - - "provide a slash parser" in { - slash("/").get must_== '/' - slash("x") must beLike {case Failure(_, _) => 1 must_== 1} - } - "provide a colon parser" in { - colon(":").get must_== ':' - colon("x") must beLike {case Failure(_, _) => 1 must_== 1} - } - "provide a EOL parser which parses the any and discards any end of line character" in { - List("\n", "\r") map { - s => - val result = EOL(s) - result.get.toString must_== "()" - result.next.atEnd must beTrue - } - - success - } - val parserA = elem("a", (c: Char) => c == 'a') - val parserB = elem("b", (c: Char) => c == 'b') - val parserC = elem("c", (c: Char) => c == 'c') - val parserD = elem("d", (c: Char) => c == 'd') - def shouldSucceed[T](r: ParseResult[T]) = r match { - case Success(x, y) => true - case _ => false - } - "provide a permute parser succeeding if any permutation of given parsers succeeds" in { - def permuteParsers(s: String) = shouldSucceed(permute(parserA, parserB, parserC, parserD)(s)) - val permutationOk = (s: String) => permuteParsers(s) - - forAll(AbcdStringGen.abcdString)(permutationOk) - } - "provide a permuteAll parser succeeding if any permutation of the list given parsers, or a sublist of the given parsers succeeds" in { - def permuteAllParsers(s: String) = shouldSucceed(permuteAll(parserA, parserB, parserC, parserD)(s)) - implicit def pick3Letters: Arbitrary[String] = AbcdStringGen.pickN(3, List("a", "b", "c")) - - forAll { (s: String) => - ((new scala.collection.immutable.StringOps(s)).nonEmpty) ==> permuteAllParsers(s) - } - } - "provide a repNN parser succeeding if an input can be parsed n times with a parser" in { - def repNNParser(s: String) = shouldSucceed(repNN(3, parserA)(s)) - implicit def pick3Letters: Arbitrary[String] = AbcdStringGen.pickN(3, List("a", "a", "a")) - - forAll { (s: String) => - ((new scala.collection.immutable.StringOps(s)).nonEmpty) ==> repNNParser(s) - } - } - } -} - - -object AbcdStringGen { - implicit def abcdString: Gen[String] = - for ( - len <- choose(4, 4); - string <- pick(len, List("a", "b", "c", "d")) - ) yield string.mkString("") - - def pickN(n: Int, elems: List[String]) = - Arbitrary { for (string <- pick(n, elems)) yield string.mkString("") } -} - - -object WhiteStringGen { - def genWhite = - for ( - len <- choose(1, 4); - string <- listOfN(len, frequency((1, Gen.const(" ")), (1, Gen.const("\t")), (1, Gen.const("\r")), (1, Gen.const("\n")))) - ) yield string.mkString("") - - implicit def genWhiteString: Arbitrary[String] = - Arbitrary { genWhite } -} - - -object StringWithWhiteGen { - import WhiteStringGen._ - - def genStringWithWhite = - for ( - len <- choose(1, 4); - string <- listOfN(len, frequency((1, Gen.const("a")), (2, Gen.const("b")), (1, genWhite))) - ) yield string.mkString("") - - implicit def genString: Arbitrary[String] = - Arbitrary { genStringWithWhite } -} diff --git a/core/util/src/test/scala-2.13/net/liftweb/util/ConnectionIdentifierSpec.scala b/core/util/src/test/scala-2.13/net/liftweb/util/ConnectionIdentifierSpec.scala deleted file mode 100644 index c6cc411118..0000000000 --- a/core/util/src/test/scala-2.13/net/liftweb/util/ConnectionIdentifierSpec.scala +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 2014-2026 Lift Committers and Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package net.liftweb -package util - -import org.specs2.mutable.Specification - -/** - * Systems under specification for ConnectionIdentifier. - */ -class ConnectionIdentifierSpec extends Specification { - "ConnectionIdentifier Specification".title - - "Connection identifier" should { - - "be set by property" in { - DefaultConnectionIdentifier.jndiName must_== "from_props" - } - } -} diff --git a/core/util/src/test/scala-2.13/net/liftweb/util/ControlHelpersSpec.scala b/core/util/src/test/scala-2.13/net/liftweb/util/ControlHelpersSpec.scala deleted file mode 100644 index 678573d58f..0000000000 --- a/core/util/src/test/scala-2.13/net/liftweb/util/ControlHelpersSpec.scala +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright 2006-2026 Lift Committers and Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package net.liftweb -package util - -import org.specs2.mutable.Specification - -import common._ -import ControlHelpers._ - - -/** - * Systems under specification for ControlHelpers. - */ -class ControlHelpersSpec extends Specification { - "ControlHelpers Specification".title - - "the tryo function" should { - "return a Full can if the tested block doesn't throw an exception" in { - tryo { "valid" } must_== Full("valid") - } - val exception = new RuntimeException("ko") - def failureBlock = { throw exception; () } - - "return a Failure if the tested block throws an exception" in { - tryo { failureBlock } must_== Failure(exception.getMessage, Full(exception), Empty) - } - "return Empty if the tested block throws an exception whose class is in the ignore list - with one element" in { - tryo(classOf[RuntimeException]) { failureBlock } must_== Empty - } - "return Empty if the tested block throws an exception whose class is in the ignore list - with 2 elements" in { - tryo(List(classOf[RuntimeException], classOf[NullPointerException])) { failureBlock } must_== Empty - } - "trigger a callback function with the exception if the tested block throws an exception" in { - val callback = (e: Throwable) => { e must_== exception; () } - tryo(callback) { failureBlock } - success - } - "trigger a callback function with the exception if the tested block throws an exception even if it is ignored" in { - val callback = (e: Throwable) => { e must_== exception; () } - tryo(List(classOf[RuntimeException]), Full(callback)) { failureBlock } - success - } - "don't trigger a callback if the tested block doesn't throw an exception" in { - var x = false - val callback = (e: Throwable) => { x = true } - tryo(callback) { "valid" } - x must_== false - } - "don't trigger a callback if the tested block doesn't throw an exception, even with an ignore list" in { - var x = false - val callback = (e: Throwable) => { x = true } - tryo(List(classOf[RuntimeException]), Full(callback)) { "valid" } - x must_== false - } - } -} - diff --git a/core/util/src/test/scala-2.13/net/liftweb/util/CssHelpersSpec.scala b/core/util/src/test/scala-2.13/net/liftweb/util/CssHelpersSpec.scala deleted file mode 100644 index af50ae2658..0000000000 --- a/core/util/src/test/scala-2.13/net/liftweb/util/CssHelpersSpec.scala +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright 2007-2026 Lift Committers and Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package net.liftweb -package util - -import scala.xml._ - -import org.specs2.mutable.Specification - -import common._ - -class CssHelpersSpec extends Specification { - import CSSHelpers._ - - "CSSParser" should { - "leave most CSS alone" in { - val baseCss = - """ - #booyan { - text-indent: 1em; - -moz-columns: 3; - -webkit-text-antialiasing: grayscale; - -magical-fake-thing: booyan; - superfake: but-still-reasonably-css-y; - } - """ - - CssUrlPrefixer("prefix").fixCss(baseCss) must_== Full(baseCss) - } - - "leave relative CSS urls alone" in { - val baseCss = - """ - #booyan { - background: url(boom); - background-image: url('boom?bam,sloop#"shap%20bap'); - image-set: url("http://boom.com/magic?'bam,sloop#bam%21bap") - } - - .bam { - background-image: url("boom?bam,sloop#shap%20bap"); - } - """ - - CssUrlPrefixer("prefix").fixCss(baseCss) must_== Full(baseCss) - } - - "prefix root-relative CSS urls with the specified prefix" in { - val baseCss = - """ - |#booyan { - | background: url(/boom); - | background-image: url('/boom?bam,"sloop#shap%20bap'); - | image-set: url("/boom.com/magic?bam,'sloop#bam%21bap") - |}""".stripMargin('|') - - CssUrlPrefixer("prefix").fixCss(baseCss) must_== - Full( - """ - |#booyan { - | background: url(prefix/boom); - | background-image: url('prefix/boom?bam,"sloop#shap%20bap'); - | image-set: url("prefix/boom.com/magic?bam,'sloop#bam%21bap") - |}""".stripMargin('|') - ) - } - - "fail on mismatched quotes or parens and report where it failed" in { - CssUrlPrefixer("prefix").fixCss("#boom { url('ha) }") must beLike { - case Failure(message, _, _) => - message must contain("'ha") - } - - CssUrlPrefixer("prefix").fixCss("#boom { url(\"ha) }") must beLike { - case Failure(message, _, _) => - message must contain("\"ha") - } - - CssUrlPrefixer("prefix").fixCss("#boom { url('ha' }") must beLike { - case Failure(message, _, _) => - message must contain("ha' }") - } - } - - // Escaped quotes-in-quotes currently fail. Maybe we want to support these? - } -} diff --git a/core/util/src/test/scala-2.13/net/liftweb/util/CssSelectorSpec.scala b/core/util/src/test/scala-2.13/net/liftweb/util/CssSelectorSpec.scala deleted file mode 100755 index 6c57b8ecb7..0000000000 --- a/core/util/src/test/scala-2.13/net/liftweb/util/CssSelectorSpec.scala +++ /dev/null @@ -1,1027 +0,0 @@ -/* - * Copyright 2010-2026 Lift Committers and Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package net.liftweb -package util - -import org.specs2.matcher.XmlMatchers -import org.specs2.mutable.Specification - -import common._ -import scala.xml._ - -import Helpers._ - -/** - * Systems under specification for CSS Selector. - */ -class CssSelectorSpec extends Specification with XmlMatchers { - "CSS Selector Specification".title - - "CssSelector" should { - "fail for garbage input" in { - CssSelectorParser.parse(" 49234e23").isDefined must_== false - } - - "select an id" in { - CssSelectorParser.parse("#foo").openOrThrowException("If the box is empty, we want a failure") must_== - IdSelector("foo", Empty) - } - - "a selector with cruft at the end must fail" in { - CssSelectorParser.parse("#foo I li**ke yaks").isDefined must_== false - } - - ":yak must not parse" in { - CssSelectorParser.parse(":yak").isDefined must_== false - } - - ":button must parse" in { - CssSelectorParser.parse(":button").openOrThrowException("If the box is empty, we want a failure") must_== - AttrSelector("type", "button", Empty) - } - - - ":checkbox must parse" in { - CssSelectorParser.parse(":checkbox").openOrThrowException("If the box is empty, we want a failure") must_== - AttrSelector("type", "checkbox", Empty) - } - - ":file must parse" in { - CssSelectorParser.parse(":file").openOrThrowException("If the box is empty, we want a failure") must_== - AttrSelector("type", "file", Empty) - } - - ":password must parse" in { - CssSelectorParser.parse(":password").openOrThrowException("If the box is empty, we want a failure") must_== - AttrSelector("type", "password", Empty) - } - - ":radio must parse" in { - CssSelectorParser.parse(":radio").openOrThrowException("If the box is empty, we want a failure") must_== - AttrSelector("type", "radio", Empty) - } - - ":reset must parse" in { - CssSelectorParser.parse(":reset").openOrThrowException("If the box is empty, we want a failure") must_== - AttrSelector("type", "reset", Empty) - } - - ":submit must parse" in { - CssSelectorParser.parse(":submit").openOrThrowException("If the box is empty, we want a failure") must_== - AttrSelector("type", "submit", Empty) - } - - ":text must parse" in { - CssSelectorParser.parse(":text").openOrThrowException("If the box is empty, we want a failure") must_== - AttrSelector("type", "text", Empty) - } - - "select an id with attr subnodes" in { - CssSelectorParser.parse("#foo *[dog] ").openOrThrowException("If the box is empty, we want a failure") must_== - IdSelector("foo", Full(AttrSubNode("dog"))) - } - - "select an id with no star attr subnodes" in { - CssSelectorParser.parse("#foo [woof] ").openOrThrowException("If the box is empty, we want a failure") must_== - IdSelector("foo", Full(AttrSubNode("woof"))) - } - - "select an id with attr append subnodes" in { - CssSelectorParser.parse("#foo *[dog+] ").openOrThrowException("If the box is empty, we want a failure") must_== - IdSelector("foo", Full(AttrAppendSubNode("dog"))) - } - - "select an id with no star attr append subnodes" in { - CssSelectorParser.parse("#foo [woof+] ").openOrThrowException("If the box is empty, we want a failure") must_== - IdSelector("foo", Full(AttrAppendSubNode("woof"))) - } - - "select an id with attr append subnodes" in { - CssSelectorParser.parse("#foo *[dog!] ").openOrThrowException("If the box is empty, we want a failure") must_== - IdSelector("foo", Full(AttrRemoveSubNode("dog"))) - } - - "select an id with no star attr append subnodes" in { - CssSelectorParser.parse("#foo [woof!] ").openOrThrowException("If the box is empty, we want a failure") must_== - IdSelector("foo", Full(AttrRemoveSubNode("woof"))) - } - - "select attr/val pair" in { - CssSelectorParser.parse("frog=dog") must_== - Full(AttrSelector("frog", "dog", Empty)) - } - - - "select attr/val pair single quote" in { - CssSelectorParser.parse("frog='dog food' *") must_== - Full(AttrSelector("frog", "dog food", Full(KidsSubNode()))) - } - - - "select attr/val pair double quote" in { - CssSelectorParser.parse("frog=\"dog breath\"") must_== - Full(AttrSelector("frog", "dog breath", Empty)) - } - - "select name/val pair" in { - CssSelectorParser.parse("name=dog") must_== - Full(NameSelector("dog", Empty)) - } - - "select name/val pair" in { - CssSelectorParser.parse("@dog") must_== - Full(NameSelector("dog", Empty)) - } - - "select name/val pair" in { - CssSelectorParser.parse("@dog *") must_== - Full(NameSelector("dog", Full(KidsSubNode()))) - } - - "select name/val pair" in { - CssSelectorParser.parse("@dog -*") must_== - Full(NameSelector("dog", Full(PrependKidsSubNode()))) - } - - "select name/val pair surround" in { - CssSelectorParser.parse("@dog <*>") must_== - Full(NameSelector("dog", Full(SurroundKids()))) - } - - "select name/val pair" in { - CssSelectorParser.parse("@dog *+") must_== - Full(NameSelector("dog", Full(AppendKidsSubNode()))) - } - - - "select name/val pair single quote" in { - CssSelectorParser.parse("name='dog food' *") must_== - Full(NameSelector("dog food", Full(KidsSubNode()))) - } - - - "select name/val pair double quote" in { - CssSelectorParser.parse("name=\"dog breath\"") must_== - Full(NameSelector("dog breath", Empty)) - } - - "select a class" in { - CssSelectorParser.parse(".foo").openOrThrowException("If the box is empty, we want a failure") must_== ClassSelector("foo", Empty) - } - - "select a class with subnodes" in { - CssSelectorParser.parse(".foo * ").openOrThrowException("If the box is empty, we want a failure") must_== - ClassSelector("foo", Full(KidsSubNode())) - } - - "Support selecting this node" in { - CssSelectorParser.parse(".foo ^^ ").openOrThrowException("If the box is empty, we want a failure") must_== - ClassSelector("foo", Full(SelectThisNode(false))) - } - - "Support selecting this node" in { - CssSelectorParser.parse(".foo ^* ").openOrThrowException("If the box is empty, we want a failure") must_== - ClassSelector("foo", Full(SelectThisNode(true))) - } - - "select a class with attr subnodes" in { - CssSelectorParser.parse(".foo *[dog] ").openOrThrowException("If the box is empty, we want a failure") must_== - ClassSelector("foo", Full(AttrSubNode("dog"))) - } - - "select an id with no star attr subnodes" in { - CssSelectorParser.parse(".foo [woof] ").openOrThrowException("If the box is empty, we want a failure") must_== - ClassSelector("foo", Full(AttrSubNode("woof"))) - } - - "select multiple depth" in { - CssSelectorParser.parse("div .foo [woof] ").openOrThrowException("If the box is empty, we want a failure") must_== - EnclosedSelector(ElemSelector("div", Empty), ClassSelector("foo", Full(AttrSubNode("woof")))) - } - - "select multiple depth with star" in { - CssSelectorParser.parse("div .foo * ").openOrThrowException("If the box is empty, we want a failure") must_== - EnclosedSelector(ElemSelector("div", Empty), ClassSelector("foo", Full(KidsSubNode()))) - } - - "select multiple super depth with star" in { - CssSelectorParser.parse("span div .foo * ").openOrThrowException("If the box is empty, we want a failure") must_== - EnclosedSelector(ElemSelector("span", Empty), EnclosedSelector(ElemSelector("div", Empty), ClassSelector("foo", Full(KidsSubNode())))) - } - - - } - -} - -class CssBindHelpersSpec extends Specification with XmlMatchers { - - "css bind helpers" should { - "clear clearable" in { - ClearClearable() must ==/ () - } - - "substitute a String by id" in { - ("#foo" #> "hello").apply() must ==/ (hello) - } - - - "not duplicate classes" in { - - def anchor(quesType: String, value: String) = { - (value) - } - var page = 1 - var elements = List("1","2","3","4") - - val xml =
-
- 1 - 1 - 1 -
- -
- - val sel = ".question" #> elements.map(value => { - ".question [id]" #> ("question-" + value) & - ".question [class]" #> ("question-" + value) & - ".L" #> anchor("L", value) & - ".U" #> anchor("U", value) & - ".D" #> anchor("D", value) - }) - - val res = sel(xml) - - ((res \\ "a").head \ "@class").head.text must_== "selected L" - } - - - "Compound selector" in { - val res = - (".foo [href]" #> "http://dog.com" & ".bar [id]" #> "moo").apply( - ) - (res \ "@href").text must_== "http://dog.com" - (res \ "@id").text must_== "moo" - } - - "not stack overflow on Elem" in { - val xf = "* [id]" #> "xx" & - "* [style]" #> "border:thin solid black" & - "* *" #> - success - } - - "not stack overflow on Elem" in { - val xf = "* [id]" #> "xx" & - "* [style]" #> "border:thin solid black" & - "* *+" #> - - xf(
) - success - } - - "not stack overflow on Elem" in { - val xf = "* [id]" #> "xx" & - "* [style]" #> "border:thin solid black" & - "* -*" #> - - xf(
) - success - } - - "data-name selector works" in { - val xf = ";frog" #> hi - - xf(
Moose
) must ==/ (
hi
) - } - - "support modifying attributes along with body" in { - val org =
foo - val func = "a [href]" #> "dog" & "a *" #> "bar" - val res = func(org) - - res.toString must_== "bar" - } - - "substitute a String by id" in { - ("#foo" replaceWith "hello").apply() must ==/ (hello) - } - - "substitute a String by nested class" in { - ("div .foo" #> "hello").apply(
) must ==/ (
hello
) - } - - "substitute a String by deep nested class" in { - ("#baz div .foo" #> "hello").apply( -
) must ==/ (
hello
) - } - - "insert a String by deep nested class" in { - ("#baz div .foo *" #> "hello").apply( -
) must ==/ (
hello
) - } - - - "Only apply to the top elem" in { - val xf = "^ [href]" #> "wombat" - - xf(stuff) must ==/ (stuff) - } - - - - "Select a node" in { - ("#foo ^^" #> "hello").apply(
) must ==/ () - } - - "Another nested select" in { - val template = -
- - -

-
-
- - -

-
-
- - val xf = "#get ^^" #> "ignore" & "#file_upload" #> - - val ret = xf(template) - - ret(0).asInstanceOf[Elem].label must_== "div" - ret.length must_== 1 - (ret \ "@id").text must_== "get" - - (ret \\ "input").length must_== 2 - - ((ret \\ "input").toList(0) \ "@type").map(_.text) must_== List("moose") - - } - - "Child nested select" in { - val template = -
- - -

-
-
- - -

-
-
- - val xf = "#get ^*" #> "ignore" & "#file_upload" #> - - val ret = xf(template) - - (ret \\ "div").length must_== 0 - - (ret \\ "input").length must_== 2 - - ((ret \\ "input").toList(0) \ "@type").map(_.text) must_== List("moose") - - } - - "Select a node and transform stuff" in { - val ret = ("#foo ^^" #> "hello" & - "span [id]" #> "bar")() - - ret(0).asInstanceOf[Elem].label must_== "span" - ret.length must_== 1 - (ret \ "@id").text must_== "bar" - } - - - "Select a node and transform stuff deeply nested" in { - val ret = ("#foo ^^" #> "hello" & - "span [id]" #> "bar")(
) - - ret(0).asInstanceOf[Elem].label must_== "span" - ret.length must_== 1 - (ret \ "@id").text must_== "bar" - } - - - "Select a node and transform stuff deeply nested 2" in { - val ret = ("#foo ^^" #> "hello" & - "span [id]" #> "bar")(
) - - ret(0).asInstanceOf[Elem].label must_== "span" - ret.length must_== 1 - (ret \ "@id").text must_== "bar" - (ret \ "@dog").text must_== "woof" - } - - - - "substitute multiple Strings by id" in { - ("#foo" #> "hello" & - "#baz" #> "bye" - )(
Hello
) must be_== (NodeSeq fromSeq {Text("bye")}{Text("hello")}) - } - - "bind href and None content" in { - val opt: Option[String] = None - val res = ("top *" #> opt & - "top [href]" #> "frog")(cat) - - res.text must_== "" - (res \ "@href").text.mkString must_== "frog" - } - - "bind href and Some content" in { - val opt: Option[String] = Some("Dog") - val res = ("top *" #> opt & - "top [href]" #> "frog")(cat) - - res.text must_== "Dog" - (res \ "@href").text.mkString must_== "frog" - } - - "bind href and Some content with multiple attrs" in { - val opt: Option[String] = Some("Dog") - val res = ("top *" #> opt & - "top [meow]" #> "woof" & - "top [href]" #> "frog")(cat) - - res.text must_== "Dog" - (res \ "@href").text.mkString must_== "frog" - (res \ "@meow").text.mkString must_== "woof" - } - - "option transform on *" in { - val opt: Option[String] = None - val res = ("* *" #> opt.map(ignore => "Dog")).apply(cat) - res.head must_== - } - - "append attribute to a class with spaces" in { - val stuff = List("a", "b") - val res = ("* [class+]" #> stuff).apply(cat) - (res \ "@class").text must_== "q a b" - } - - "append attribute to an href" in { - val stuff = List("&a=b", "&b=d") - val res = ("* [href+]" #> stuff).apply(cat) - (res \ "@href").text must_== "q?z=r&a=b&b=d" - } - - "remove an attribute from a class" in { - val func = ".foo [class!]" #> "andOther" - - (func() \ "@class").text must_== "foo" - } - - "remove an attribute from a class and the attribute if it's the only one left" in { - val func = ".foo [class!]" #> "foo" - val res = func() - - (res \ "@class").length must_== 0 - } - - "don't merge class attribute" in { - val func = "p !!" #> 10 - val res = func.apply(

Test

) - (res \ "@class").text must_== "replacement" - } - - "merge other attributes when using don't merge class modification" in { - val func = "p !!" #> 10 - val res = func.apply(

Test

) - (res \ "@data-one").text must_== "1" - (res \ "@data-two").text must_== "2" - (res \ "@class").text must_== "replacement" - } - - "leave node class attribute for replacement without class" in { - // TODO: Since was agreed not to change current behaviour, create test for it (https://groups.google.com/forum/#!topic/liftweb/Nswcxoykspc) - val func = "p !!" #> 10 - val res = func.apply(

Test

) - (res \ "@class").text must_== "first second" - } - - "Remove a subnode's class attribute" in { - - val func = ".removeme !!" #> ("td [class!]" #> "removeme") - val res = func.apply(Hi) - - ((res \ "td") \ "@class").text must_== "fish" - } - - - "not remove a non-existant class" in { - val func = ".foo [class!]" #> "bar" - val res = func() - - (res \ "@class").text must_== "foo" - } - - - "remove an attribute from an attribute" in { - val func = "span [href!]" #> "foo" - val res = func() - - (res \ "@href").length must_== 0 - } - - - "not remove a non-existant href" in { - val func = "span [href!]" #> "bar" - val res = func() - - (res \ "@href").text must_== "foo bar" - } - - "option transform on *" in { - val opt: Option[Int] = Full(44) - val res = ("* *" #> opt.map(ignore => "Dog")).apply(cat) - res must ==/ (Dog) - } - - - "Java number support" in { - val f = "a *" #> Full(java.lang.Long.valueOf(12)) - val xml = Hello - - f(xml) must ==/ (12) - } - - - "Surround kids" in { - val f = "a <*>" #>
- val xml = Meow Cat woof - - f(xml) must ==/ (Meow
Cat
woof
) - } - - "Andreas's thing doesn't blow up" in { - def cachedMessageList: Box[Box[String]] = Empty - - def messageListId = "Hello" - - def collapseUnless[A](isEmptyCond: Boolean)(f: => A): Box[A] = { - if (!isEmptyCond) { - Empty - } else { - Full(f) - } - } - - ".noMail" #> collapseUnless(cachedMessageList.map(_.isEmpty).openOr(true)) { - "tbody [id]" #> messageListId & - "*" #> PassThru - } - - true must_== true - } - - "other Andreas test" in { - def renderBlogEntrySummary = { - ".blogEntry" #> ((ns: NodeSeq) => { - ("*" #> "Horse").apply(ns) - }) - } - - - - def render = { - - "*" #> ((ns: NodeSeq) => - renderBlogEntrySummary.apply(ns) ++ hi - ) - } - - render - - true must_== true - } - - - "option transform on *" in { - val opt: Box[String] = Empty - val res = ("* *" #> opt.map(ignore => "Dog")).apply(cat) - res.head must_== - } - - "option transform on *" in { - val opt: Box[Int] = Some(44) - val res = ("* *" #> opt.map(ignore => "Dog")).apply(cat) - res must ==/ (Dog) - } - - "transform on *" in { - val res = ("* *" #> "Dog").apply(cat) - res must ==/ (Dog) - } - - "transform child content on *+" in { - val res = ("* *+" #> "moose").apply(I like ) - res.text must_== "I like moose" - } - - "transform child content on -*" in { - val res = ("* -*" #> "moose").apply( I like) - res.text must_== "moose I like" - } - - "transform on li" in { - val res = ("li *" #> List("Woof", "Bark") & ClearClearable)( -
  • meow
  • a
  • a
) - res must ==/ (
  • Woof
  • Bark
) - } - - "substitute multiple Strings by id" in { - (("#foo" replaceWith "hello") & - ("#baz" replaceWith "bye") - )( -
Hello
- ) must_== (NodeSeq fromSeq {Text("bye")}{Text("hello")}) - } - - "substitute multiple Strings with a List by id" in { - ("#foo" #> "hello" & - "#baz" #> List("bye", "bye"))(
Hello
) must_== (NodeSeq fromSeq {Text("bye")}{Text("bye")}{Text("hello")}) - } - - "substitute multiple Strings with a List by id" in { - (("#foo" replaceWith "hello") & - ("#baz" replaceWith List("bye", "bye")))(
Hello
) must_== (NodeSeq fromSeq {Text("bye")}{Text("bye")}{Text("hello")}) - } - - - "substitute multiple Strings with a List of XML by id" in { - val answer = ("#foo" #> "hello" & - "#baz" #> List[NodeSeq](, Meow))(
Hello
) - - (answer \ "i").length must_== 2 - (answer \ "i")(0) must ==/ () - (answer \ "i")(1) must ==/ (Meow) - } - - "substitute multiple Strings with a List of XML by id" in { - val answer = (("#foo" replaceWith "hello") & - ("#baz" replaceWith List[NodeSeq](, Meow)))(
Hello
) - - (answer \ "i").length must_== 2 - (answer \ "i")(0) must ==/ () - (answer \ "i")(1) must ==/ (Meow) - } - - "substitute by name" in { - val answer = ("name=moose" #> ).apply ( -
) - - (answer \ "input")(0) must ==/ () - } - - - "Deal with NodeSeq as a NodeSeq" in { - val f = "h6 *" #> ((Text("Some awesome ") ++ text ++ Text(" here.")): NodeSeq) - val xml =
Dude, where's my car?
- - val res = f(xml) - res must ==/ (
Some awesome text here.
) - } - - "substitute by name" in { - val answer = ("name=moose" replaceWith ).apply ( -
) - - (answer \ "input")(0) must ==/ () - } - - - "substitute by name with attrs" in { - val answer = ("name=moose" #> ).apply ( -
) - - (answer \ "input")(0) must ==/ () - } - - "substitute by name with attrs" in { - val answer = ("name=moose" replaceWith ).apply ( -
) - - (answer \ "input")(0) must ==/ () - } - - - "substitute by a selector with attrs" in { - val answer = ("cute=moose" #> ).apply ( -
) - - (answer \ "input")(0) must ==/ () - } - - "substitute by a selector with attrs" in { - val answer = ("cute=moose" replaceWith ).apply ( -
) - - (answer \ "input")(0) must ==/ () - } - - "Map of funcs" in { - val func: NodeSeq => NodeSeq = "#horse" #> List(1,2,3).map(".item *" #> _) - val answer: NodeSeq = func(
frogi
) - - answer must ==/ (
frog1
frog2
frog3
) - - } - - "maintain unique id attributes provided by transform" in { - val func = ".thinglist *" #> - (".thing" #> List("xx1", "xx2", "xx2", "xx2", "xx4").map(t => { - ".thing [id]" #> t - }) - ) - val answer = func(
) - - answer must ==/ (
) - } - - "merge classes" in { - val answer = ("cute=moose" #> ).apply ( -
) - - (answer \ "input")(0) must ==/ () - } - - - "merge classes" in { - val answer = ("cute=moose" replaceWith ).apply ( -
) - - (answer \ "input")(0) must ==/ () - } - - - - - "list of strings" in { - val answer = ("#moose *" #> List("a", "b", "c", "woof") & - ClearClearable).apply ( -
    -
  • first
  • -
  • second
  • -
  • Third
  • -
) - - val lis = (answer \ "li").toList - - lis.length must_== 4 - - lis(0) must ==/ (
  • a
  • ) - lis(3) must ==/ (
  • woof
  • ) - } - - - "list of Nodes" in { - val answer = ("#moose *" #> List[NodeSeq]("a", Text("b"), Text("c"), woof) & - ClearClearable).apply ( -
      -
    • first
    • -
    • second
    • -
    • Third
    • -
    ) - - val lis = (answer \ "li").toList - - lis.length must_== 4 - - lis(0) must ==/ (
  • "a"
  • ) - lis(3) must ==/ (
  • woof
  • ) - } - - - "set href" in { - val answer = ("#moose [href]" #> "Hi" & - ClearClearable).apply ( - ) - - - (answer \ "a" \ "@href").text must_== "Hi" - (answer \ "li").length must_== 0 - } - - "set href and subnodes" in { - val answer = ("#moose [href]" #> "Hi" & - ClearClearable).apply ( - ) - - - (answer \ "a" \ "@href").text must_== "Hi" - (answer \\ "li").length must_== 0 - } - - - "list of strings" in { - val answer = (("#moose *" replaceWith List("a", "b", "c", "woof")) & - ClearClearable).apply ( -
      -
    • first
    • -
    • second
    • -
    • Third
    • -
    ) - - val lis = (answer \ "li").toList - - lis.length must_== 4 - - lis(0) must ==/ (
  • a
  • ) - lis(3) must ==/ (
  • woof
  • ) - } - - "bind must bind to subnodes" in { - val html =
      -
    • - -
    • -
    - - val lst = List(1,2,3) - - val f = ".users *" #> ("li" #> lst.map(i => ".user [userid]" #> i)) - - (f(html) \\ "ul").length must_== 1 - (f(html) \\ "li").length must_== 3 - } - - "list of Nodes" in { - val answer = (("#moose *" replaceWith List[NodeSeq]("a", Text("b"), Text("c"), woof)) & - ClearClearable).apply ( -
      -
    • first
    • -
    • second
    • -
    • Third
    • -
    ) - - val lis = (answer \ "li").toList - - lis.length must_== 4 - - lis(0) must ==/ (
  • "a"
  • ) - lis(3) must ==/ (
  • woof
  • ) - } - - - "set href" in { - val answer = (("#moose [href]" replaceWith "Hi") & - ClearClearable).apply ( - ) - - - (answer \ "a" \ "@href").text must_== "Hi" - (answer \ "li").length must_== 0 - } - - "set href and subnodes" in { - val answer = (("#moose [href]" replaceWith "Hi") & - ClearClearable).apply ( - ) - - - (answer \ "a" \ "@href").text must_== "Hi" - (answer \\ "li").length must_== 0 - } - - - } -} - - -/** - * This class doesn't actually perform any tests, but insures that - * the implicit conversions work correctly - */ -object CheckTheImplicitConversionsForToCssBindPromoter { - val bog = new CssBindPromoter(Empty, Empty) - - "foo" #> "baz" - - bog #> "Hello" - bog #> - bog #> 1 - bog #> Symbol("foo") - bog #> 44L - bog #> 1.22 - bog #> false - - bog #> List() - bog #> Full() - val e: Box[String] = Empty - bog #> e - bog #> Some() - val n: Option[String] = None - bog #> n - - - bog #> List("Hello") - bog #> List(1.22) - bog #> List(44L) - bog #> List(1) - bog #> Full("Dog") - bog #> Some("Moo") - - - bog #> List((null: Bindable)) - bog #> Full((null: Bindable)) - bog #> Some((null: Bindable)) - - bog #> nsToNs _ - bog #> nsToOptNs _ - bog #> nsToBoxNs _ - bog #> nsToSeqNs _ - - bog #> nsToString _ - bog #> nsToOptString _ - bog #> nsToBoxString _ - bog #> nsToSeqString _ - - val nsf: NodeSeq => NodeSeq = bog #> "Hello" & - bog #> & - bog #> 1 & - bog #> Symbol("foo") & - bog #> 44L & - bog #> false - - "foo" #> "Hello" - "foo" #> - "foo" #> 1 - "foo" #> Symbol("foo") - "foo" #> 44L - "foo" #> false - - "foo" #> List() - "foo" #> Full() - "foo" #> Some() - - - "foo" #> List("Hello") - "foo" #> Full("Dog") - "foo" #> Some("Moo") - - - "foo" #> List((null: Bindable)) - "foo" #> Full((null: Bindable)) - "foo" #> Some((null: Bindable)) - - "foo" #> nsToNs _ - "foo" #> nsToOptNs _ - "foo" #> nsToBoxNs _ - "foo" #> nsToSeqNs _ - - "foo" #> nsToString _ - "foo" #> nsToOptString _ - "foo" #> nsToBoxString _ - "foo" #> nsToSeqString _ - - "#foo" #> Set("a", "b", "c") - - val nsf2: NodeSeq => NodeSeq = "foo" #> "Hello" & - "foo" #> & - "foo" #> 1 & - "foo" #> Symbol("foo") & - "foo" #> 44L & - "foo" #> false - - "bar" #> List("1","2","3").map(s => "baz" #> s) - - "bar" #> Full(1).map(s => ("baz" #> s): CssBindFunc) - "bar" #> Some(1).map(s => ("baz" #> s): CssBindFunc) - - - - def nsToNs(in: NodeSeq): NodeSeq = in - def nsToOptNs(in: NodeSeq): Option[NodeSeq] = Some(in) - def nsToBoxNs(in: NodeSeq): Box[NodeSeq] = Full(in) - def nsToSeqNs(in: NodeSeq): Seq[NodeSeq] = List(in) - - def nsToString(in: NodeSeq): String = in.text - def nsToOptString(in: NodeSeq): Option[String] = Some(in.text) - def nsToBoxString(in: NodeSeq): Box[String] = Full(in.text) - def nsToSeqString(in: NodeSeq): Seq[String] = List(in.text) -} diff --git a/core/util/src/test/scala-2.13/net/liftweb/util/CurrencyZoneSpec.scala b/core/util/src/test/scala-2.13/net/liftweb/util/CurrencyZoneSpec.scala deleted file mode 100644 index 130e709b37..0000000000 --- a/core/util/src/test/scala-2.13/net/liftweb/util/CurrencyZoneSpec.scala +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright 2007-2026 Lift Committers and Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package net.liftweb -package util - -import org.specs2.mutable.Specification - - -/** - * Systems under specification for CurrencyZone. - */ -class CurrencyZoneSpec extends Specification { - "CurrencyZone Specification".title - - "Australian money" should { - - "not equal to other money" in { - val auBoolean = AU(4.42) != US(4.42) - auBoolean mustEqual true - } - - "be not equal to a different amount of its own money" in { - val auBoolean = AU(4.48) == AU(4.481) - auBoolean mustEqual false - } - - - "be equal to the same amount of its own money" in { - val auBoolean = AU(4.42) == AU(4.42) - auBoolean mustEqual true - } - - "be comparable not gt" in { - val auBoolean = AU(4.42) > AU(4.420000) - auBoolean mustEqual false - } - - "be creatable" in { - AU(20.1).get must beMatching ("20.10") - } - - "be addable" in { - val au = AU(20.68) + AU(3.08) - au.get must beMatching ("23.76") - } - - "be subtractable" in { - val au = AU(23.76) - AU(3.08) - au.get must beMatching ("20.68") - } - - "be mutipliable" in { - val au = AU(20.68) * 3 - au.get must beMatching ("62.04") - } - - "be divisable" in { - val au = AU(20.68) / AU(3) - au.get must beMatching ("6.89") - } - - - "be comparable gt" in { - val auBoolean = AU(20.68) > AU(3) - auBoolean mustEqual true - } - - "be comparable lt" in { - val auBoolean = AU(3.439) < AU(3.44) - auBoolean mustEqual true - } - - "be comparable lt or eq" in { - val auBoolean = AU(20.68) <= AU(20.68) - auBoolean mustEqual true - } - } - -} - diff --git a/core/util/src/test/scala-2.13/net/liftweb/util/Html5ParserSpec.scala b/core/util/src/test/scala-2.13/net/liftweb/util/Html5ParserSpec.scala deleted file mode 100644 index 54533654cb..0000000000 --- a/core/util/src/test/scala-2.13/net/liftweb/util/Html5ParserSpec.scala +++ /dev/null @@ -1,183 +0,0 @@ -/* - * Copyright 2006-2026 Lift Committers and Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package net.liftweb -package util - -import scala.xml.{ Comment, Elem } - -import org.specs2.mutable.Specification -import org.specs2.execute.PendingUntilFixed - -import common._ -import Helpers._ - - -/** - * Systems under specification for Html5 Parser. - */ -class Html5ParserSpec extends Specification with PendingUntilFixed with Html5Parser with Html5Writer { - "Html5Parser Specification".title - - "Html5 Writer" should { - "Write &" in { - toString() must_== """""" - } - - "ignore attributes that are null" in { - toString() must_== """""" - } - - "render void tags without a closing tag" in { - toString(
    ) must_== "
    " - } - - "render void tags with attributes" in { - toString(y) must_== """y""" - } - - "render non-void empty tags with a closing tag" in { - toString(
    ) must_== "
    " - } - - "not escape content inside script tags" in { - toString() must_== "" - } - - "not escape content inside style tags" in { - toString() must_== "" - } - - "write PCData as CDATA section" in { - toString(
    {PCData("x < y & z")}
    ) must_== "
    " - } - - "write Comment nodes" in { - toString(
    {Comment("a comment")}
    ) must_== "
    " - } - - "preserve namespace prefix on elements" in { - toString(
    ) must_== - """
    """ - } - } - - "Html5 Parser" should { - val pages = for { - page1 <- tryo(readWholeStream(getClass.getResourceAsStream("Html5ParserSpec.page1.html"))).filter(_ ne null) - page2 <- tryo(readWholeStream(getClass.getResourceAsStream("Html5ParserSpec.page2.html"))).filter(_ ne null) - page3 <- tryo(readWholeStream(getClass.getResourceAsStream("Html5ParserSpec.page3.html"))).filter(_ ne null) - } yield (page1, page2, page3) - - pages match { - case Full(p) => - val (page1, page2, page3) = (new String(p._1), new String(p._2), new String(p._3)) - - "parse valid page type1" in { - val parsed = parse(page1).openOrThrowException("Test") - (parsed \\ "script").length must be >= 4 - } - - "parse valid page type2" in { - val parsed = parse(page2).openOrThrowException("Test") - (parsed \\ "script").length must be >= 4 - } - - "fail to parse invalid page type3" in { - val parsed = parse(page3) - parsed must beAnInstanceOf[Failure] - }.pendingUntilFixed - - case _ => - failure("Failed loading test files") // TODO: Improve error message - } - - "change to " in { - val parsed = parse("
    123
    ").openOrThrowException("Test") - val heads = parsed \\ "head" - heads.length must_== 1 - heads.text must_== "123" - (heads(0).asInstanceOf[Elem].prefix == null) must_== true - }.pendingUntilFixed - - "Parse stuff with lift: namespace" in { - val parsed = parse("""
    """) - val e = parsed.openOrThrowException("Test").asInstanceOf[Elem] - e.prefix must_== "lift" - e.label must_== "surround" - (parsed.openOrThrowException("Test") \ "@with").text must_== "dog" - } - - "Parse stuff without lift: namespace" in { - val parsed = parse("""
    """) - val e = parsed.openOrThrowException("Test").asInstanceOf[Elem] - e.label must_== "div" - (parsed.openOrThrowException("Test") \ "@with").text must_== "dog" - } - - "unwrap a single fragment element via AutoInsertedBody" in { - val result = parse("
    hello
    ").openOrThrowException("Test") - result.label must_== "div" - result.text must_== "hello" - } - - "not unwrap a full html document" in { - val result = parse("T

    X

    ") - .openOrThrowException("Test") - result.label must_== "html" - } - - "unwrap a single self-closing fragment element" in { - val result = parse("").openOrThrowException("Test") - result.label must_== "span" - } - - "resolve standard HTML entities to their character values" in { - val result = parse("

     

    ").openOrThrowException("Test") - result.text must_== "\u00A0" - } - - "preserve script tag content verbatim (in head)" in { - // nu.validator places bare ").openOrThrowException("Test") - result.label must_== "html" - (result \\ "script").text must_== "var x = 1 < 2 && true;" - } - - "preserve style tag content verbatim (in head)" in { - // nu.validator places bare ").openOrThrowException("Test") - result.label must_== "html" - (result \\ "style").text must_== "p > span { color: red; }" - } - - "preserve data-* attributes" in { - val result = parse("""
    x
    """).openOrThrowException("Test") - (result \ "@data-foo").text must_== "bar" - (result \ "@data-baz").text must_== "qux" - } - - "preserve Unicode content" in { - val result = parse("

    café naïve 日本語

    ").openOrThrowException("Test") - result.text must_== "café naïve 日本語" - } - - "return a Full result for empty string input" in { - parse("") must beAnInstanceOf[Full[Elem]] - } - } - -} diff --git a/core/util/src/test/scala-2.13/net/liftweb/util/HtmlHelpersSpec.scala b/core/util/src/test/scala-2.13/net/liftweb/util/HtmlHelpersSpec.scala deleted file mode 100644 index ca55e5aad8..0000000000 --- a/core/util/src/test/scala-2.13/net/liftweb/util/HtmlHelpersSpec.scala +++ /dev/null @@ -1,315 +0,0 @@ -/* - * Copyright 2007-2026 Lift Committers and Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package net.liftweb -package util - -import scala.xml._ - -import org.specs2.matcher.XmlMatchers -import org.specs2.mutable.Specification - -import common._ - -/** - * Systems under specification for HtmlHelpers. - */ -class HtmlHelpersSpec extends Specification with HtmlHelpers with XmlMatchers { - "HtmlHelpers Specification".title - - "findBox" should { - "find an id" in { - val xml = Dog - - findBox(xml) { - e => e.attribute("id"). - filter(_.text == "3"). - map(i => e) - }.openOrThrowException("Test") must ==/ () - } - - "not find an ide" in { - val xml = Dog - - findBox(xml) { - e => e.attribute("id"). - filter(_.text == "3").map(i => e) - } must_== Empty - } - - - "not find a the wrong id" in { - val xml = Dog - - findBox(xml) { - e => e.attribute("id"). - filter(_.text == "3").map(i => e) - } must_== Empty - } - } - - "findOption" should { - "find an id" in { - val xml = Dog - - findOption(xml) { - e => e.attribute("id"). - filter(_.text == "3").map(i => e) - }.get must ==/ () - } - - "not find an ide" in { - val xml = Dog - - findOption(xml) { - e => e.attribute("id"). - filter(_.text == "3").map(i => e) - } must_== None - } - - - "not find a the wrong id" in { - val xml = Dog - - findOption(xml) { - e => e.attribute("id"). - filter(_.text == "3").map(i => e) - } must_== None - } - } - - "findId" should { - val xml = - - Boom - Other boom - - - "find the element with a requested id in a NodeSeq" in { - findId(xml, "boom") must beLike { - case Some(element) => - element must ==/(Boom) - } - } - - "provide a None if a requested id is not found in the NodeSeq" in { - findId(xml, "explode") must beNone - } - - "find the first id in a NodeSeq when no id is requested" in { - findId(xml) must_== Full("boom") - } - - "provide an Empty if no ide is foud in a NodeSeq when no id is requested" in { - findId() must_== Empty - } - } - - "head removal" should { - "remove " in { - Helpers.stripHead(hello) must ==/(hello) - } - - "ignore non-head" in { - Helpers.stripHead(hello) must ==/(hello) - } - - "String subhead" in { - Helpers.stripHead(hello) must ==/(hello) - } - } - - "removeAttribute" should { - val element = - - "remove the specified attribute from a provided element" in { - val removed = removeAttribute("attribute", element) - - removed must ==/() - } - - "remove the specified attribute from a provided MetaData list" in { - val removed = removeAttribute("attribute", element.attributes) - - (removed("attribute") must_== null) and - (removed("otherAttribute") must_== Text("good-bye")) - } - } - - "addCssClass" should { - "add a new attribute if no class attribute exists" in { - (addCssClass("foo", ) \ "@class").text must_== "foo" - } - - "append to an existing class attribute if it already exists" in { - (addCssClass("foo", ) \ "@class").text must_== "dog foo" - } - } - - "ensureUniqueId" should { - "leave things unchanged if no ids collide" in { - val xml = - - - - - - val uniqued = {ensureUniqueId(xml).head} - - (uniqued must \("boom", "id" -> "thing")) and - (uniqued must \\("hello", "id" -> "other-thing")) and - (uniqued must \\("bye", "id" -> "third-thing")) - } - - "strip the ids if elements have an id matching a previous one" in { - val xml = - Group( - - - - ) - - val uniqued = NodeSeq.seqToNodeSeq(ensureUniqueId(xml).flatten) - - uniqued must ==/( - - - - ) - } - - "leave child element ids alone even if they match the ids of the root element or each other" in { - val xml = - - - - - - val uniqued = {ensureUniqueId(xml).head} - - (uniqued must \\("hello", "id" -> "thing")) and - (uniqued must \\("bye", "id" -> "thing")) - } - } - - "deepEnsureUniqueId" should { - "leave things unchanged if no ids collide" in { - val xml = - - - - - - val uniqued = {deepEnsureUniqueId(xml).head} - - (uniqued must \("boom", "id" -> "thing")) and - (uniqued must \\("hello", "id" -> "other-thing")) and - (uniqued must \\("bye", "id" -> "third-thing")) - } - - "strip the ids if elements have an id matching a previous one" in { - val xml = - Group( - - - - ) - - val uniqued = NodeSeq.seqToNodeSeq(deepEnsureUniqueId(xml).flatten) - - uniqued must ==/( - - - - ) - } - - "strip child element ids alone if they match the ids of the root element or each other" in { - val xml = - - - Boom - - - - - - val uniqued = {deepEnsureUniqueId(xml).head} - - uniqued must ==/( - - - - Boom - - - - - - ) - } - } - - "ensureId" should { - "if the first element has an id, replace it with the specified one" in { - val xml = - - - Boom - - - - - - val uniqued = {ensureId(xml, "other-thinger").head} - - uniqued must \("boom", "id" -> "other-thinger") - } - - "if the first element has no id, give it the specified one" in { - val xml = - - - Boom - - - - - - val uniqued = {ensureId(xml, "other-thinger").head} - - uniqued must \("boom", "id" -> "other-thinger") - } - - "not affect other elements" in { - val xml = - Group( - - - - ) - - val uniqued = NodeSeq.seqToNodeSeq(ensureId(xml, "other-thinger").flatten) - - uniqued must ==/( - - - - ) - } - } -} - diff --git a/core/util/src/test/scala-2.13/net/liftweb/util/HtmlRoundTripSpec.scala b/core/util/src/test/scala-2.13/net/liftweb/util/HtmlRoundTripSpec.scala deleted file mode 100644 index 64b40791e4..0000000000 --- a/core/util/src/test/scala-2.13/net/liftweb/util/HtmlRoundTripSpec.scala +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Copyright 2026 Lift Committers and Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package net.liftweb -package util - -import scala.xml.Elem - -import org.specs2.mutable.Specification - - -/** - * Round-trip tests for HTML parsing and serialization pipelines. - * These lock in the observable behavior of both parser paths so that - * implementation changes can be validated against them. - */ -class HtmlRoundTripSpec extends Specification with Html5Parser with Html5Writer { - "Html5 round-trip" should { - "preserve element label and text content" in { - val result = parse("
    hello world
    ").openOrThrowException("Test") - val output = toString(result) - output must contain("
    ") - output must contain("hello world") - output must contain("
    ") - } - - "preserve attribute values" in { - val result = parse("""link""") - .openOrThrowException("Test") - val output = toString(result) - output must contain("http://example.com") - output must contain("nav") - output must contain("link") - } - - "preserve nested structure" in { - val input = "" - val result = parse(input).openOrThrowException("Test") - val output = toString(result) - output must contain("
      ") - output must contain("
    • ") - output must contain("
      """) - .openOrThrowException("Test") - val output = toString(result) - output must contain("lift:surround") - output must contain("""with="default"""") - } - - "preserve unicode content" in { - val result = parse("

      café 日本語

      ").openOrThrowException("Test") - val output = toString(result) - output must contain("café") - output must contain("日本語") - } - - "represent nbsp as a non-breaking space character (not entity name)" in { - // Html5 parser resolves   to the U+00A0 character. - // Html5Writer (with convertAmp=true, the toString default) does not convert it back. - val result = parse("

       

      ").openOrThrowException("Test") - val output = toString(result) - output must contain("\u00A0") - } - - "write void tags without closing tag" in { - val result = parse("

      ").openOrThrowException("Test") - val output = toString(result) - output must contain("
      ") - output must contain("" - output must not contain "" - } - } - - "PCDataXmlParser + AltXML round-trip" should { - "preserve element label and text content" in { - val result = PCDataXmlParser("
      hello world
      ").openOrThrowException("Test") - val output = AltXML.toXML(result.head, false, true) - output must contain("
      ") - output must contain("hello world") - output must contain("
      ") - } - - "preserve attribute values" in { - val result = PCDataXmlParser("""
      link""") - .openOrThrowException("Test") - val output = AltXML.toXML(result.head, false, true) - output must contain("http://example.com") - output must contain("link") - } - - "preserve nested structure" in { - val input = "" - val result = PCDataXmlParser(input).openOrThrowException("Test") - val output = AltXML.toXML(result.head, false, true) - output must contain("
        ") - output must contain("
      • ") - output must contain("text") - } - - "preserve CDATA content as CDATA" in { - val result = PCDataXmlParser("
        ") - .openOrThrowException("Test") - val output = AltXML.toXML(result.head, false, true) - output must contain("") - } - - "preserve HTML entities as characters with convertAmp=true" in { - // With convertAmp=true, the U+00A0 char produced by parsing   - // is emitted as the character (not converted back to entity name) - val result = PCDataXmlParser("

         

        ").openOrThrowException("Test") - val output = AltXML.toXML(result.head, false, true) - output must contain("\u00A0") - } - - "convert high-codepoint chars back to entity names with convertAmp=false" in { - // With convertAmp=false, U+00A0 is reversed to   via revMap - val result = PCDataXmlParser("

         

        ").openOrThrowException("Test") - val output = AltXML.toXML(result.head, false, false) - output must contain(" ") - } - - "preserve lift: namespace prefix through both parsers" in { - val result = PCDataXmlParser("""
        """) - .openOrThrowException("Test") - val output = AltXML.toXML(result.head, false, true) - output must contain("lift:surround") - output must contain("""with="default"""") - } - } - -} diff --git a/core/util/src/test/scala-2.13/net/liftweb/util/HttpHelpersSpec.scala b/core/util/src/test/scala-2.13/net/liftweb/util/HttpHelpersSpec.scala deleted file mode 100644 index d89f69fa50..0000000000 --- a/core/util/src/test/scala-2.13/net/liftweb/util/HttpHelpersSpec.scala +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright 2006-2026 Lift Committers and Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package net.liftweb -package util - -import org.specs2.matcher.XmlMatchers -import org.specs2.mutable.Specification - -import HttpHelpers._ - - -/** - * Systems under specification for HttpHelpers. - */ -class HttpHelpersSpec extends Specification with HttpHelpers with ListHelpers with StringHelpers with XmlMatchers { - "HttpHelpers Specification".title - - "Http helpers" should { - "urlEncode and urlDecode functions" >> { - urlDecode(urlEncode("hello world")) must_== "hello world" - urlEncode(urlDecode("hello+world")) must_== "hello+world" - } - "a paramsToUrlParams function to translate a map of parameters to a URL query" in { - paramsToUrlParams(List(("firstname", "hello"), ("lastname", "world"))) must_== "firstname=hello&lastname=world" - } - "an appendParams function to add parameters to a URL query" in { - "creating the param list with ? if there are no existing params" in { - appendParams("www.helloworld.com/params", List(("firstname", "hello"), ("lastname", "world"))) must_== - "www.helloworld.com/params?firstname=hello&lastname=world" - } - "appending the param list with & if there are some already" in { - appendParams("www.helloworld.com/params?firstname=hello", List(("lastname", "world"))) must_== - "www.helloworld.com/params?firstname=hello&lastname=world" - } - "returning the url if no param list is passed" in { - appendParams("www.helloworld.com/params", Nil) must_== "www.helloworld.com/params" - } - } - "a couldBeHtml function" in { - "returning true if there is a pair (Content-Type, text/html)" in { - couldBeHtml(Map(("Content-Type", "text/html"))) must beTrue - } - "returning true if there is a pair (Content-Type, Application/xhtml+xml). The check is case insensitive" in { - couldBeHtml(Map(("Content-Type", "Application/xhtml+XML"))) must beTrue - } - "returning false if the content type is something else (Content-Type, application/jpeg)" in { - couldBeHtml(Map(("Content-Type", "application/jpeg"))) must beFalse - } - "returning true if there is no a pair starting with Content-Type" in { - couldBeHtml(Map(("no content type", "text/html"))) must beTrue - } - } - "a noHtmlTag" in { - "returning true if a xml node doesn't contain the html tag" in { - noHtmlTag() must beTrue - } - "returning false if a xml node contains the html tag" in { - noHtmlTag() must beFalse - } - } - "a toHashMap function transforming a Map to a mutable HashMap" in { - toHashMap(Map(1 -> 2, 3 -> 4)) must haveClass[scala.collection.mutable.HashMap[Int, Int]] - } - "an insureField function" in { - "checking that the appropriate fields are in the header" in { - insureField(List(("name", "hello")), List(("name", "hello"))) must_== List(("name", "hello")) - } - "checking that the appropriate fields are in the header, adding them if necessary" in { - insureField(List(("name2", "hello")), List(("name", "hello"))) must_== List(("name", "hello"), ("name2", "hello")) - } - } - "an implicit definition to transform a pair to an UnprefixedAttribute" in { - pairToUnprefixed(("value", 1)).apply("value").toString must_== "1" - } - "a findOrAddId function" in { - "returning an element and its id if found" in { findOrAddId() must_== (, "1") } - "returning an element with a random id if not found" in { - val (e, id) = findOrAddId() - e must \("@id") - // id must beMatching("R\\[a-zA-Z0-9]*") - } - } - } - // currentSus is no longer part of Specification in 1.6 def provide(e: =>Example) = { currentSus.verb += " provide"; e } -} - diff --git a/core/util/src/test/scala-2.13/net/liftweb/util/IoHelpersSpec.scala b/core/util/src/test/scala-2.13/net/liftweb/util/IoHelpersSpec.scala deleted file mode 100644 index b70e10cede..0000000000 --- a/core/util/src/test/scala-2.13/net/liftweb/util/IoHelpersSpec.scala +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright 2017-2026 Lift Committers and Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package net.liftweb -package util - -import org.specs2.mutable.Specification - -import common._ -import Helpers._ - -import java.nio.charset.StandardCharsets -import java.nio.file.{Files, Path} - -class IoHelpersSpec extends Specification with IoHelpers { - "IoHelpers Specification".title - - "Io helpers" should { - - "readWholeFile properly" in { - // Copy a resource file to the tmp directory so we can refer to it as a Path - val resourceAsPath: Box[Path] = { - for { - bytes <- tryo(readWholeStream(getClass.getResourceAsStream("IoHelpersSpec.txt"))).filter(_ ne null) - text <- tryo(new String(bytes)) - path = { - val tempFile = Files.createTempFile(s"IoHelpersSpec_${nextFuncName}", ".tmp") - Files.write(tempFile, text.getBytes(StandardCharsets.UTF_8)) - tempFile - } - } yield path - } - - resourceAsPath.isDefined must_== true - - resourceAsPath.foreach { path => - val pathContents = new String(readWholeFile(path)).trim - Files.delete(path) - pathContents must_== "IoHelpersSpec" - } - - success - } - } -} diff --git a/core/util/src/test/scala-2.13/net/liftweb/util/JsonCommandSpec.scala b/core/util/src/test/scala-2.13/net/liftweb/util/JsonCommandSpec.scala deleted file mode 100644 index d1871ef170..0000000000 --- a/core/util/src/test/scala-2.13/net/liftweb/util/JsonCommandSpec.scala +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2008-2026 Lift Committers and Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package net.liftweb -package util - -import org.specs2.mutable.Specification - -import org.json4s._ -import org.json4s.native.JsonParser -import org.json4s.native.JsonMethods._ - - -/** - * Systems under specification for JsonCommand. - */ -class JsonCommandSpec extends Specification { - "JsonCommand Specification".title - - private def parse(in: String): JValue = JsonParser.parse(in) - - "The JsonCommand object" should { - "return None for non-commands" in { - JsonCommand.unapply(parse("""{"foo": "bar", "baz": false, "params": "moose"} """)) must_== None - } - - "return None for non-params" in { - JsonCommand.unapply(parse("""{"command": "frog", "foo": "bar", "baz": false} """)) must_== None - } - - "Parse even if target missing" in { - JsonCommand.unapply(parse("""{"command": "frog", "foo": "bar", "params": 99} """)) must_== Some(("frog", None, JInt(99))) - } - - "Parse the whole thing" in { - JsonCommand.unapply(parse("""{"command": "frog", "target": "spud", "foo": "bar", "params": 982, "baz": false} """)) must_== - Some(("frog", Some("spud"), JInt(982))) - } - } -} diff --git a/core/util/src/test/scala-2.13/net/liftweb/util/ListHelpersSpec.scala b/core/util/src/test/scala-2.13/net/liftweb/util/ListHelpersSpec.scala deleted file mode 100644 index 0fc2102ed2..0000000000 --- a/core/util/src/test/scala-2.13/net/liftweb/util/ListHelpersSpec.scala +++ /dev/null @@ -1,197 +0,0 @@ -/* - * Copyright 2007-2026 Lift Committers and Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package net.liftweb -package util - -import org.specs2.mutable.Specification - -import common._ - - -/** - * Systems under specification for ListHelpers. - */ -class ListHelpersSpec extends Specification with ListHelpers { - "ListHelpers Specification".title - - "ListHelpers.delta" should { - "insert after 2" in { - val ret = delta(List(1, 2, 4, 5), List(1, 2, 3, 4, 5)) { - case InsertAfterDelta(3, 2) => "ok" - case _ => "not ok" - } - ret must_== List("ok") - } - - "prepend and append 2,4, 99" in { - val ret = delta(List(2, 4, 99), List(1, 2, 3, 4, 5)) { - case InsertAfterDelta(3, 2) => "ok" - case AppendDelta(5) => "ok5" - case RemoveDelta(99) => "99" - case InsertAtStartDelta(1) => "1" - case InsertAfterDelta(5, 4) => "ok5" - case _ => "fail" - } - ret must_== List("1", "ok", "ok5", "99") - } - - "prepend and append" in { - val ret = delta(List(4, 2, 99), List(1, 2, 3, 4, 5)) { - case InsertAfterDelta(3, 2) => "ok" - case InsertAfterDelta(4, 3) => "ok3" - case RemoveDelta(4) => "r4" - case AppendDelta(5) => "ok5" - case RemoveDelta(99) => "99" - case InsertAtStartDelta(1) => "1" - case InsertAfterDelta(5, 4) => "ok5" - case _ => "fail" - } - ret must_== List("1", "r4", "ok", "ok3", "ok5", "99") - } - } - - "The ListHelpers first_? function" should { - "return an Empty can if the list is empty" in { - first_?((Nil: List[Int]))((i: Int) => true) must_== Empty - } - "return an Empty can if no element in the list satisfies the predicate" in { - first_?(List(1, 2, 3))((i: Int) => i < 0) must_== Empty - } - "return a Full can with the first element in the list satisfying the predicate" in { - first_?(List(1, 2, 3))((i: Int) => i > 0) must_== Full(1) - } - } - - "The ListHelpers first function" should { - "return an Empty can if the list is empty" in { - first((Nil: List[Int]))((i: Int) => Full(1)) must_== Empty - } - "return an Empty can if no element in the list returns a Full can when applied a function" in { - first(List(1, 2, 3))((i: Int) => Empty) must_== Empty - } - "return the first Full can returned by a function f over the list elements" in { - val f = (i: Int) => i >= 2 match {case true => Full(3) case false => Empty} - first(List(1, 2, 3))(f) must_== Full(3) - } - } - - "The ciGet function on Lists of pairs of string" should { - "return Empty if the list is Nil" in { - (Nil: List[(String, String)]).ciGet("") must_== Empty - } - "return Empty if no pair has the key as its first element" in { - List(("one", "1"), ("two", "2")).ciGet("three") must_== Empty - } - "return a Full can with the first second value of a pair matching the key" in { - List(("one", "1"), ("two", "2")).ciGet("one") must_== Full("1") - } - "return a Full can with the first second value of a pair matching the key case-insensitively" in { - List(("one", "1"), ("two", "2"), ("two", "3")).ciGet("two") must_== Full("2") - } - } - - "The ListHelpers enumToList and enumToStringList functions" should { - "convert a java enumeration to a List" in { - val v: java.util.Vector[Int] = new java.util.Vector[Int] - v.add(1); - v.add(2) - enumToList(v.elements) must_== List(1, 2) - } - "convert a java enumeration containing any kind of object to a List of Strings" in { - val v: java.util.Vector[Any] = new java.util.Vector[Any] - v.add(1); - v.add("hello") - enumToStringList(v.elements) must_== List("1", "hello") - } - } - - "The ListHelpers head function (headOr on a list object)" should { - "return the first element of a list" in { - List(1).headOr(2) must_== 1 - } - "return a default value if the list is empty" in { - head(Nil, 2) must_== 2 - } - "not evaluate the default valueif list is not empty" in { - head(List(1), {sys.error("stop"); 2}) must_== 1 - } - } - - "The ListHelpers listIf function" should { - "create a List containing an element if the predicate is true" in { - listIf(true)(1) must_== List(1) - } - "return an empty List if the predicate is false" in { - listIf(false)(1) must_== Nil - } - "not evaluate its argument if the predicate is false" in { - listIf(false)({sys.error("stop"); 1}) must_== Nil - } - } - - "The ListHelpers rotateList function (rotate method on a List object)" should { - "create a List of all the circular permutations of a given list" in { - List(1, 2, 3).rotate must_== List(List(1, 2, 3), List(2, 3, 1), List(3, 1, 2)) - } - } - - "The ListHelpers permuteList function (permute method on a List object)" should { - "create a List of all the permutations of a given list" in { - List(1, 2, 3).permute must_== - List(List(1, 2, 3), List(1, 3, 2), List(2, 3, 1), List(2, 1, 3), List(3, 1, 2), List(3, 2, 1)) - } - } - - "The ListHelpers permuteWithSublists function (permuteAll method on a List object)" should { - "create a List of all the permutations of a given list" in { - List(1, 2, 3).permuteAll must_== - List( - List(1, 2, 3), List(1, 3, 2), List(2, 3, 1), - List(2, 1, 3), List(3, 1, 2), List(3, 2, 1), - List(2, 3), List(3, 2), List(3, 1), - List(1, 3), List(1, 2), List(2, 1), - List(3), List(2), List(1)) - } - } - - "The ListHelpers" should { - "provide an or method on Lists returning the list itself if not empty or another list if it is empty" in { - List(1).or(List(2)) must_== List(1) - (Nil: List[Int]).or(List(2)) must_== List(2) - } - "provide a str method on Lists joining the toString value of all elements" in { - List("h", "e", "l", "l", "o").str must_== "hello" - } - "provide a comma method on Lists being an alias for mkString(\", \")" in { - List("hello", "world").comma must_== "hello, world" - } - "provide a join method on Lists being an alias for mkString" in { - List("hello", "world").join(", ") must_== "hello, world" - } - "provide a ? method return true iff the list is not empty" in { - List().? must beFalse - List(1).? must beTrue - } - "provide a replace method to replace one element of the list at a given position (0-based index)." + - " If the position is negative, the first element is replaced" in { - List(1, 2, 3).replace(1, 4) must_== List(1, 4, 3) - List(1, 2, 3).replace(4, 4) must_== List(1, 2, 3) - List(1, 2, 3).replace(-1, 4) must_== List(4, 2, 3) - } - } - -} diff --git a/core/util/src/test/scala-2.13/net/liftweb/util/MarkdownParserSpec.scala b/core/util/src/test/scala-2.13/net/liftweb/util/MarkdownParserSpec.scala deleted file mode 100644 index 1313bfdff4..0000000000 --- a/core/util/src/test/scala-2.13/net/liftweb/util/MarkdownParserSpec.scala +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright 2026 Lift Committers and Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package net.liftweb -package util - -import scala.xml.{ Elem, NodeSeq } - -import org.specs2.mutable.Specification - -import net.liftweb.common.Full - - -/** - * Basic characterization tests for MarkdownParser. - * MarkdownParser delegates to Html5.parse so these also exercise that pipeline. - */ -class MarkdownParserSpec extends Specification { - "MarkdownParser" should { - "return Full for basic paragraph markdown" in { - MarkdownParser.parse("hello world") must beAnInstanceOf[Full[NodeSeq]] - } - - "render a paragraph as a

        element" in { - val result = MarkdownParser.parse("hello world").openOrThrowException("Test") - val paras = result.filter(n => n.isInstanceOf[Elem] && n.asInstanceOf[Elem].label == "p") - paras must not(beEmpty) - } - - "render bold markdown as " in { - val result = MarkdownParser.parse("**bold text**").openOrThrowException("Test") - val strong = result \\ "strong" - strong must not(beEmpty) - strong.text must contain("bold text") - } - - "render italic markdown as " in { - val result = MarkdownParser.parse("*italic text*").openOrThrowException("Test") - val em = result \\ "em" - em must not(beEmpty) - em.text must contain("italic text") - } - - "render a markdown link as " in { - val result = MarkdownParser.parse("[link text](http://example.com)").openOrThrowException("Test") - val anchors = result \\ "a" - anchors must not(beEmpty) - anchors.text must contain("link text") - } - - "render a code block as

        " in {
        -      val result = MarkdownParser.parse("    code line").openOrThrowException("Test")
        -      val pre = result \\ "pre"
        -      pre must not(beEmpty)
        -    }
        -
        -    "childrenOfBody extracts children from a body element" in {
        -      val input = 

        x

        y

        - val result = MarkdownParser.childrenOfBody(input) - result.length must be >= 2 - (result \\ "p").text must contain("x") - } - - "childrenOfBody returns input unchanged when no body element" in { - val input =

        x

        - val result = MarkdownParser.childrenOfBody(input) - result must_== input - } - } - -} diff --git a/core/util/src/test/scala-2.13/net/liftweb/util/PCDataXmlParserSpec.scala b/core/util/src/test/scala-2.13/net/liftweb/util/PCDataXmlParserSpec.scala deleted file mode 100644 index cd21fabbe2..0000000000 --- a/core/util/src/test/scala-2.13/net/liftweb/util/PCDataXmlParserSpec.scala +++ /dev/null @@ -1,156 +0,0 @@ -/* - * Copyright 2010-2026 Lift Committers and Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package net.liftweb -package util - -import java.io.ByteArrayInputStream - -import scala.xml.Elem - -import org.specs2.matcher.XmlMatchers -import org.specs2.mutable.Specification - -import net.liftweb.common.{ Failure, Full } - - -/** - * Systems under specification for PCDataXmlParser. - */ -class PCDataXmlParserSpec extends Specification with XmlMatchers { - "PCDataXmlParser Specification".title - - val data1 = """ - - -dude - - -""" - - val data2 = """ - - - -dude - - -""" - - val data3 = """ - - - -Meow - - - - - - - - - - - - - - -""" - - "PCDataMarkupParser" should { - "Parse a document with whitespace" in { - PCDataXmlParser(data1).openOrThrowException("Test") must ==/ (dude) - } - - "Parse a document with doctype" in { - PCDataXmlParser(data2).openOrThrowException("Test") must ==/ (dude) - } - - "Parse a document with xml and doctype" in { - PCDataXmlParser(data3).openOrThrowException("Test").apply(0).label must_== "html" - } - - "resolve named HTML entities to their character values" in { - val result = PCDataXmlParser("

         ©€

        ").openOrThrowException("Test") - val text = result.apply(0).text - text must contain("\u00A0") // nbsp - text must contain("\u00A9") // copy - text must contain("\u20AC") // euro - } - - "parse numeric character references" in { - val result = PCDataXmlParser("

         €

        ").openOrThrowException("Test") - val text = result.apply(0).text - text must contain("\u00A0") //   = nbsp - text must contain("\u20AC") // € = euro - } - - "parse CDATA sections as Lift PCData nodes" in { - val result = PCDataXmlParser("
        ").openOrThrowException("Test") - val elem = result.apply(0).asInstanceOf[Elem] - elem.child must haveSize(1) - val child = elem.child.head - child must beAnInstanceOf[PCData] - child.asInstanceOf[PCData].data must_== "x < y & z" - } - - "parse namespace-prefixed elements" in { - val result = PCDataXmlParser("""
        """) - .openOrThrowException("Test") - val elem = result.apply(0).asInstanceOf[Elem] - elem.prefix must_== "lift" - elem.label must_== "surround" - (result.apply(0) \ "@with").text must_== "default" - } - - "parse xmlns declarations and produce namespace bindings" in { - val result = PCDataXmlParser("""""") - .openOrThrowException("Test") - val elem = result.apply(0).asInstanceOf[Elem] - elem.label must_== "html" - elem.scope.uri must_== "http://www.w3.org/1999/xhtml" - } - - "return Failure for malformed XML" in { - PCDataXmlParser("
        ") must beAnInstanceOf[Failure] - } - - "return Failure for empty string" in { - PCDataXmlParser("") must beAnInstanceOf[Failure] - } - - "parse self-closing tags as elements with empty children" in { - val result = PCDataXmlParser("
        ").openOrThrowException("Test") - val elem = result.apply(0).asInstanceOf[Elem] - elem.label must_== "br" - elem.child must beEmpty - } - - "parse attributes containing encoded ampersands" in { - val result = PCDataXmlParser("""
        x""").openOrThrowException("Test") - val elem = result.apply(0).asInstanceOf[Elem] - (elem \ "@href").text must_== "foo&bar" - } - - "parse via InputStream" in { - val bytes = "

        hello

        ".getBytes("UTF-8") - val result = PCDataXmlParser(new ByteArrayInputStream(bytes)).openOrThrowException("Test") - result.apply(0).label must_== "p" - } - } - -} diff --git a/core/util/src/test/scala-2.13/net/liftweb/util/PropsSpec.scala b/core/util/src/test/scala-2.13/net/liftweb/util/PropsSpec.scala deleted file mode 100644 index 2b9be2834c..0000000000 --- a/core/util/src/test/scala-2.13/net/liftweb/util/PropsSpec.scala +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Copyright 2006-2026 Lift Committers and Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package net.liftweb -package util - -import java.io.ByteArrayInputStream - -import org.specs2.mutable.Specification -import org.specs2.mutable.After - -import common._ -import Props.RunModes._ - -class PropsSpec extends Specification { - "Props Specification".title - - case class TestProps() extends Props - - "Props" should { - "Detect test mode correctly" in { - TestProps().testMode must_== true - } - - "Allow modification of whereToLook before run-mode is set" in { - val testProps = TestProps() - val originalWtl = testProps.whereToLook - - var wasCalled = false - testProps.whereToLook = () => { - wasCalled = true - - List( - ("test propsters", () => Full(new ByteArrayInputStream("test.prop=value".getBytes("UTF-8")))) - ) - } - - testProps.getInt("jetty.port") must_== Empty - testProps.get("test.prop") must_== Full("value") - wasCalled must_== true - } - - "Allow modification of run-mode properties before the run-mode is set" in { - val testProps = TestProps() - - val before = testProps.autoDetectRunModeFn.get - try { - testProps.runModeInitialised = false - testProps.autoDetectRunModeFn.allowModification must_== true - testProps.autoDetectRunModeFn.set(() => Test) must_== true - testProps.autoDetectRunModeFn.get must_!= before - } finally { - testProps.autoDetectRunModeFn.set(before) - testProps.runModeInitialised = true - } - } - - "Prohibit modification of run-mode properties when the run-mode is set" in { - val testProps = TestProps() - - val before = testProps.autoDetectRunModeFn.get - testProps.mode // initialize run mode - testProps.autoDetectRunModeFn.allowModification must_== false - testProps.autoDetectRunModeFn.set(() => Test) must_== false - testProps.autoDetectRunModeFn.get must_== before - } - - "Parse and cast to int" in { - TestProps().getInt("an.int") must_== Full(42) - } - - "Parse and cast to long" in { - TestProps().getLong("a.long") must_== Full(9223372036854775807L) - } - - "Parse and cast to boolean" in { - TestProps().getBool("a.boolean") must_== Full(true) - } - - "Prefer prepended properties to the test.default.props" in { - val testProps = TestProps() - - testProps.prependProvider(Map("jetty.port" -> "8080")) - val port = testProps.getInt("jetty.port") - - port must_== Full(8080) - } - - "Prefer prepended System.properties to the test.default.props" in { - val testProps = TestProps() - - System.setProperty("omniauth.baseurl1", "http://google.com") - - testProps.prependProvider(sys.props) - val baseurl = testProps.get("omniauth.baseurl1") - - baseurl must_== Full("http://google.com") - } - - "Read through to System.properties, correctly handling mutation" in { - val testProps = TestProps() - - System.setProperty("omniauth.baseurl2", "http://google.com") - testProps.prependProvider(sys.props) - System.setProperty("omniauth.baseurl2", "http://ebay.com") - val baseurl = testProps.get("omniauth.baseurl2") - - baseurl must_== Full("http://ebay.com") - } - - "Find properties in appended maps when not defined in test.default.props" in { - val testProps = TestProps() - - testProps.appendProvider(Map("new.prop" -> "new.value")) - val prop = testProps.get("new.prop") - - prop must_== Full("new.value") - } - - "Not interpolate values when no interpolator is given" in { - val port = TestProps().get("jetty.port") - - port must_== Full("${PORT}") - } - - "Interpolate values from the given interpolator" in { - val testProps = TestProps() - - testProps.appendInterpolationValues(Map("PORT" -> "8080")) - val port = testProps.getInt("jetty.port") - - port must_== Full(8080) - } - - "Interpolate multiple values in a string from the given interpolator" in { - val testProps = TestProps() - - testProps.appendInterpolationValues(Map("DB_HOST" -> "localhost", "DB_PORT" -> "3306")) - val url = testProps.get("db.url") - - url must_== Full("jdbc:mysql://localhost:3306/MYDB") - } - - "Find properties in append for require()" in { - val testProps = TestProps() - - testProps.appendProvider(Map("new.prop" -> "new.value")) - testProps.require("new.prop") must_== Nil - } - - "Find properties in prepend for require()" in { - val testProps = TestProps() - - testProps.prependProvider(Map("new.prop" -> "new.value")) - testProps.require("new.prop") must_== Nil - } - } -} diff --git a/core/util/src/test/scala-2.13/net/liftweb/util/ScheduleSpec.scala b/core/util/src/test/scala-2.13/net/liftweb/util/ScheduleSpec.scala deleted file mode 100644 index e60f0af3c0..0000000000 --- a/core/util/src/test/scala-2.13/net/liftweb/util/ScheduleSpec.scala +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright 2007-2026 Lift Committers and Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package net.liftweb -package util - -import org.specs2.mutable.Specification -import org.specs2.specification.BeforeEach -import org.specs2.execute.PendingUntilFixed - -import actor._ -import Helpers._ - - -/** - * Systems under specification for Lift Schedule. - */ -class ScheduleSpec extends Specification with PendingUntilFixed with PingedService with BeforeEach { - "Schedule Specification".title - - def before = Schedule.restart - - "The Schedule object" should { - "provide a schedule method to ping an actor regularly" in { - Schedule.schedule(service, Alive, TimeSpan(10)) - service.pinged must eventually(beTrue) - } - "honor multiple restarts" in { - Schedule.restart - Schedule.restart - Schedule.restart - Schedule.schedule(service, Alive, TimeSpan(10)) - service.pinged must eventually(beTrue) - } - "honor shutdown followed by restart" in { - Schedule.shutdown() - Schedule.restart - Schedule.schedule(service, Alive, TimeSpan(10)) - service.pinged must eventually(beTrue) - } - "not honor multiple shutdowns" in { - Schedule.shutdown() - Schedule.shutdown() -// service.pinged must eventually(beFalse) - service.pinged must throwA[ActorPingException] - }.pendingUntilFixed - } - -} - - -trait PingedService { - case object Alive - val service = new Service - - class Service extends LiftActor { - @volatile var pinged = false - /* - def act() { - while (true) { - receive { - case Alive => {pinged = true; exit()} - } - } - } - */ - protected def messageHandler = { - case Alive => {pinged = true /*; exit() */} - } - } -} diff --git a/core/util/src/test/scala-2.13/net/liftweb/util/SecurityHelpersSpec.scala b/core/util/src/test/scala-2.13/net/liftweb/util/SecurityHelpersSpec.scala deleted file mode 100644 index 58e8efb1bc..0000000000 --- a/core/util/src/test/scala-2.13/net/liftweb/util/SecurityHelpersSpec.scala +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright 2006-2026 Lift Committers and Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package net.liftweb -package util - -import org.xml.sax.SAXParseException - -import org.specs2.mutable.Specification - -import SecurityHelpers._ - -/** - * Systems under specification for SecurityHelpers. - */ -class SecurityHelpersSpec extends Specification { - "SecurityHelpers Specification".title - - "Security Helpers" should { - "not parse XML with a DOCTYPE" in { - secureXML.loadString(""" - - ]> - &xxe;""" - ) must throwA[SAXParseException] - } - - "parse XML without a DOCTYPE" in { - secureXML.loadString(""" - & - """).toString must_== "&" - } - - "provide a randomLong method returning a random Long modulo a number" in { - randomLong(7L) must be_<(7L) - } - "provide a randomInt method returning a random Int modulo a number" in { - randomInt(7) must be_<(7) - } - "provide a shouldShow function always returning true only a given percentage of time, expressed as a Int between 0 and 100" in { - shouldShow(100) must beTrue - shouldShow(0) must beFalse - } - "provide a shouldShow function always returning true only a given percentage of time, expressed as a Double between 0 and 1.0" in { - shouldShow(1.0) must beTrue - shouldShow(0.0) must beFalse - } - - /* - "provide makeBlowfishKey, blowfishEncrypt, blowfishDecrypt functions to encrypt/decrypt Strings with Blowfish keys" in { - val key = makeBlowfishKey - val encrypted = blowfishEncrypt("hello world", key) - encrypted must_!= "hello world" - blowfishDecrypt(encrypted, key) must_== "hello world" - } - */ - - "provide a md5 function to create a md5 digest from a string" in { - md5("hello") must_== "XUFAKrxLKna5cZ2REBfFkg==" - md5("hello") must_!= md5("hell0") - } - "provide a hash function to create a SHA digest from a string" in { - hash("hello") must_== "qvTGHdzF6KLavt4PO0gs2a6pQ00=" - hash("hello") must_!= hash("hell0") - } - "provide a hash256 function to create a SHA-256 digest from a string" in { - hash256("hello") must_== "LPJNul+wow4m6DsqxbninhsWHlwfp0JecwQzYpOLmCQ=" - hash256("hello") must_!= hash256("hell0") - } - "provide a hex encoded SHA hash function" in { - hexDigest("hello".getBytes) must_== "aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d" - hexDigest("hello".getBytes) must_!= hexDigest("hell0".getBytes) - } - "provide a hex encoded SHA-256 hash function" in { - hexDigest256("hello".getBytes) must_== "2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824" - hexDigest256("hello".getBytes) must_!= hexDigest256("hell0".getBytes) - } - } - -} - diff --git a/core/util/src/test/scala-2.13/net/liftweb/util/SoftReferenceCacheSpec.scala b/core/util/src/test/scala-2.13/net/liftweb/util/SoftReferenceCacheSpec.scala deleted file mode 100644 index 426bd9163b..0000000000 --- a/core/util/src/test/scala-2.13/net/liftweb/util/SoftReferenceCacheSpec.scala +++ /dev/null @@ -1,27 +0,0 @@ -package net.liftweb.util - -import org.specs2.mutable._ -import net.liftweb.common._ - -class SoftReferenceCacheSpec extends Specification { - - sequential - - object cache extends SoftReferenceCache[String, String](1) - - "SoftReferenceCache " should { - "Accept additions" in { - cache += ("test" -> "test") - cache.keys.size() must_== 1 - } - "Allow objects to be retrieved" in { - val cached = cache("test") - cached must beLike { case Full("test") => ok } - } - "Properly age out entries" in { - cache += ("test2" -> "test2") - cache("test") must_== Empty - } - } - -} diff --git a/core/util/src/test/scala-2.13/net/liftweb/util/StringHelpersSpec.scala b/core/util/src/test/scala-2.13/net/liftweb/util/StringHelpersSpec.scala deleted file mode 100644 index 5608384779..0000000000 --- a/core/util/src/test/scala-2.13/net/liftweb/util/StringHelpersSpec.scala +++ /dev/null @@ -1,351 +0,0 @@ -/* - * Copyright 2007-2026 Lift Committers and Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package net.liftweb -package util - -import org.specs2.mutable.Specification -import org.specs2.ScalaCheck -import org.scalacheck.Gen._ -import org.scalacheck.Prop.forAll - -import StringHelpers._ - - -/** - * Systems under specification for StringHelpers. - */ -class StringHelpersSpec extends Specification with ScalaCheck with StringGen { - "StringHelpers Specification".title - - "The snakify function" should { - "replace upper case with underscore" in { - snakify("MyCamelCase") must_== "my_camel_case" - snakify("CamelCase") must_== "camel_case" - snakify("Camel") must_== "camel" - snakify("MyCamel12Case") must_== "my_camel12_case" - snakify("CamelCase12") must_== "camel_case12" - snakify("Camel12") must_== "camel12" - } - - "not modify existing snake case strings" in { - snakify("my_snake_case") must_== "my_snake_case" - snakify("snake") must_== "snake" - } - - "handle abbeviations" in { - snakify("HTML") must_== "html" - snakify("HTMLEditor") must_== "html_editor" - snakify("EditorTOC") must_== "editor_toc" - snakify("HTMLEditorTOC") must_== "html_editor_toc" - - snakify("HTML5") must_== "html5" - snakify("HTML5Editor") must_== "html5_editor" - snakify("Editor2TOC") must_== "editor2_toc" - snakify("HTML5Editor2TOC") must_== "html5_editor2_toc" - } - } - - "The camelify function" should { - "CamelCase a name which is underscored, removing each underscore and capitalizing the next letter" in { - def previousCharacterIsUnderscore(name: String, i: Int) = i > 1 && name.charAt(i - 1) == '_' - def underscoresNumber(name: String, i: Int) = if (i == 0) 0 else name.substring(0, i).toList.count(_ == '_') - def correspondingIndexInCamelCase(name: String, i: Int) = i - underscoresNumber(name, i) - def correspondingCharInCamelCase(name: String, i: Int): Char = camelify(name).charAt(correspondingIndexInCamelCase(name, i)) - - val doesntContainUnderscores = forAll(underscoredStrings){ ((name: String) => !camelify(name).contains("_")) } - val isCamelCased = forAll(underscoredStrings) ((name: String) => { - name.forall(_ == '_') && camelify(name).isEmpty || - name.toList.zipWithIndex.forall { case (c, i) => - c == '_' || - correspondingIndexInCamelCase(name, i) == 0 && correspondingCharInCamelCase(name, i) == c.toUpper || - !previousCharacterIsUnderscore(name, i) && correspondingCharInCamelCase(name, i) == c || - previousCharacterIsUnderscore(name, i) && correspondingCharInCamelCase(name, i) == c.toUpper - } - }) - (doesntContainUnderscores && isCamelCased) - } - "return an empty string if given null" in { - camelify(null) must_== "" - } - "leave a CamelCased name untouched" in { - forAll(camelCasedStrings){ (name: String) => camelify(name) == name } - } - } - - "The camelifyMethod function" should { - "camelCase a name with the first letter being lower cased" in { - forAll(underscoredStrings){ - (name: String) => - camelify(name).isEmpty && camelifyMethod(name).isEmpty || - camelifyMethod(name).toList.head.isLower && camelify(name) == camelifyMethod(name).capitalize - } - } - } - - "SuperListString" should { - """allow "foo" / "bar" """ in { - ("foo" / "bar") must_== List("foo", "bar") - } - - """allow "foo" / "bar" / "baz" """ in { - ("foo" / "bar" / "baz") must_== List("foo", "bar", "baz") - } - } - - "The StringHelpers processString function" should { - "replace groups found in a string surrounded by <%= ... %> by their corresponding value in a map" in { - processString("<%=hello%>", Map("hello" -> "bonjour")) must_== "bonjour" - } - "replace groups found in several strings surrounded by <%= ... %> by their corresponding value in a map" in { - processString("<%=hello%> <%=world%>", Map("hello" -> "bonjour", "world" -> "monde")) must_== "bonjour monde" - } - "not replace the group if it starts with %" in { - processString("<%=%hello%>", Map("hello" -> "bonjour")) must_== "<%=%hello%>" - } - "throw an exception if no correspondance is found" in { - processString("<%=hello%>", Map("hallo" -> "bonjour")) must throwA[Exception] - } - } - - "The StringHelpers capify function" should { - "capitalize a word" in { - capify("hello") must_== "Hello" - } - "capitalize the first letters of 2 words" in { - capify("hello world") must_== "Hello World" - } - "capitalize the first letters of 2 words separated by an underscore" in { - capify("hello_world") must_== "Hello_World" - } - "capitalize the second character in a word if the first is a digit" in { - capify("hello 1world") must_== "Hello 1World" - } - "capitalize the third character in a word if the first 2 are digits" in { - capify("hello 12world") must_== "Hello 12World" - } - "suppress symbols placed in front of words and capitalize the words" in { - capify("@hello $world") must_== "Hello World" - } - "remove letters in the word if there are more than 250 digits in front of it" in { - capify("1" * 250 + "hello") must_== "1" * 250 - } - } - "The StringHelpers clean function" should { - "return an empty string if the input is null" in { - clean(null) must_== "" - } - "remove every character which is not a-zA-Z0-9_" in { - clean(" He@llo Wor+ld_!") must_== "HelloWorld_" - } - } - "The StringHelpers randomString" should { - "return an empty string if size is 0" in { - randomString(0) must_== "" - } - /* - "return a string of size n" in { - randomString(10).toSeq must haveSize(10) - } - */ - - "return only capital letters and digits" in { - randomString(10) must beMatching("[A-Z0-9]*") - } - } - "The StringHelpers escChar" should { - "return the unicode value of a character as a string starting with \\u" in { - escChar('{') must_== "\\u007b" - escChar('A') must_== "\\u0041" - } - } - "The StringHelpers splitColonPair" should { - "split a string separated by a dot in 2 parts" in { - splitColonPair("a.b", "1", "2") must_== ("a", "b") - } - "split a string separated by a dot in 2 trimmed parts" in { - splitColonPair(" a . b ", "1", "2") must_== ("a", "b") - } - "split a string separated by a column in 2 parts" in { - splitColonPair("a:b", "1", "2") must_== ("a", "b") - } - "split a string according to the dot prioritarily" in { - splitColonPair("a.b:c", "1", "2") must_== ("a", "b:c") - } - "split a string according to first the dot if there are several ones and removing everything after the next dot" in { - splitColonPair("a.b.c", "1", "2") must_== ("a", "b") - splitColonPair("a.b.c.d", "1", "2") must_== ("a", "b") - } - "use a default value for the second part if there is nothing to split" in { - splitColonPair("abc", "1", "2") must_== ("abc", "2") - } - "use null for the first part if the input string is null" in { - splitColonPair(null, "1", "2") must_== ("", "2") - } - "use a default value for the first part if the input string is empty" in { - splitColonPair("", "1", "2") must_== ("1", "2") - } - } - "The StringHelpers parseNumber function" should { - "return a Long corresponding to the value of a string with digits" in { - parseNumber("1234") must_== 1234L - } - "return a positive Long value if the string starts with +" in { - parseNumber("+1234") must_== 1234L - } - "return a positive Long value if the string starts with -" in { - parseNumber("-1234") must_== -1234L - } - "return 0 if the string is null" in { - parseNumber(null) must_== 0L - } - "return 0 if the string is empty" in { - parseNumber("") must_== 0L - } - "return 0 if the string can't be parsed" in { - parseNumber("string") must_== 0L - } - } - "The SuperString class roboSplit method" should { - "split a string according to a separator" in { - "hello".roboSplit("ll") must_== List("he", "o") - } - "split a string according to a separator - 2" in { - "hAeAlAlAo".roboSplit("A") must_== List("h", "e", "l", "l", "o") - } - "split a string into trimmed parts" in { - "hello . world ".roboSplit("\\.") must_== List("hello", "world") - } - "split a string into trimmed parts whose length is > 0" in { - "hello . . world ".roboSplit("\\.") must_== List("hello", "world") - } - "split a string according to a separator. The separator is always interpreted as a regular expression" in { - "hello".roboSplit("(l)+") must_== List("he", "o") - } - "return a list containing the string if the separator is not found" in { - "hello".roboSplit("tt") must_== List("hello") - } - "return an empty list if the string is null" in { - (null: String).roboSplit("a") must_== List() - } - "return a list containing the string if the string is empty" in { - "".roboSplit("a") must_== List() - } - } - - "The SuperString class charSplit method" should { - "split a string according to a separator" in { - "hello".charSplit('l') must_== List("he", "o") - } - "split a string according to a separator - 2" in { - "hAeAlAlAo".charSplit('A') must_== List("h", "e", "l", "l", "o") - } - "split a string" in { - "hello . world ".charSplit('.') must_== List("hello ", " world ") - } - "split a string into parts" in { - "hello .. world ".charSplit('.') must_== List("hello ", " world ") - } - "return an empty list if the string is null" in { - (null: String).charSplit('a') must_== List() - } - "return a list containing the string if the string is empty" in { - "".charSplit('a') must_== List() - } - } - - - "The SuperString class splitAt method" should { - "split a string according to a separator and return a List containing a pair with the 2 parts" in { - stringToSuper("hello").splitAt("ll") must_== List(("he", "o")) - } - "split a string according to a separator and return an empty List if no separator is found" in { - stringToSuper("hello").splitAt("tt") must_== Nil - } - "split a string according to a separator and return an empty List if the string is null" in { - stringToSuper(null: String).splitAt("tt") must_== Nil - } - } - "The SuperString class encJs method" should { - "encode a string replacing backslash with its unicode value" in { - "\\hello".encJs must_== "\"\\u005chello\"" - } - "encode a string replacing the quote character with its unicode value" in { - "h'ello".encJs must_== "\"h\\u0027ello\"" - } - "encode a string adding a quote before and a quote after the string" in { - "hello".encJs must_== "\"hello\"" - } - "encode a string replacing non-ASCII characters by their unicode value" in { - "ni\u00f1a".encJs must_== "\"ni\\u00f1a\"" - } - "return the string \"null\" if the input string is null" in { - (null: String).encJs must_== "null" - } - } - "The SuperString class commafy method" should { - "add a comma before the last 3 characters of the input string" in { - "hello".commafy must_== "he,llo" - } - "add nothing if the input string is less than 4 characters" in { - "hel".commafy must_== "hel" - } - "return null if the input string is null" in { - (null: String).commafy must beNull - } - } - "The blankForNull method" should { - "return the empty String for a given null String" in { - StringHelpers.blankForNull(null) must_== "" - } - "return the given String for a given not-null String" in { - StringHelpers.blankForNull("x") must_== "x" - } - } - "The emptyForBlank method" should { - import net.liftweb.common._ - "return Empty for a given null String" in { - StringHelpers.emptyForBlank(null) must_== Empty - } - "return Empty for a given a blank String" in { - StringHelpers.emptyForBlank("") must_== Empty - } - "return Empty for a String of spaces" in { - StringHelpers.emptyForBlank(" ") must_== Empty - } - "return the trim'ed String for a given not-null String" in { - StringHelpers.emptyForBlank(" x ") must_== Full("x") - } - } -} - - -trait StringGen { - val underscoredStrings = - for { - length <- choose(0, 4) - s <- listOfN(length, frequency((3, alphaChar), (1, oneOf(List('_'))))) - } yield s.mkString - - val camelCasedStrings = - for { - length <- choose(0, 4) - firstLetter <- alphaNumChar.map(_.toUpper) - string <- listOfN(length, frequency((3, alphaNumChar.map(_.toLower)), - (1, alphaNumChar.map(_.toUpper)))) - } yield (firstLetter :: string).mkString -} - diff --git a/core/util/src/test/scala-2.13/net/liftweb/util/TimeHelpersSpec.scala b/core/util/src/test/scala-2.13/net/liftweb/util/TimeHelpersSpec.scala deleted file mode 100644 index fbce5cfc1b..0000000000 --- a/core/util/src/test/scala-2.13/net/liftweb/util/TimeHelpersSpec.scala +++ /dev/null @@ -1,248 +0,0 @@ -/* - * Copyright 2006-2026 Lift Committers and Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package net.liftweb -package util - -import java.util.{Calendar, Date, TimeZone} - -import net.liftweb.common._ -import net.liftweb.util.TimeHelpers._ -import org.joda.time.{Period, DateTimeZone, DateTime} -import org.scalacheck.Gen._ -import org.scalacheck.Prop._ -import org.specs2.ScalaCheck -import org.specs2.execute.AsResult -import org.specs2.matcher.MatchersImplicits -import org.specs2.mutable.{Around, Specification} - -/** - * Systems under specification for TimeHelpers. - */ -class TimeHelpersSpec extends Specification with ScalaCheck with TimeAmountsGen { - "TimeHelpers Specification".title - - "A TimeSpan" can { - "be created from a number of milliseconds" in forAllTimeZones { - TimeSpan(3000) must_== TimeSpan(3 * 1000) - } - "be created from a number of seconds" in forAllTimeZones { - 3.seconds must_== TimeSpan(3 * 1000) - } - "be created from a number of minutes" in forAllTimeZones { - 3.minutes must_== TimeSpan(3 * 60 * 1000) - } - "be created from a number of hours" in forAllTimeZones { - 3.hours must_== TimeSpan(3 * 60 * 60 * 1000) - } - "be created from a number of days" in forAllTimeZones { - 3.days must_== TimeSpan(3 * 24 * 60 * 60 * 1000) - } - "be created from a number of weeks" in forAllTimeZones { - 3.weeks must_== TimeSpan(3 * 7 * 24 * 60 * 60 * 1000) - } - "be created from a number of months" in forAllTimeZones { - 3.months must_== Period.months(3) - } - "be created from a number of years" in forAllTimeZones { - 3.years must_== Period.years(3) - } - "be converted implicitly to a date starting from the epoch time" in forAllTimeZones { - 3.seconds.after(new Date(0)) must beTrue - } - "be converted to a date starting from the epoch time, using the date method" in forAllTimeZones { - 3.seconds.after(new Date(0)) must beTrue - } - "be compared to another TimeSpan" in forAllTimeZones { - 3.seconds must_== 3.seconds - 3.seconds must_!= 2.seconds - } - "be compared to another object" in forAllTimeZones { - 3.seconds must_!= "string" - } - } - - "A TimeSpan" should { - "return a new TimeSpan representing the sum of the 2 times when added with another TimeSpan" in forAllTimeZones { - 3.seconds + 3.seconds must_== 6.seconds - } - "return a new TimeSpan representing the difference of the 2 times when substracted with another TimeSpan" in forAllTimeZones { - 3.seconds - 4.seconds must_== (-1).seconds - } - "have a toString method returning the relevant number of weeks, days, hours, minutes, seconds, millis" in forAllTimeZones { - val conversionIsOk = forAll(timeAmounts)((t: TimeAmounts) => { val (timeSpanToString, timeSpanAmounts) = t - timeSpanAmounts forall { case (amount, unit) => - amount >= 1 && - timeSpanToString.contains(amount.toString) || true } - }) - val timeSpanStringIsPluralized = forAll(timeAmounts)((t: TimeAmounts) => { val (timeSpanToString, timeSpanAmounts) = t - timeSpanAmounts forall { case (amount, unit) => - amount > 1 && timeSpanToString.contains(unit + "s") || - amount == 1 && timeSpanToString.contains(unit) || - amount == 0 && !timeSpanToString.contains(unit) - } - }) - conversionIsOk && timeSpanStringIsPluralized - } - } - - "the TimeHelpers" should { - "provide a 'seconds' function transforming a number of seconds into millis" in forAllTimeZones { - seconds(3) must_== 3 * 1000 - } - "provide a 'minutes' function transforming a number of minutes into millis" in forAllTimeZones { - minutes(3) must_== 3 * 60 * 1000 - } - "provide a 'hours' function transforming a number of hours into milliss" in forAllTimeZones { - hours(3) must_== 3 * 60 * 60 * 1000 - } - "provide a 'days' function transforming a number of days into millis" in forAllTimeZones { - days(3) must_== 3 * 24 * 60 * 60 * 1000 - } - "provide a 'weeks' function transforming a number of weeks into millis" in forAllTimeZones { - weeks(3) must_== 3 * 7 * 24 * 60 * 60 * 1000 - } - "provide a noTime function on Date objects to transform a date into a date at the same day but at 00:00" in forAllTimeZones { - hourFormat(now.noTime) must_== "00:00:00" - } - - "provide a day function returning the day of month corresponding to a given date (relative to UTC)" in forAllTimeZones { - day(today.setTimezone(utc).setDay(3).getTime) must_== 3 - } - "provide a month function returning the month corresponding to a given date" in forAllTimeZones { - month(today.setTimezone(utc).setMonth(4).getTime) must_== 4 - } - "provide a year function returning the year corresponding to a given date" in forAllTimeZones { - year(today.setTimezone(utc).setYear(2008).getTime) must_== 2008 - } - "provide a millisToDays function returning the number of days since the epoch time" in forAllTimeZones { - millisToDays(new Date(0).getTime) must_== 0 - millisToDays(today.setYear(1970).setMonth(0).setDay(1).getTime.getTime) must_== 0 // the epoch time - // on the 3rd day after the epoch time, 2 days are passed - millisToDays(today.setTimezone(utc).setYear(1970).setMonth(0).setDay(3).getTime.getTime) must_== 2 - } - "provide a daysSinceEpoch function returning the number of days since the epoch time" in forAllTimeZones { - daysSinceEpoch must_== millisToDays(now.getTime) - } - "provide a time function creating a new Date object from a number of millis" in forAllTimeZones { - time(1000) must_== new Date(1000) - } - "provide a calcTime function returning the time taken to evaluate a block in millis and the block's result" in forAllTimeZones { - val (time, result) = calcTime((1 to 10).reduceLeft[Int](_ + _)) - time.toInt must beCloseTo(0, 1000) // it should take less than 1 second! - result must_== 55 - } - - "provide a hourFormat function to format the time of a date object" in forAllTimeZones { - hourFormat(Calendar.getInstance(utc).noTime.getTime) must_== "00:00:00" - } - - "provide a formattedDateNow function to format todays date" in forAllTimeZones { - formattedDateNow must beMatching("\\d\\d\\d\\d/\\d\\d/\\d\\d") - } - "provide a formattedTimeNow function to format now's time with the TimeZone" in forAllTimeZones { - val regex = "\\d\\d:\\d\\d (....?.?|GMT((\\+|\\-)\\d\\d:\\d\\d)?)" - "10:00 CEST" must beMatching(regex) - "10:00 GMT+02:00" must beMatching(regex) - "10:00 GMT" must beMatching(regex) - "10:00 XXX" must beMatching(regex) - formattedTimeNow must beMatching(regex) - } - - "provide a parseInternetDate function to parse a string formatted using the internet format" in forAllTimeZones { - parseInternetDate(internetDateFormatter.format(now)).getTime.toLong must beCloseTo(now.getTime.toLong, 1000L) - } - "provide a parseInternetDate function returning new Date(0) if the input date cant be parsed" in forAllTimeZones { - parseInternetDate("unparsable") must_== new Date(0) - } - "provide a toInternetDate function formatting a date to the internet format" in forAllTimeZones { - toInternetDate(now) must beMatching("..., \\d* ... \\d\\d\\d\\d \\d\\d:\\d\\d:\\d\\d .*") - } - "provide a toDate returning a Full(date) from many kinds of objects" in forAllTimeZones { - val d = now - List(null, Nil, None, Failure("", Empty, Empty)) forall { toDate(_) must_== Empty } - List(Full(d), Some(d), List(d)) forall { toDate(_) must_== Full(d) } - - toDate(internetDateFormatter.format(d)) must beLike { - case Full(converted) => - converted.getTime.toLong must beCloseTo(d.getTime.toLong, 1000L) - } - } - } - - "The Calendar class" should { - "have a setDay method setting the day of month and returning the updated Calendar" in forAllTimeZones { - day(today.setTimezone(utc).setDay(1).getTime) must_== 1 - } - "have a setMonth method setting the month and returning the updated Calendar" in forAllTimeZones { - month(today.setTimezone(utc).setMonth(0).getTime) must_== 0 - } - "have a setYear method setting the year and returning the updated Calendar" in forAllTimeZones { - year(today.setTimezone(utc).setYear(2008).getTime) must_== 2008 - } - "have a setTimezone method to setting the time zone and returning the updated Calendar" in forAllTimeZones { - today.setTimezone(utc).getTimeZone must_== utc - } - "have a noTime method to setting the time to 00:00:00 and returning the updated Calendar" in forAllTimeZones { - hourFormat(today.noTime.getTime) must_== "00:00:00" - } - } -} - -object forAllTimeZones extends Around { - import MatchersImplicits._ - - override def around[T: AsResult](f: => T) = synchronized { - import scala.jdk.CollectionConverters._ - // setDefault is on static context so tests should be sequenced - // some timezones for java (used in formatters) and for Joda (other computations) has other offset - val commonJavaAndJodaTimeZones = (TimeZone.getAvailableIDs.toSet & DateTimeZone.getAvailableIDs.asScala.toSet).filter { timeZoneId => - TimeZone.getTimeZone(timeZoneId).getOffset(millis) == DateTimeZone.forID(timeZoneId).getOffset(millis) - } - val tzBefore = TimeZone.getDefault - val dtzBefore = DateTimeZone.getDefault - try { - forall(commonJavaAndJodaTimeZones) { timeZoneId => - TimeZone.setDefault(TimeZone.getTimeZone(timeZoneId)) - DateTimeZone.setDefault(DateTimeZone.forID(timeZoneId)) - f - } - } finally { - TimeZone.setDefault(tzBefore) - DateTimeZone.setDefault(dtzBefore) - } - } -} - - -trait TimeAmountsGen { - - type TimeAmounts = (String, List[(Int, String)]) - - val timeAmounts = - for { - w <- choose(0, 2) - d <- choose(0, 6) - h <- choose(0, 23) - m <- choose(0, 59) - s <- choose(0, 59) - ml <- choose(0, 999) - } - yield ( - TimeSpan(weeks(w) + days(d) + hours(h) + minutes(m) + seconds(s) + ml).toString, - (w, "week") :: (d, "day") :: (h, "hour") :: (m, "minute") :: (s, "second") :: (ml, "milli") :: Nil - ) -} diff --git a/core/util/src/test/scala-2.13/net/liftweb/util/ToHeadSpec.scala b/core/util/src/test/scala-2.13/net/liftweb/util/ToHeadSpec.scala deleted file mode 100644 index 888a78b729..0000000000 --- a/core/util/src/test/scala-2.13/net/liftweb/util/ToHeadSpec.scala +++ /dev/null @@ -1,146 +0,0 @@ -/* - * Copyright 2007-2026 Lift Committers and Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package net.liftweb -package util - -import org.specs2.matcher.XmlMatchers -import org.specs2.mutable.Specification - -import common._ -import ControlHelpers._ -import HeadHelper._ -import Helpers.secureXML - -/** - * Systems under specification for ToHead. - */ -class ToHeadSpec extends Specification with XmlMatchers { - "ToHead Specification".title - - "lift merger" should { - "merge /html/body//head into existing /html/head section" in { - val susfiles = for { - act <- tryo(getClass.getResource("ToHeadSpec.actual1.html")).filter(_ ne null) - exp <- tryo(getClass.getResource("ToHeadSpec.expected1.html")).filter(_ ne null) - } yield (act, exp) - - susfiles must beLike { - case Full(sus) => - val actual = secureXML.load(sus._1) - val expected = secureXML.load(sus._2) - mergeToHtmlHead(actual).toString.replaceAll("\\s", "") must_== - (expected.toString.replaceAll("\\s", "")) - } - } - - "merge from real example" in { - val susfiles = for { - act <- tryo(getClass.getResource("ToHeadSpec.actual2.html")).filter(_ ne null) - exp <- tryo(getClass.getResource("ToHeadSpec.expected2.html")).filter(_ ne null) - } yield (act, exp) - - susfiles must beLike { - case Full(sus) => - val actual = secureXML.load(sus._1) - val expected = secureXML.load(sus._2) - mergeToHtmlHead(actual) must ==/(expected) - } - } - - "merge into a new head if not previously exist" in { - val susfiles = for { - act <- tryo(getClass.getResource("ToHeadSpec.actual3.html")).filter(_ ne null) - exp <- tryo(getClass.getResource("ToHeadSpec.expected3.html")).filter(_ ne null) - } yield (act, exp) - - susfiles must beLike { - case Full(sus) => - val actual = secureXML.load(sus._1) - val expected = secureXML.load(sus._2) - mergeToHtmlHead(actual).toString.replaceAll("\\s", "") must_== - (expected.toString.replaceAll("\\s", "")) - } - } - } - - /* - "lift head cleaner" should { - "remove duplicate title tag" >> { - val actual = (hellohello2hello3) - - val expected = (hello) - - HeadHelper.cleanHead(actual) must beEqualToIgnoringSpace(expected) - } - "remove script tag with same id as previous script tag" >> { - val invariant = () - HeadHelper.cleanHead(invariant) must beEqualToIgnoringSpace(invariant) - - val actual = () - val expected = () - HeadHelper.cleanHead(actual) must beEqualToIgnoringSpace(expected) - } - "remove script tag with src attributes if src attributes are equals to previous script" >> { - val actual = () - val expected = () - HeadHelper.cleanHead(actual) must beEqualToIgnoringSpace(expected) - - val actual2 = () - val expected2 = () - HeadHelper.cleanHead(actual2) must beEqualToIgnoringSpace(expected2) - } - "remove script tag if content are equals to previous script (need to trim each line ?)" >> { - val actual = () - val expected = () - HeadHelper.cleanHead(actual) must beEqualToIgnoringSpace(expected) - } - "remove link to css with same id as previous link tag" >> { - val invariant = () - HeadHelper.cleanHead(invariant) must beEqualToIgnoringSpace(invariant) - - val actual = () - val expected = () - HeadHelper.cleanHead(actual) must beEqualToIgnoringSpace(expected) - } - "remove link tag with href attributes if href attributes are equals to previous link" >> { - val invariant = () - HeadHelper.cleanHead(invariant) must beEqualToIgnoringSpace(invariant) - - val actual = () - val expected = () - HeadHelper.cleanHead(actual) must beEqualToIgnoringSpace(expected) - } - "remove style tag with same id as previous style tag" >> { - val invariant = () - HeadHelper.cleanHead(invariant) must beEqualToIgnoringSpace(invariant) - - val actual = () - val expected = () - HeadHelper.cleanHead(actual) must beEqualToIgnoringSpace(expected) - } - "remove style tag if content are equals to previous style (need to trim each line ?)" >> { - val invariant = () - HeadHelper.cleanHead(invariant) must beEqualToIgnoringSpace(invariant) - - val actual = () - val expected = () - HeadHelper.cleanHead(actual) must beEqualToIgnoringSpace(expected) - } - } -*/ -} - diff --git a/core/util/src/test/scala-2.13/net/liftweb/util/VCardParserSpec.scala b/core/util/src/test/scala-2.13/net/liftweb/util/VCardParserSpec.scala deleted file mode 100644 index dcbe4f3bf0..0000000000 --- a/core/util/src/test/scala-2.13/net/liftweb/util/VCardParserSpec.scala +++ /dev/null @@ -1,143 +0,0 @@ -/* - * Copyright 2008-2026 Lift Committers and Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package net.liftweb -package util - -import org.specs2.matcher.XmlMatchers -import org.specs2.mutable.Specification - - -/** - * Systems under specification for VCardParser. - */ -class VCardParserSpec extends Specification with XmlMatchers { - "VCardParser Specification".title - - val vcard = - """BEGIN:VCARD - |VERSION:2.1 - |N:Gump;Forrest - |FN:Forrest Gump - |ORG:Bubba Gump Shrimp Co. - |TITLE:Shrimp Man - |TEL;WORK;VOICE:(111) 555-1212 - |TEL;HOME;VOICE:(404) 555-1212 - |END:VCARD""".stripMargin - - "VCard" should { - "parse a basic VCard (2.1) correctly" in { - val list = VCardParser.parse(vcard) - list must beLike { - case Left(l) => { - import VCardParser._ - l must_== - List( - VCardEntry(VCardKey("BEGIN", Nil), List("VCARD")), - VCardEntry(VCardKey("VERSION", Nil), List("2.1")), - VCardEntry(VCardKey("N", Nil), List("Gump", "Forrest")), - VCardEntry(VCardKey("FN", Nil), List("Forrest Gump")), - VCardEntry(VCardKey("ORG", Nil), List("Bubba Gump Shrimp Co.")), - VCardEntry(VCardKey("TITLE", Nil), List("Shrimp Man")), - VCardEntry(VCardKey("TEL", List(("WORK", ""), ("VOICE", ""))), List("(111) 555-1212")), - VCardEntry(VCardKey("TEL", List(("HOME", ""), ("VOICE", ""))), List("(404) 555-1212")), - VCardEntry(VCardKey("END", Nil), List("VCARD"))) - } - } - } - - "parse a basic Apple VCard (3.0) correctly" in { - - val appleIOS9DavidTaylorVCard3 = - """BEGIN:VCARD - |VERSION:3.0 - |PRODID:-//Apple Inc.//iPhone OS 9.3//EN - |N:Taylor;David;;; - |FN: David Taylor - |TEL;type=HOME;type=VOICE;type=pref:555-610-6679 - |item1.ADR;type=HOME;type=pref:;;1747 Steuart Street;Tiburon;CA;94920;USA - |item1.X-ABADR:us - |BDAY:1998-06-15 - |END:VCARD""".stripMargin - - val list = VCardParser.parse(appleIOS9DavidTaylorVCard3) - list must beLike { - case Left(l) => { - import VCardParser._ - l must_== - List( - VCardEntry(VCardKey("BEGIN", Nil), List("VCARD")), - VCardEntry(VCardKey("VERSION", Nil), List("3.0")), - VCardEntry(VCardKey("PRODID", Nil),List("-//Apple Inc.//iPhone OS 9.3//EN")), - VCardEntry(VCardKey("N", Nil), List("Taylor", "David", "", "", "")), - VCardEntry(VCardKey("FN", Nil), List(" David Taylor")), - VCardEntry(VCardKey("TEL", List(("type", "HOME"), ("type", "VOICE"), ("type", "pref"))), List("555-610-6679")), - VCardEntry(VCardKey("ADR", List(("type","HOME"), ("type","pref"))),List("", "", "1747 Steuart Street", "Tiburon", "CA", "94920", "USA")), - VCardEntry(VCardKey("X-ABADR",Nil),List("us")), - VCardEntry(VCardKey("BDAY",Nil),List("1998-06-15")), - VCardEntry(VCardKey("END", Nil), List("VCARD"))) - } - } - - } - - "parse a more complex Apple VCard (3.0) correctly" in { - - val appleIOS9JohnAppleseedVCard3 = - """BEGIN:VCARD - |VERSION:3.0 - |PRODID:-//Apple Inc.//iPhone OS 9.3//EN - |N:Appleseed;John;;; - |FN: John Appleseed - |EMAIL;type=INTERNET;type=WORK;type=pref:John-Appleseed@mac.com - |TEL;type=CELL;type=VOICE;type=pref:888-555-5512 - |TEL;type=HOME;type=VOICE:888-555-1212 - |item1.ADR;type=WORK;type=pref:;;3494 Kuhl Avenue;Atlanta;GA;30303;USA - |item1.X-ABADR:ca - |item2.ADR;type=HOME:;;1234 Laurel Street;Atlanta;GA;30303;USA - |item2.X-ABADR:us - |BDAY:1980-06-22 - |END:VCARD""".stripMargin - - val list = VCardParser.parse(appleIOS9JohnAppleseedVCard3) - list must beLike { - case Left(l) => { - import VCardParser._ - l must_== - List( - VCardEntry(VCardKey("BEGIN", Nil), List("VCARD")), - VCardEntry(VCardKey("VERSION", Nil), List("3.0")), - VCardEntry(VCardKey("PRODID", Nil),List("-//Apple Inc.//iPhone OS 9.3//EN")), - VCardEntry(VCardKey("N", Nil), List("Appleseed", "John", "", "", "")), - VCardEntry(VCardKey("FN", Nil), List(" John Appleseed")), - VCardEntry(VCardKey("EMAIL", List(("type","INTERNET"), ("type","WORK"), ("type","pref"))),List("John-Appleseed@mac.com")), - VCardEntry(VCardKey("TEL", List(("type", "CELL"), ("type", "VOICE"), ("type", "pref"))), List("888-555-5512")), - VCardEntry(VCardKey("TEL", List(("type", "HOME"), ("type", "VOICE"))), List("888-555-1212")), - VCardEntry(VCardKey("ADR", List(("type","WORK"), ("type","pref"))),List("", "", "3494 Kuhl Avenue", "Atlanta", "GA", "30303", "USA")), - VCardEntry(VCardKey("X-ABADR",Nil),List("ca")), - VCardEntry(VCardKey("ADR", List(("type","HOME"))),List("", "", "1234 Laurel Street", "Atlanta", "GA", "30303", "USA")), - VCardEntry(VCardKey("X-ABADR",Nil),List("us")), - VCardEntry(VCardKey("BDAY",Nil),List("1980-06-22")), - VCardEntry(VCardKey("END", Nil), List("VCARD"))) - } - } - - } - - - } - -} diff --git a/core/util/src/test/scala-2.13/net/liftweb/util/XmlParserSpec.scala b/core/util/src/test/scala-2.13/net/liftweb/util/XmlParserSpec.scala deleted file mode 100644 index 8f7d21865d..0000000000 --- a/core/util/src/test/scala-2.13/net/liftweb/util/XmlParserSpec.scala +++ /dev/null @@ -1,143 +0,0 @@ -/* - * Copyright 2007-2026 Lift Committers and Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package net.liftweb -package util - -import java.io.ByteArrayInputStream - -import scala.xml.{ EntityRef, Text, Unparsed } - -import org.specs2.matcher.XmlMatchers -import org.specs2.mutable.Specification - - -/** - * Systems under specification for XmlParser, specifically PCDataMarkupParser. - */ -class XmlParserSpec extends Specification with XmlMatchers { - "Xml Parser Specification".title - - "Multiple attributes with same name, but different namespace" should { - "parse correctly" >> { - val actual = - - - - - val expected = - - - - - val bis = new ByteArrayInputStream(actual.toString.getBytes("UTF-8")) - val parsed = PCDataXmlParser(bis).openOrThrowException("Test") - parsed must ==/(expected) - } - - } - - "XML can contain PCData" in { - val data = { - PCData("Hello Yak") - } - - val str = AltXML.toXML(data, false, true) - - str.indexOf(" -1 - } - - "XML can contain Unparsed" in { - val data = { - Unparsed("Hello & goodbye > - - val str = AltXML.toXML(data, false, true) - - str.indexOf("Hello & goodbye > -1 - } - - "XML cannot contain Control characters" in { - val data = - - { - '\u0085' - }{ - Text("hello \u0000 \u0085 \u0080") - }{ - "hello \u0000 \u0003 \u0085 \u0080" - }{ - '\u0003' - } - - - val str = AltXML.toXML(data, false, true) - - def cntIllegal(in: Char): Int = in match { - case '\u0085' => 1 - case c if (c >= '\u007f' && c <= '\u0095') => 1 - case '\n' => 0 - case '\r' => 0 - case '\t' => 0 - case c if c < ' ' => 1 - case _ => 0 - } - - str.toList.foldLeft(0)((a, b) => a + cntIllegal(b)) must_== 0 - } - - "AltXML" should { - "render empty elements with self-close syntax" in { - AltXML.toXML(
        , false, true) must contain("/>") - } - - "render non-empty elements with open and close tags" in { - val result = AltXML.toXML(
        x
        , false, true) - result must contain("
        ") - result must contain("
        ") - } - - "preserve EntityRef nodes when convertAmp is false" in { - val data =

        {EntityRef("nbsp")}

        - val result = AltXML.toXML(data, false, false) - result must contain(" ") - } - - "convert high-codepoint EntityRef to character when convertAmp is true" in { - // nbsp = 160, which is >= 128, so it converts to the actual char - val data =

        {EntityRef("nbsp")}

        - val result = AltXML.toXML(data, false, true) - result must contain("\u00A0") - } - - "preserve low-codepoint EntityRef as entity when convertAmp is true" in { - // amp = 38, which is < 128, so it stays as & - val data =

        {EntityRef("amp")}

        - val result = AltXML.toXML(data, false, true) - result must contain("&") - } - - "apply legacy IE compatibility mode to br tags" in { - // legacy mode: br gets />, no space - val withLegacy = AltXML.toXML(
        , false, true, legacyIeCompatibilityMode = true) - withLegacy must contain("/>") - // without legacy mode: br is in inlineTags, gets " />" - val withoutLegacy = AltXML.toXML(
        , false, true, legacyIeCompatibilityMode = false) - withoutLegacy must contain(" />") - } - } - -} diff --git a/core/util/src/test/scala-3/net/liftweb/util/BasicTypesHelpersSpec.scala b/core/util/src/test/scala/net/liftweb/util/BasicTypesHelpersSpec.scala similarity index 100% rename from core/util/src/test/scala-3/net/liftweb/util/BasicTypesHelpersSpec.scala rename to core/util/src/test/scala/net/liftweb/util/BasicTypesHelpersSpec.scala diff --git a/core/util/src/test/scala-3/net/liftweb/util/BundleBuilderSpec.scala b/core/util/src/test/scala/net/liftweb/util/BundleBuilderSpec.scala similarity index 100% rename from core/util/src/test/scala-3/net/liftweb/util/BundleBuilderSpec.scala rename to core/util/src/test/scala/net/liftweb/util/BundleBuilderSpec.scala diff --git a/core/util/src/test/scala-3/net/liftweb/util/CanResolveAsyncSpec.scala b/core/util/src/test/scala/net/liftweb/util/CanResolveAsyncSpec.scala similarity index 100% rename from core/util/src/test/scala-3/net/liftweb/util/CanResolveAsyncSpec.scala rename to core/util/src/test/scala/net/liftweb/util/CanResolveAsyncSpec.scala diff --git a/core/util/src/test/scala-3/net/liftweb/util/ClassHelpersSpec.scala b/core/util/src/test/scala/net/liftweb/util/ClassHelpersSpec.scala similarity index 100% rename from core/util/src/test/scala-3/net/liftweb/util/ClassHelpersSpec.scala rename to core/util/src/test/scala/net/liftweb/util/ClassHelpersSpec.scala diff --git a/core/util/src/test/scala-3/net/liftweb/util/CombParserHelpersSpec.scala b/core/util/src/test/scala/net/liftweb/util/CombParserHelpersSpec.scala similarity index 100% rename from core/util/src/test/scala-3/net/liftweb/util/CombParserHelpersSpec.scala rename to core/util/src/test/scala/net/liftweb/util/CombParserHelpersSpec.scala diff --git a/core/util/src/test/scala-3/net/liftweb/util/ConnectionIdentifierSpec.scala b/core/util/src/test/scala/net/liftweb/util/ConnectionIdentifierSpec.scala similarity index 100% rename from core/util/src/test/scala-3/net/liftweb/util/ConnectionIdentifierSpec.scala rename to core/util/src/test/scala/net/liftweb/util/ConnectionIdentifierSpec.scala diff --git a/core/util/src/test/scala-3/net/liftweb/util/ControlHelpersSpec.scala b/core/util/src/test/scala/net/liftweb/util/ControlHelpersSpec.scala similarity index 100% rename from core/util/src/test/scala-3/net/liftweb/util/ControlHelpersSpec.scala rename to core/util/src/test/scala/net/liftweb/util/ControlHelpersSpec.scala diff --git a/core/util/src/test/scala-3/net/liftweb/util/CssHelpersSpec.scala b/core/util/src/test/scala/net/liftweb/util/CssHelpersSpec.scala similarity index 100% rename from core/util/src/test/scala-3/net/liftweb/util/CssHelpersSpec.scala rename to core/util/src/test/scala/net/liftweb/util/CssHelpersSpec.scala diff --git a/core/util/src/test/scala-3/net/liftweb/util/CssSelectorSpec.scala b/core/util/src/test/scala/net/liftweb/util/CssSelectorSpec.scala similarity index 100% rename from core/util/src/test/scala-3/net/liftweb/util/CssSelectorSpec.scala rename to core/util/src/test/scala/net/liftweb/util/CssSelectorSpec.scala diff --git a/core/util/src/test/scala-3/net/liftweb/util/CurrencyZoneSpec.scala b/core/util/src/test/scala/net/liftweb/util/CurrencyZoneSpec.scala similarity index 100% rename from core/util/src/test/scala-3/net/liftweb/util/CurrencyZoneSpec.scala rename to core/util/src/test/scala/net/liftweb/util/CurrencyZoneSpec.scala diff --git a/core/util/src/test/scala-3/net/liftweb/util/Html5ParserSpec.scala b/core/util/src/test/scala/net/liftweb/util/Html5ParserSpec.scala similarity index 100% rename from core/util/src/test/scala-3/net/liftweb/util/Html5ParserSpec.scala rename to core/util/src/test/scala/net/liftweb/util/Html5ParserSpec.scala diff --git a/core/util/src/test/scala-3/net/liftweb/util/HtmlHelpersSpec.scala b/core/util/src/test/scala/net/liftweb/util/HtmlHelpersSpec.scala similarity index 100% rename from core/util/src/test/scala-3/net/liftweb/util/HtmlHelpersSpec.scala rename to core/util/src/test/scala/net/liftweb/util/HtmlHelpersSpec.scala diff --git a/core/util/src/test/scala-3/net/liftweb/util/HtmlRoundTripSpec.scala b/core/util/src/test/scala/net/liftweb/util/HtmlRoundTripSpec.scala similarity index 100% rename from core/util/src/test/scala-3/net/liftweb/util/HtmlRoundTripSpec.scala rename to core/util/src/test/scala/net/liftweb/util/HtmlRoundTripSpec.scala diff --git a/core/util/src/test/scala-3/net/liftweb/util/HttpHelpersSpec.scala b/core/util/src/test/scala/net/liftweb/util/HttpHelpersSpec.scala similarity index 100% rename from core/util/src/test/scala-3/net/liftweb/util/HttpHelpersSpec.scala rename to core/util/src/test/scala/net/liftweb/util/HttpHelpersSpec.scala diff --git a/core/util/src/test/scala-3/net/liftweb/util/IoHelpersSpec.scala b/core/util/src/test/scala/net/liftweb/util/IoHelpersSpec.scala similarity index 100% rename from core/util/src/test/scala-3/net/liftweb/util/IoHelpersSpec.scala rename to core/util/src/test/scala/net/liftweb/util/IoHelpersSpec.scala diff --git a/core/util/src/test/scala-3/net/liftweb/util/JsonCommandSpec.scala b/core/util/src/test/scala/net/liftweb/util/JsonCommandSpec.scala similarity index 100% rename from core/util/src/test/scala-3/net/liftweb/util/JsonCommandSpec.scala rename to core/util/src/test/scala/net/liftweb/util/JsonCommandSpec.scala diff --git a/core/util/src/test/scala-3/net/liftweb/util/ListHelpersSpec.scala b/core/util/src/test/scala/net/liftweb/util/ListHelpersSpec.scala similarity index 100% rename from core/util/src/test/scala-3/net/liftweb/util/ListHelpersSpec.scala rename to core/util/src/test/scala/net/liftweb/util/ListHelpersSpec.scala diff --git a/core/util/src/test/scala-3/net/liftweb/util/MarkdownParserSpec.scala b/core/util/src/test/scala/net/liftweb/util/MarkdownParserSpec.scala similarity index 100% rename from core/util/src/test/scala-3/net/liftweb/util/MarkdownParserSpec.scala rename to core/util/src/test/scala/net/liftweb/util/MarkdownParserSpec.scala diff --git a/core/util/src/test/scala-3/net/liftweb/util/PCDataXmlParserSpec.scala b/core/util/src/test/scala/net/liftweb/util/PCDataXmlParserSpec.scala similarity index 100% rename from core/util/src/test/scala-3/net/liftweb/util/PCDataXmlParserSpec.scala rename to core/util/src/test/scala/net/liftweb/util/PCDataXmlParserSpec.scala diff --git a/core/util/src/test/scala-3/net/liftweb/util/PropsSpec.scala b/core/util/src/test/scala/net/liftweb/util/PropsSpec.scala similarity index 100% rename from core/util/src/test/scala-3/net/liftweb/util/PropsSpec.scala rename to core/util/src/test/scala/net/liftweb/util/PropsSpec.scala diff --git a/core/util/src/test/scala-3/net/liftweb/util/ScheduleSpec.scala b/core/util/src/test/scala/net/liftweb/util/ScheduleSpec.scala similarity index 100% rename from core/util/src/test/scala-3/net/liftweb/util/ScheduleSpec.scala rename to core/util/src/test/scala/net/liftweb/util/ScheduleSpec.scala diff --git a/core/util/src/test/scala-3/net/liftweb/util/SecurityHelpersSpec.scala b/core/util/src/test/scala/net/liftweb/util/SecurityHelpersSpec.scala similarity index 100% rename from core/util/src/test/scala-3/net/liftweb/util/SecurityHelpersSpec.scala rename to core/util/src/test/scala/net/liftweb/util/SecurityHelpersSpec.scala diff --git a/core/util/src/test/scala-3/net/liftweb/util/SoftReferenceCacheSpec.scala b/core/util/src/test/scala/net/liftweb/util/SoftReferenceCacheSpec.scala similarity index 100% rename from core/util/src/test/scala-3/net/liftweb/util/SoftReferenceCacheSpec.scala rename to core/util/src/test/scala/net/liftweb/util/SoftReferenceCacheSpec.scala diff --git a/core/util/src/test/scala-3/net/liftweb/util/StringHelpersSpec.scala b/core/util/src/test/scala/net/liftweb/util/StringHelpersSpec.scala similarity index 100% rename from core/util/src/test/scala-3/net/liftweb/util/StringHelpersSpec.scala rename to core/util/src/test/scala/net/liftweb/util/StringHelpersSpec.scala diff --git a/core/util/src/test/scala-3/net/liftweb/util/TimeHelpersSpec.scala b/core/util/src/test/scala/net/liftweb/util/TimeHelpersSpec.scala similarity index 100% rename from core/util/src/test/scala-3/net/liftweb/util/TimeHelpersSpec.scala rename to core/util/src/test/scala/net/liftweb/util/TimeHelpersSpec.scala diff --git a/core/util/src/test/scala-3/net/liftweb/util/ToHeadSpec.scala b/core/util/src/test/scala/net/liftweb/util/ToHeadSpec.scala similarity index 100% rename from core/util/src/test/scala-3/net/liftweb/util/ToHeadSpec.scala rename to core/util/src/test/scala/net/liftweb/util/ToHeadSpec.scala diff --git a/core/util/src/test/scala-3/net/liftweb/util/VCardParserSpec.scala b/core/util/src/test/scala/net/liftweb/util/VCardParserSpec.scala similarity index 100% rename from core/util/src/test/scala-3/net/liftweb/util/VCardParserSpec.scala rename to core/util/src/test/scala/net/liftweb/util/VCardParserSpec.scala diff --git a/core/util/src/test/scala-3/net/liftweb/util/XmlParserSpec.scala b/core/util/src/test/scala/net/liftweb/util/XmlParserSpec.scala similarity index 100% rename from core/util/src/test/scala-3/net/liftweb/util/XmlParserSpec.scala rename to core/util/src/test/scala/net/liftweb/util/XmlParserSpec.scala diff --git a/project/Dependencies.scala b/project/Dependencies.scala index 5e9c272d7a..553b842780 100644 --- a/project/Dependencies.scala +++ b/project/Dependencies.scala @@ -42,17 +42,12 @@ object Dependencies { lazy val scalaz7_core = "org.scalaz" %% "scalaz-core" % "7.3.8" lazy val slf4j_api = "org.slf4j" % "slf4j-api" % slf4jVersion lazy val scala_xml = "org.scala-lang.modules" %% "scala-xml" % "2.4.0" - lazy val scala_parallel_collections = "org.scala-lang.modules" %% "scala-parallel-collections" % "1.2.0" lazy val rhino = "org.mozilla" % "rhino" % "1.9.0" lazy val scala_parser = "org.scala-lang.modules" %% "scala-parser-combinators" % "2.4.0" lazy val xerces = "xerces" % "xercesImpl" % "2.12.2" lazy val scala_compiler: ModuleMap = (version: String) => { - if (version.startsWith("2")) { - "org.scala-lang" % "scala-compiler" % version - } else { - "org.scala-lang" % "scala3-compiler_3" % version - } + "org.scala-lang" % "scala3-compiler_3" % version } // Aliases @@ -79,45 +74,21 @@ object Dependencies { lazy val derby = "org.apache.derby" % "derby" % "10.7.1.1" % Test lazy val h2database = "com.h2database" % "h2" % "1.2.147" % Test - // Specs2 versions differ between Scala 2 and Scala 3 - def specs2Version(scalaVersion: String): String = { - CrossVersion.partialVersion(scalaVersion) match { - case Some((2, 13)) => "4.21.0" - case Some((3, _)) => "5.6.4" - case _ => "4.21.0" - } - } + lazy val specs2Version = "5.6.4" - lazy val specs2: ModuleMap = (version: String) => "org.specs2" %% "specs2-core" % specs2Version(version) % Test - lazy val scalacheck: ModuleMap = (version: String) => "org.specs2" %% "specs2-scalacheck" % specs2Version(version) % Test - lazy val specs2Prov: ModuleMap = (version: String) => "org.specs2" %% "specs2-core" % specs2Version(version) % Provided - lazy val specs2Matchers: ModuleMap = (version: String) => "org.specs2" %% "specs2-matcher-extra" % specs2Version(version) % Test - lazy val specs2MatchersProv: ModuleMap = (version: String) => "org.specs2" %% "specs2-matcher-extra" % specs2Version(version) % Provided - def specs2XmlDeps(version: String): Seq[ModuleID] = - CrossVersion.partialVersion(version) match { - case Some((3, _)) => - Seq("org.specs2" %% "specs2-xml" % specs2Version(version) % Test) - case _ => - Seq.empty - } - - lazy val specs2Mock: ModuleMap = (version: String) => { - CrossVersion.partialVersion(version) match { - case Some((2, 13)) => "org.specs2" %% "specs2-mock" % specs2Version(version) % Test - case Some((3, _)) => "org.scalatestplus" %% "mockito-5-18" % "3.2.19.0" % Test - case _ => "org.specs2" %% "specs2-mock" % specs2Version(version) % Test - } - } + lazy val specs2: ModuleMap = (_: String) => "org.specs2" %% "specs2-core" % specs2Version % Test + lazy val scalacheck: ModuleMap = (_: String) => "org.specs2" %% "specs2-scalacheck" % specs2Version % Test + lazy val specs2Prov: ModuleMap = (_: String) => "org.specs2" %% "specs2-core" % specs2Version % Provided + lazy val specs2Matchers: ModuleMap = (_: String) => "org.specs2" %% "specs2-matcher-extra" % specs2Version % Test + lazy val specs2MatchersProv: ModuleMap = (_: String) => "org.specs2" %% "specs2-matcher-extra" % specs2Version % Provided + lazy val specs2Xml = "org.specs2" %% "specs2-xml" % specs2Version % Test + lazy val specs2Mock = "org.scalatestplus" %% "mockito-5-18" % "3.2.19.0" % Test lazy val scalactic = "org.scalactic" %% "scalactic" % "3.2.19" % Test lazy val scalatest = "org.scalatest" %% "scalatest" % "3.2.19" % Test lazy val scalatest_junit = "org.scalatestplus" %% "junit-4-12" % "3.1.2.0" % Test - lazy val mockito_scalatest: ModuleMap = (version: String) => { - CrossVersion.partialVersion(version) match { - case Some((2, 13)) => "org.mockito" %% "mockito-scala-scalatest" % "1.14.3" % Test - case Some((3, _)) => "org.scalatestplus" %% "mockito-5-18" % "3.2.19.0" % Test - case _ => "org.mockito" %% "mockito-scala-scalatest" % "1.14.3" % Test - } + lazy val mockito_scalatest: ModuleMap = (_: String) => { + "org.scalatestplus" %% "mockito-5-18" % "3.2.19.0" % Test } lazy val scalamock = "org.scalamock" %% "scalamock" % "7.4.1" % Test diff --git a/web/testkit/src/test/scala-2.13/net/liftweb/http/testing/MockHttpRequestSpec.scala b/web/testkit/src/test/scala-2.13/net/liftweb/http/testing/MockHttpRequestSpec.scala deleted file mode 100644 index 67f4406496..0000000000 --- a/web/testkit/src/test/scala-2.13/net/liftweb/http/testing/MockHttpRequestSpec.scala +++ /dev/null @@ -1,143 +0,0 @@ -/* - * Copyright 2011-2026 Lift Committers and Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package net.liftweb -package mocks - -import org.specs2.mutable.Specification - -import org.json4s.JsonDSL._ - -/** - * System under specification for MockHttpRequest. - */ -class MockHttpRequestSpec extends Specification { - "MockHttpRequest Specification".title - - val IF_MODIFIED_HEADER = "If-Modified-Since" - val TEST_URL = "https://foo.com/test/this/page?a=b&b=a&a=c" - val TEST_URL_BLANK_PARAMETER = "https://foo.com/test/this/page?a=b&b=a&c=&d" - val TEST_URL_BLANK_PARAMETER_SERIALIZED = "https://foo.com/test/this/page?a=b&b=a&c=&d=" - - "MockHttpRequest" should { - - "properly deconstruct from a URL" in { - val testRequest = new MockHttpServletRequest(TEST_URL, "/test") - - testRequest.getScheme must_== "https" - testRequest.isSecure must_== true - testRequest.getServerName must_== "foo.com" - testRequest.getContextPath must_== "/test" - testRequest.getRequestURI must_== "/test/this/page" - testRequest.getRequestURL.toString must_== TEST_URL - testRequest.getQueryString must_== "a=b&b=a&a=c" - testRequest.getParameterValues("a").toList must_== List("b","c") - testRequest.getParameter("b") must_== "a" - } - - "parse parameters with empty values" in { - val testRequest = new MockHttpServletRequest(TEST_URL_BLANK_PARAMETER, "/test") - - testRequest.getScheme must_== "https" - testRequest.isSecure must_== true - testRequest.getServerName must_== "foo.com" - testRequest.getContextPath must_== "/test" - testRequest.getRequestURI must_== "/test/this/page" - testRequest.getRequestURL.toString must_== TEST_URL_BLANK_PARAMETER_SERIALIZED - testRequest.getQueryString must_== "a=b&b=a&c=&d=" - testRequest.getParameter("c") must_== "" - testRequest.getParameter("d") must_== "" - } - - "correctly add and parse a date header" in { - val testRequest = new MockHttpServletRequest(TEST_URL, "/test") - - val epoch = 241000 // (milliseconds not included in RFC 1123) - - testRequest.setDateHeader(IF_MODIFIED_HEADER, epoch) - - testRequest.getDateHeader(IF_MODIFIED_HEADER) must_== epoch - } - - "throw an IllegalArgumentException for an invalid date header" in { - val testRequest = new MockHttpServletRequest(TEST_URL, "/test") - - testRequest.headers += IF_MODIFIED_HEADER -> List("this is not a valid date") - - testRequest.getDateHeader(IF_MODIFIED_HEADER) must throwA[IllegalArgumentException] - } - - "throw an IllegalArgumentException for an invalid context path" in { - (new MockHttpServletRequest(TEST_URL, "foo")) must throwA[IllegalArgumentException] - (new MockHttpServletRequest(TEST_URL, "/foo/")) must throwA[IllegalArgumentException] - } - - "throw an IllegalArgumentException for an invalid query string" in { - val testRequest = new MockHttpServletRequest(TEST_URL, "/test") - - (testRequest.queryString ="this=a&&that=b") must throwA[IllegalArgumentException] - } - - - "properly set a default content type for JSON" in { - val testRequest = new MockHttpServletRequest(TEST_URL, "/test") - - testRequest.body_=("name" -> "joe") - - testRequest.contentType must_== "application/json" - } - - "properly set a user-specificed content type for JSON" in { - val testRequest = new MockHttpServletRequest(TEST_URL, "/test") - - testRequest.body_=(("name" -> "joe"), "text/json") - - testRequest.contentType must_== "text/json" - } - - "properly set a default content type for XML" in { - val testRequest = new MockHttpServletRequest(TEST_URL, "/test") - - testRequest.body_=() - - testRequest.contentType must_== "text/xml" - } - - "properly set a user-specificed content type for XML" in { - val testRequest = new MockHttpServletRequest(TEST_URL, "/test") - - testRequest.body_=(, "application/xml") - - testRequest.contentType must_== "application/xml" - } - - "properly set a default content type for a String" in { - val testRequest = new MockHttpServletRequest(TEST_URL, "/test") - - testRequest.body_=("test") - - testRequest.contentType must_== "text/plain" - } - - "properly set a user-specificed content type for a String" in { - val testRequest = new MockHttpServletRequest(TEST_URL, "/test") - - testRequest.body_=("test", "text/csv") - - testRequest.contentType must_== "text/csv" - } - - } -} diff --git a/web/testkit/src/test/scala-3/net/liftweb/http/testing/MockHttpRequestSpec.scala b/web/testkit/src/test/scala/net/liftweb/http/testing/MockHttpRequestSpec.scala similarity index 100% rename from web/testkit/src/test/scala-3/net/liftweb/http/testing/MockHttpRequestSpec.scala rename to web/testkit/src/test/scala/net/liftweb/http/testing/MockHttpRequestSpec.scala diff --git a/web/webkit/src/main/scala/net/liftweb/http/LiftSession.scala b/web/webkit/src/main/scala/net/liftweb/http/LiftSession.scala index 33dbf18c74..3e85a4bbbb 100644 --- a/web/webkit/src/main/scala/net/liftweb/http/LiftSession.scala +++ b/web/webkit/src/main/scala/net/liftweb/http/LiftSession.scala @@ -2858,8 +2858,8 @@ class LiftSession(private[http] val _contextPath: String, val underlyingId: Stri LAScheduler.execute(() => { executeInScope(currentReq, renderVersion)( for { - JString(guid) <- in \ "guid" - JString(name) <- in \ "name" + guid <- (in \ "guid") match { case JString(g) => Some(g); case _ => None } + name <- (in \ "name") match { case JString(n) => Some(n); case _ => None } func <- map.get(name) payload = in \ "payload" reified <- if (func.manifest == jvmanifest) Some(payload) else { diff --git a/web/webkit/src/main/scala_3/net/liftweb/http/NamedCometDispatcher.scala b/web/webkit/src/main/scala/net/liftweb/http/NamedCometDispatcher.scala similarity index 100% rename from web/webkit/src/main/scala_3/net/liftweb/http/NamedCometDispatcher.scala rename to web/webkit/src/main/scala/net/liftweb/http/NamedCometDispatcher.scala diff --git a/web/webkit/src/main/scala_2.11/net/liftweb/http/FutureWithSession.scala b/web/webkit/src/main/scala_2.11/net/liftweb/http/FutureWithSession.scala deleted file mode 100644 index dfa9e6324a..0000000000 --- a/web/webkit/src/main/scala_2.11/net/liftweb/http/FutureWithSession.scala +++ /dev/null @@ -1,128 +0,0 @@ -package net.liftweb.http - -import net.liftweb.common.Full - -import scala.concurrent.duration.Duration -import scala.concurrent.{CanAwait, ExecutionContext, Future} -import scala.util.Try - -/** - * Decorates `Future` instance to allow access to session and request resources. Should be created with - * `FutureWithSession.withCurrentSession` that takes the current Lift request and session and make it available - * to all transformation methods and initial `Future` execution body. Each transformation method returns - * `FutureWithSession`, thus, they can be all chained together. - * - * It's important to bear in mind that each chained method requires current thread's `LiftSession` to be available. - * `FutureWithSession` does _not_ propagate initial session or request to all chained methods. - * - * @see FutureWithSession.withCurrentSession - * - * @param delegate original `Future` instance that will be enriched with session and request access - */ -private[http] class FutureWithSession[T](private[this] val delegate: Future[T]) extends Future[T] { - - import FutureWithSession.withCurrentSession - - override def isCompleted: Boolean = delegate.isCompleted - - override def value: Option[Try[T]] = delegate.value - - override def result(atMost: Duration)(implicit permit: CanAwait): T = delegate.result(atMost) - - override def ready(atMost: Duration)(implicit permit: CanAwait) = { - delegate.ready(atMost) - this - } - - override def onComplete[U](f: (Try[T]) => U)(implicit executor:ExecutionContext): Unit = { - val sessionFn = withCurrentSession(f) - delegate.onComplete(sessionFn) - } - - override def map[S](f: T => S)(implicit executor: ExecutionContext): FutureWithSession[S] = { - val sessionFn = withCurrentSession(f) - new FutureWithSession(delegate.map(sessionFn)) - } - - override def flatMap[S](f: T => Future[S])(implicit executor: ExecutionContext): FutureWithSession[S] = { - val sessionFn = withCurrentSession(f) - new FutureWithSession(delegate.flatMap(sessionFn)) - } - - override def andThen[U](pf: PartialFunction[Try[T], U])(implicit executor: ExecutionContext): FutureWithSession[T] = { - val sessionFn = withCurrentSession(pf) - new FutureWithSession(delegate.andThen { - case t => sessionFn(t) - }) - } - - override def failed: FutureWithSession[Throwable] = { - new FutureWithSession(delegate.failed) - } - - override def fallbackTo[U >: T](that: Future[U]): FutureWithSession[U] = { - new FutureWithSession[U](delegate.fallbackTo(that)) - } - - override def recover[U >: T](pf: PartialFunction[Throwable, U])(implicit executor: ExecutionContext): FutureWithSession[U] = { - val sessionFn = withCurrentSession(pf) - new FutureWithSession(delegate.recover { - case t => sessionFn(t) - }) - } - - override def recoverWith[U >: T](pf: PartialFunction[Throwable, Future[U]])(implicit executor: ExecutionContext): FutureWithSession[U] = { - val sessionFn = withCurrentSession(pf) - new FutureWithSession(delegate.recoverWith { - case t => sessionFn(t) - }) - } - - override def transform[S](s: T => S, f: Throwable => Throwable)(implicit executor: ExecutionContext): Future[S] = { - val sessionSuccessFn = withCurrentSession(s) - val sessionFailureFn = withCurrentSession(f) - - new FutureWithSession(delegate.transform(s => sessionSuccessFn(s), f => sessionFailureFn(f))) - } - - override def zip[U](that: Future[U]): Future[(T, U)] = { - new FutureWithSession(delegate.zip(that)) - } -} - -object FutureWithSession { - - /** - * Creates `Future` instance aware of current request and session. Each `Future` returned by chained - * transformation method (e.g. `map`, `flatMap`) will be also request/session-aware. However, it's - * important to bear in mind that initial request and session are not propagated to chained methods. - * It's required that current execution thread for chained method has its own request/session available - * if reading/writing some data to it as a part of chained method execution. - */ - def withCurrentSession[T](task: => T)(implicit executionContext: ExecutionContext): Future[T] = { - FutureWithSession(task) - } - - private def apply[T](task: => T)(implicit executionContext: ExecutionContext): FutureWithSession[T] = { - S.session match { - case Full(_) => - val sessionFn = withCurrentSession(() => task) - new FutureWithSession(Future[T](sessionFn())) - - case _ => - new FutureWithSession(Future.failed[T]( - new IllegalStateException("LiftSession not available in this thread context") - )) - } - } - - private def withCurrentSession[T](task: () => T): () => T = { - val session = S.session openOrThrowException "LiftSession not available in this thread context" - session.buildDeferredFunction(task) - } - - private def withCurrentSession[A,T](task: (A)=>T): (A)=>T = { - val session = S.session openOrThrowException "LiftSession not available in this thread context" - session.buildDeferredFunction(task) - } -} diff --git a/web/webkit/src/main/scala_2.11/net/liftweb/http/NamedCometDispatcher.scala b/web/webkit/src/main/scala_2.11/net/liftweb/http/NamedCometDispatcher.scala deleted file mode 100644 index 0f162854d7..0000000000 --- a/web/webkit/src/main/scala_2.11/net/liftweb/http/NamedCometDispatcher.scala +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright 2007-2026 Lift Committers and Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package net.liftweb -package http - -import common.{Box, Full, Loggable} -import actor.LiftActor - -/** - * This class keeps a list of comet actors that need to update the UI - */ -class NamedCometDispatcher(name: Box[String]) extends LiftActor with Loggable { - - logger.debug("DispatcherActor got name: %s".format(name)) - - private var cometActorsToUpdate: Vector[BaseCometActor]= Vector() - - override def messageHandler = { - /** - * if we do not have this actor in the list, add it (register it) - */ - case registerCometActor(actor, Full(name)) => { - if(cometActorsToUpdate.contains(actor) == false){ - logger.debug("We are adding actor: %s to the list".format(actor)) - cometActorsToUpdate= cometActorsToUpdate :+ actor - } else { - logger.debug("The list so far is %s".format(cometActorsToUpdate)) - } - } - case unregisterCometActor(actor) => { - logger.debug("before %s".format(cometActorsToUpdate)) - cometActorsToUpdate= cometActorsToUpdate.filterNot(_ == actor) - logger.debug("after %s".format(cometActorsToUpdate)) - } - - //Catch the dummy message we send on comet creation - case CometName(name) => - - /** - * Go through the list of actors and send them a message - */ - case msg => { - cometActorsToUpdate.par.foreach{ x => { - x ! msg - logger.debug("We will update this comet actor: %s showing name: %s".format(x, name)) - } - } - } - } -} - - -/** - * These are the message we pass around to - * register each named comet actor with a dispatcher that - * only updates the specific version it monitors - */ -case class registerCometActor(actor: BaseCometActor, name: Box[String]) -case class unregisterCometActor(actor: BaseCometActor) -case class CometName(name: String) diff --git a/web/webkit/src/main/scala_2.12/net/liftweb/http/FutureWithSession.scala b/web/webkit/src/main/scala_2.12/net/liftweb/http/FutureWithSession.scala deleted file mode 100644 index 7477d7083e..0000000000 --- a/web/webkit/src/main/scala_2.12/net/liftweb/http/FutureWithSession.scala +++ /dev/null @@ -1,138 +0,0 @@ -package net.liftweb.http - -import net.liftweb.common.Full - -import scala.concurrent.duration.Duration -import scala.concurrent.{CanAwait, ExecutionContext, Future} -import scala.util.Try - -/** - * Decorates `Future` instance to allow access to session and request resources. Should be created with - * `FutureWithSession.withCurrentSession` that takes the current Lift request and session and make it available - * to all transformation methods and initial `Future` execution body. Each transformation method returns - * `FutureWithSession`, thus, they can be all chained together. - * - * It's important to bear in mind that each chained method requires current thread's `LiftSession` to be available. - * `FutureWithSession` does _not_ propagate initial session or request to all chained methods. - * - * @see FutureWithSession.withCurrentSession - * - * @param delegate original `Future` instance that will be enriched with session and request access - */ -private[http] class FutureWithSession[T](private[this] val delegate: Future[T]) extends Future[T] { - - import FutureWithSession.withCurrentSession - - override def isCompleted: Boolean = delegate.isCompleted - - override def value: Option[Try[T]] = delegate.value - - override def result(atMost: Duration)(implicit permit: CanAwait): T = delegate.result(atMost) - - override def ready(atMost: Duration)(implicit permit: CanAwait) = { - delegate.ready(atMost) - this - } - - override def onComplete[U](f: (Try[T]) => U)(implicit executor:ExecutionContext): Unit = { - val sessionFn = withCurrentSession(f) - delegate.onComplete(sessionFn) - } - - override def map[S](f: T => S)(implicit executor: ExecutionContext): FutureWithSession[S] = { - val sessionFn = withCurrentSession(f) - new FutureWithSession(delegate.map(sessionFn)) - } - - override def flatMap[S](f: T => Future[S])(implicit executor: ExecutionContext): FutureWithSession[S] = { - val sessionFn = withCurrentSession(f) - new FutureWithSession(delegate.flatMap(sessionFn)) - } - - override def andThen[U](pf: PartialFunction[Try[T], U])(implicit executor: ExecutionContext): FutureWithSession[T] = { - val sessionFn = withCurrentSession(pf) - new FutureWithSession(delegate.andThen { - case t => sessionFn(t) - }) - } - - override def failed: FutureWithSession[Throwable] = { - new FutureWithSession(delegate.failed) - } - - override def fallbackTo[U >: T](that: Future[U]): FutureWithSession[U] = { - new FutureWithSession[U](delegate.fallbackTo(that)) - } - - override def recover[U >: T](pf: PartialFunction[Throwable, U])(implicit executor: ExecutionContext): FutureWithSession[U] = { - val sessionFn = withCurrentSession(pf) - new FutureWithSession(delegate.recover { - case t => sessionFn(t) - }) - } - - override def recoverWith[U >: T](pf: PartialFunction[Throwable, Future[U]])(implicit executor: ExecutionContext): FutureWithSession[U] = { - val sessionFn = withCurrentSession(pf) - new FutureWithSession(delegate.recoverWith { - case t => sessionFn(t) - }) - } - - override def transform[S](s: T => S, f: Throwable => Throwable)(implicit executor: ExecutionContext): Future[S] = { - val sessionSuccessFn = withCurrentSession(s) - val sessionFailureFn = withCurrentSession(f) - - new FutureWithSession(delegate.transform(s => sessionSuccessFn(s), f => sessionFailureFn(f))) - } - - def transform[S](f: Try[T] => Try[S])(implicit executor: ExecutionContext): Future[S] = { - val sessionFn = withCurrentSession(f) - new FutureWithSession(delegate.transform(sessionFn)) - } - - def transformWith[S](f: Try[T] => Future[S])(implicit executor: ExecutionContext): Future[S] = { - val sessionFn = withCurrentSession(f) - new FutureWithSession(delegate.transformWith(sessionFn)) - } - - override def zip[U](that: Future[U]): Future[(T, U)] = { - new FutureWithSession(delegate.zip(that)) - } -} - -object FutureWithSession { - - /** - * Creates `Future` instance aware of current request and session. Each `Future` returned by chained - * transformation method (e.g. `map`, `flatMap`) will be also request/session-aware. However, it's - * important to bear in mind that initial request and session are not propagated to chained methods. - * It's required that current execution thread for chained method has its own request/session available - * if reading/writing some data to it as a part of chained method execution. - */ - def withCurrentSession[T](task: => T)(implicit executionContext: ExecutionContext): Future[T] = { - FutureWithSession(task) - } - - private def apply[T](task: => T)(implicit executionContext: ExecutionContext): FutureWithSession[T] = { - S.session match { - case Full(_) => - val sessionFn = withCurrentSession(() => task) - new FutureWithSession(Future[T](sessionFn())) - - case _ => - new FutureWithSession(Future.failed[T]( - new IllegalStateException("LiftSession not available in this thread context") - )) - } - } - - private def withCurrentSession[T](task: () => T): () => T = { - val session = S.session openOrThrowException "LiftSession not available in this thread context" - session.buildDeferredFunction(task) - } - - private def withCurrentSession[A,T](task: (A)=>T): (A)=>T = { - val session = S.session openOrThrowException "LiftSession not available in this thread context" - session.buildDeferredFunction(task) - } -} diff --git a/web/webkit/src/main/scala_2.12/net/liftweb/http/NamedCometDispatcher.scala b/web/webkit/src/main/scala_2.12/net/liftweb/http/NamedCometDispatcher.scala deleted file mode 100644 index 0f162854d7..0000000000 --- a/web/webkit/src/main/scala_2.12/net/liftweb/http/NamedCometDispatcher.scala +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright 2007-2026 Lift Committers and Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package net.liftweb -package http - -import common.{Box, Full, Loggable} -import actor.LiftActor - -/** - * This class keeps a list of comet actors that need to update the UI - */ -class NamedCometDispatcher(name: Box[String]) extends LiftActor with Loggable { - - logger.debug("DispatcherActor got name: %s".format(name)) - - private var cometActorsToUpdate: Vector[BaseCometActor]= Vector() - - override def messageHandler = { - /** - * if we do not have this actor in the list, add it (register it) - */ - case registerCometActor(actor, Full(name)) => { - if(cometActorsToUpdate.contains(actor) == false){ - logger.debug("We are adding actor: %s to the list".format(actor)) - cometActorsToUpdate= cometActorsToUpdate :+ actor - } else { - logger.debug("The list so far is %s".format(cometActorsToUpdate)) - } - } - case unregisterCometActor(actor) => { - logger.debug("before %s".format(cometActorsToUpdate)) - cometActorsToUpdate= cometActorsToUpdate.filterNot(_ == actor) - logger.debug("after %s".format(cometActorsToUpdate)) - } - - //Catch the dummy message we send on comet creation - case CometName(name) => - - /** - * Go through the list of actors and send them a message - */ - case msg => { - cometActorsToUpdate.par.foreach{ x => { - x ! msg - logger.debug("We will update this comet actor: %s showing name: %s".format(x, name)) - } - } - } - } -} - - -/** - * These are the message we pass around to - * register each named comet actor with a dispatcher that - * only updates the specific version it monitors - */ -case class registerCometActor(actor: BaseCometActor, name: Box[String]) -case class unregisterCometActor(actor: BaseCometActor) -case class CometName(name: String) diff --git a/web/webkit/src/main/scala_2.13/net/liftweb/http/FutureWithSession.scala b/web/webkit/src/main/scala_2.13/net/liftweb/http/FutureWithSession.scala deleted file mode 100644 index 7477d7083e..0000000000 --- a/web/webkit/src/main/scala_2.13/net/liftweb/http/FutureWithSession.scala +++ /dev/null @@ -1,138 +0,0 @@ -package net.liftweb.http - -import net.liftweb.common.Full - -import scala.concurrent.duration.Duration -import scala.concurrent.{CanAwait, ExecutionContext, Future} -import scala.util.Try - -/** - * Decorates `Future` instance to allow access to session and request resources. Should be created with - * `FutureWithSession.withCurrentSession` that takes the current Lift request and session and make it available - * to all transformation methods and initial `Future` execution body. Each transformation method returns - * `FutureWithSession`, thus, they can be all chained together. - * - * It's important to bear in mind that each chained method requires current thread's `LiftSession` to be available. - * `FutureWithSession` does _not_ propagate initial session or request to all chained methods. - * - * @see FutureWithSession.withCurrentSession - * - * @param delegate original `Future` instance that will be enriched with session and request access - */ -private[http] class FutureWithSession[T](private[this] val delegate: Future[T]) extends Future[T] { - - import FutureWithSession.withCurrentSession - - override def isCompleted: Boolean = delegate.isCompleted - - override def value: Option[Try[T]] = delegate.value - - override def result(atMost: Duration)(implicit permit: CanAwait): T = delegate.result(atMost) - - override def ready(atMost: Duration)(implicit permit: CanAwait) = { - delegate.ready(atMost) - this - } - - override def onComplete[U](f: (Try[T]) => U)(implicit executor:ExecutionContext): Unit = { - val sessionFn = withCurrentSession(f) - delegate.onComplete(sessionFn) - } - - override def map[S](f: T => S)(implicit executor: ExecutionContext): FutureWithSession[S] = { - val sessionFn = withCurrentSession(f) - new FutureWithSession(delegate.map(sessionFn)) - } - - override def flatMap[S](f: T => Future[S])(implicit executor: ExecutionContext): FutureWithSession[S] = { - val sessionFn = withCurrentSession(f) - new FutureWithSession(delegate.flatMap(sessionFn)) - } - - override def andThen[U](pf: PartialFunction[Try[T], U])(implicit executor: ExecutionContext): FutureWithSession[T] = { - val sessionFn = withCurrentSession(pf) - new FutureWithSession(delegate.andThen { - case t => sessionFn(t) - }) - } - - override def failed: FutureWithSession[Throwable] = { - new FutureWithSession(delegate.failed) - } - - override def fallbackTo[U >: T](that: Future[U]): FutureWithSession[U] = { - new FutureWithSession[U](delegate.fallbackTo(that)) - } - - override def recover[U >: T](pf: PartialFunction[Throwable, U])(implicit executor: ExecutionContext): FutureWithSession[U] = { - val sessionFn = withCurrentSession(pf) - new FutureWithSession(delegate.recover { - case t => sessionFn(t) - }) - } - - override def recoverWith[U >: T](pf: PartialFunction[Throwable, Future[U]])(implicit executor: ExecutionContext): FutureWithSession[U] = { - val sessionFn = withCurrentSession(pf) - new FutureWithSession(delegate.recoverWith { - case t => sessionFn(t) - }) - } - - override def transform[S](s: T => S, f: Throwable => Throwable)(implicit executor: ExecutionContext): Future[S] = { - val sessionSuccessFn = withCurrentSession(s) - val sessionFailureFn = withCurrentSession(f) - - new FutureWithSession(delegate.transform(s => sessionSuccessFn(s), f => sessionFailureFn(f))) - } - - def transform[S](f: Try[T] => Try[S])(implicit executor: ExecutionContext): Future[S] = { - val sessionFn = withCurrentSession(f) - new FutureWithSession(delegate.transform(sessionFn)) - } - - def transformWith[S](f: Try[T] => Future[S])(implicit executor: ExecutionContext): Future[S] = { - val sessionFn = withCurrentSession(f) - new FutureWithSession(delegate.transformWith(sessionFn)) - } - - override def zip[U](that: Future[U]): Future[(T, U)] = { - new FutureWithSession(delegate.zip(that)) - } -} - -object FutureWithSession { - - /** - * Creates `Future` instance aware of current request and session. Each `Future` returned by chained - * transformation method (e.g. `map`, `flatMap`) will be also request/session-aware. However, it's - * important to bear in mind that initial request and session are not propagated to chained methods. - * It's required that current execution thread for chained method has its own request/session available - * if reading/writing some data to it as a part of chained method execution. - */ - def withCurrentSession[T](task: => T)(implicit executionContext: ExecutionContext): Future[T] = { - FutureWithSession(task) - } - - private def apply[T](task: => T)(implicit executionContext: ExecutionContext): FutureWithSession[T] = { - S.session match { - case Full(_) => - val sessionFn = withCurrentSession(() => task) - new FutureWithSession(Future[T](sessionFn())) - - case _ => - new FutureWithSession(Future.failed[T]( - new IllegalStateException("LiftSession not available in this thread context") - )) - } - } - - private def withCurrentSession[T](task: () => T): () => T = { - val session = S.session openOrThrowException "LiftSession not available in this thread context" - session.buildDeferredFunction(task) - } - - private def withCurrentSession[A,T](task: (A)=>T): (A)=>T = { - val session = S.session openOrThrowException "LiftSession not available in this thread context" - session.buildDeferredFunction(task) - } -} diff --git a/web/webkit/src/main/scala_2.13/net/liftweb/http/NamedCometDispatcher.scala b/web/webkit/src/main/scala_2.13/net/liftweb/http/NamedCometDispatcher.scala deleted file mode 100644 index 87a494e25f..0000000000 --- a/web/webkit/src/main/scala_2.13/net/liftweb/http/NamedCometDispatcher.scala +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright 2007-2026 Lift Committers and Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package net.liftweb -package http - -import common.{Box, Full, Loggable} -import actor.LiftActor -import scala.collection.parallel.CollectionConverters._ - -/** - * This class keeps a list of comet actors that need to update the UI - */ -class NamedCometDispatcher(name: Box[String]) extends LiftActor with Loggable { - - logger.debug("DispatcherActor got name: %s".format(name)) - - private var cometActorsToUpdate: Vector[BaseCometActor]= Vector() - - override def messageHandler = { - /** - * if we do not have this actor in the list, add it (register it) - */ - case registerCometActor(actor, Full(name)) => { - if(cometActorsToUpdate.contains(actor) == false){ - logger.debug("We are adding actor: %s to the list".format(actor)) - cometActorsToUpdate= cometActorsToUpdate :+ actor - } else { - logger.debug("The list so far is %s".format(cometActorsToUpdate)) - } - } - case unregisterCometActor(actor) => { - logger.debug("before %s".format(cometActorsToUpdate)) - cometActorsToUpdate= cometActorsToUpdate.filterNot(_ == actor) - logger.debug("after %s".format(cometActorsToUpdate)) - } - - //Catch the dummy message we send on comet creation - case CometName(name) => - - /** - * Go through the list of actors and send them a message - */ - case msg => { - cometActorsToUpdate.par.foreach{ x => { - x ! msg - logger.debug("We will update this comet actor: %s showing name: %s".format(x, name)) - } - } - } - } -} - - -/** - * These are the message we pass around to - * register each named comet actor with a dispatcher that - * only updates the specific version it monitors - */ -case class registerCometActor(actor: BaseCometActor, name: Box[String]) -case class unregisterCometActor(actor: BaseCometActor) -case class CometName(name: String) diff --git a/web/webkit/src/test/scala-2.13/net/liftweb/http/LAFutureWithSessionSpec.scala b/web/webkit/src/test/scala-2.13/net/liftweb/http/LAFutureWithSessionSpec.scala deleted file mode 100644 index c6231b0e21..0000000000 --- a/web/webkit/src/test/scala-2.13/net/liftweb/http/LAFutureWithSessionSpec.scala +++ /dev/null @@ -1,314 +0,0 @@ -package net.liftweb.http - -import net.liftweb.actor.LAFuture -import net.liftweb.common.{Box, Empty, Failure, Full} -import net.liftweb.mockweb.WebSpec -import org.specs2.matcher.ThrownMessages - -class LAFutureWithSessionSpec extends WebSpec with ThrownMessages { - - sequential - - object SessionVar1 extends SessionVar[String]("Uninitialized1") - object SessionVar2 extends SessionVar[String]("Uninitialized2") - - object ReqVar1 extends RequestVar[String]("Uninitialized1") - object ReqVar2 extends RequestVar[String]("Uninitialized2") - - val timeout = 10000L - - "LAFutureWithSession" should { - - "fail if session is not available" in { - val future = LAFutureWithSession.withCurrentSession("kaboom") - - future.get(timeout) mustEqual Failure("LiftSession not available in this thread context", Empty, Empty) - } - - "succeed with original value if session is available" withSFor "/" in { - val future = LAFutureWithSession.withCurrentSession("works!") - - future.get(timeout) mustEqual Full("works!") - } - - "have access to session variables in LAFuture task" withSFor "/" in { - SessionVar1("dzien dobry") - - val future = LAFutureWithSession.withCurrentSession(SessionVar1.is) - - future.get(timeout) mustEqual Full("dzien dobry") - } - - "have access to request variables in LAFuture task" withSFor "/" in { - ReqVar1("guten tag") - - val future = LAFutureWithSession.withCurrentSession(ReqVar1.is) - - future.get(timeout) mustEqual Full("guten tag") - } - - "have access to session variables in onComplete()" withSFor "/" in { - // workaround for a possible race condition in AnyVarTrait - // https://groups.google.com/forum/#!topic/liftweb/V1pWy14Wl3A - SessionVar1.is - - val future = LAFutureWithSession.withCurrentSession { - Thread.sleep(Long.MaxValue) - "292 billion years" - } - - future.onComplete { - case Full(v) => SessionVar1(v) - case problem => ko("Future computation failed: " + problem) - } - - future.satisfy("thorgal") - - SessionVar1.is must eventually(beEqualTo("thorgal")) - } - - "have access to request variables in onComplete()" withSFor "/" in { - // workaround for a possible race condition in AnyVarTrait - // https://groups.google.com/forum/#!topic/liftweb/V1pWy14Wl3A - ReqVar1.is - - val future = LAFutureWithSession.withCurrentSession { - Thread.sleep(Long.MaxValue) - "292 billion years" - } - - future.onComplete { - case Full(v) => ReqVar1(v) - case problem => ko("Future computation failed: " + problem) - } - - future.satisfy("thor") - - ReqVar1.is must eventually(beEqualTo("thor")) - } - - "have access to session variables in onFail()" withSFor "/" in { - // workaround for a possible race condition in SessionVar - // https://groups.google.com/forum/#!topic/liftweb/V1pWy14Wl3A - SessionVar1.is - - val future = LAFutureWithSession.withCurrentSession { - Thread.sleep(Long.MaxValue) - "292 billion years" - } - - future.onFail { - case f: Failure => SessionVar1(f.msg) - case _ => fail("The Future should have failed") - } - - future.fail(new Exception("kaboom!")) - - SessionVar1.is must eventually(beEqualTo("kaboom!")) - } - - "have access to request variables in onFail()" withSFor "/" in { - // workaround for a possible race condition in AnyVarTrait - // https://groups.google.com/forum/#!topic/liftweb/V1pWy14Wl3A - ReqVar1.is - - val future = LAFutureWithSession.withCurrentSession { - Thread.sleep(Long.MaxValue) - "292 billion years" - } - - future.onFail { - case f: Failure => ReqVar1(f.msg) - case _ => fail("The Future should have failed") - } - - future.fail(new Exception("nope!")) - - ReqVar1.is must eventually(beEqualTo("nope!")) - } - - "have access to session variables in onSuccess()" withSFor "/" in { - // workaround for a possible race condition in AnyVarTrait - // https://groups.google.com/forum/#!topic/liftweb/V1pWy14Wl3A - SessionVar1.is - - val future = LAFutureWithSession.withCurrentSession { - Thread.sleep(Long.MaxValue) - "292 billion years" - } - - future.onSuccess(SessionVar1(_)) - - future.satisfy("done") - - SessionVar1.is must eventually(beEqualTo("done")) - } - - "have access to request variables in onSuccess()" withSFor "/" in { - // workaround for a possible race condition in AnyVarTrait - // https://groups.google.com/forum/#!topic/liftweb/V1pWy14Wl3A - ReqVar1.is - - val future = LAFutureWithSession.withCurrentSession { - Thread.sleep(Long.MaxValue) - "292 billion years" - } - - future.onSuccess(ReqVar1(_)) - - future.satisfy("my preciousss") - - ReqVar1.is must eventually(beEqualTo("my preciousss")) - } - - "have access to session variables in chains of filter()" withSFor "/" in { - SessionVar1("see") - SessionVar2("me") - - val future = LAFutureWithSession.withCurrentSession("they see me rollin") - val filtered = future - .filter(_.contains(SessionVar1.is)) - .filter(_.contains(SessionVar2.is)) - - filtered.get(timeout) must eventually(===(Full("they see me rollin"): Box[String])) - } - - "have access to request variables in chains of filter()" withSFor "/" in { - ReqVar1("see") - ReqVar2("me") - - val future = LAFutureWithSession.withCurrentSession("they see me rollin") - val filtered = future - .filter(_.contains(ReqVar1.is)) - .filter(_.contains(ReqVar2.is)) - - filtered.get(timeout) must eventually(===(Full("they see me rollin"): Box[String])) - } - - "have access to session variables in chains of withFilter()" withSFor "/" in { - SessionVar1("come") - SessionVar2("prey") - - val future = LAFutureWithSession.withCurrentSession("do not come between the nazgul and his prey") - val filtered = future - .withFilter(_.contains(SessionVar1.is)) - .withFilter(_.contains(SessionVar2.is)) - - filtered.get(timeout) must eventually(===(Full("do not come between the nazgul and his prey"): Box[String])) - } - - "have access to request variables in chains of withFilter()" withSFor "/" in { - ReqVar1("hurt") - ReqVar2("precious") - - val future = LAFutureWithSession.withCurrentSession("mustn't go that way, mustn't hurt the precious!") - val filtered = future - .withFilter(_.contains(ReqVar1.is)) - .withFilter(_.contains(ReqVar2.is)) - - filtered.get(timeout) must eventually(===(Full("mustn't go that way, mustn't hurt the precious!"): Box[String])) - } - - "have access to session variables in chains of map()" withSFor "/" in { - SessionVar1("b") - SessionVar2("c") - - val future = LAFutureWithSession.withCurrentSession("a") - val mapped = future.map(_ + SessionVar1.is).map(_ + SessionVar2.is) - - mapped.get(timeout) mustEqual Full("abc") - } - - "have access to request variables in chains of map()" withSFor "/" in { - ReqVar1("b") - ReqVar2("c") - - val future = LAFutureWithSession.withCurrentSession("a") - val mapped = future.map(_ + ReqVar1.is).map(_ + ReqVar2.is) - - mapped.get(timeout) mustEqual Full("abc") - } - - "have access to session variables in chains of flatMap()" withSFor "/" in { - SessionVar1("e") - SessionVar2("f") - - val future = LAFutureWithSession.withCurrentSession("d") - val mapped = future - .flatMap { s => - val out = s + SessionVar1.is - LAFuture.build(out) - } - .flatMap { s => - val out = s + SessionVar2.is - LAFuture.build(out) - } - - mapped.get(timeout) mustEqual Full("def") - } - - "have access to request variables in chains of flatMap()" withSFor "/" in { - ReqVar1("e") - ReqVar2("f") - - val future = LAFutureWithSession.withCurrentSession("d") - val mapped = future - .flatMap { s => - val out = s + ReqVar1.is - LAFuture.build(out) - } - .flatMap { s => - val out = s + ReqVar2.is - LAFuture.build(out) - } - - mapped.get(timeout) mustEqual Full("def") - } - - "have access to session variables in foreach()" withSFor "/" in { - // workaround for a possible race condition in AnyVarTrait - // https://groups.google.com/forum/#!topic/liftweb/V1pWy14Wl3A - SessionVar1.is - - val future = LAFutureWithSession.withCurrentSession("cookie") - future.foreach(SessionVar1(_)) - - SessionVar1.is must eventually(beEqualTo("cookie")) - } - - "have access to request variables in foreach()" withSFor "/" in { - // workaround for a possible race condition in AnyVarTrait - // https://groups.google.com/forum/#!topic/liftweb/V1pWy14Wl3A - ReqVar1.is - - val future = LAFutureWithSession.withCurrentSession("monster") - future.foreach(ReqVar1(_)) - - ReqVar1.is must eventually(beEqualTo("monster")) - } - - "not leak out initial session between threads with their own sessions" in { - val session1 = new LiftSession("Test session 1", "", Empty) - val session2 = new LiftSession("Test session 2", "", Empty) - val session3 = new LiftSession("Test session 3", "", Empty) - - S.initIfUninitted(session1)(SessionVar1("one")) - S.initIfUninitted(session2)(SessionVar1("two")) - S.initIfUninitted(session3)(SessionVar1("three")) - - val future = S.initIfUninitted(session1)(LAFutureWithSession.withCurrentSession("zero")) - - S.initIfUninitted(session2) { - future.map(v => SessionVar1.is).get(timeout) must eventually(===(Full("two"): Box[String])) - } - - S.initIfUninitted(session3) { - future.map(v => SessionVar1.is).get(timeout) must eventually(===(Full("three"): Box[String])) - } - - S.initIfUninitted(session1) { - future.map(v => SessionVar1.is).get(timeout) must eventually(===(Full("one"): Box[String])) - } - } - } -} diff --git a/web/webkit/src/test/scala-2.13/net/liftweb/http/LiftMergeSpec.scala b/web/webkit/src/test/scala-2.13/net/liftweb/http/LiftMergeSpec.scala deleted file mode 100644 index d38dcfbd99..0000000000 --- a/web/webkit/src/test/scala-2.13/net/liftweb/http/LiftMergeSpec.scala +++ /dev/null @@ -1,473 +0,0 @@ -package net.liftweb -package http - -import scala.xml._ - -import org.specs2.mutable.Specification -import org.specs2.matcher.XmlMatchers -import org.specs2.mock.Mockito - -import common._ - -import js.JE.JsObj -import js.pageScript -import SpecContextHelpers._ - -class LiftMergeSpec extends Specification with XmlMatchers with Mockito { - val mockReq = mock[Req] - mockReq.contextPath returns "/context-path" - - val testSession = new LiftSession("/context-path", "underlying id", Empty) - - val testRules = new LiftRules() - // Avoid extra appended elements by default. - testRules.javaScriptSettings.default.set(() => () => Empty) - testRules.autoIncludeAjaxCalc.default.set(() => () => (_: LiftSession) => false) - testRules.excludePathFromContextPathRewriting.default - .set( - () => (in: String) => in.startsWith("exclude-me") - ) - - val eventExtractingTestRules = new LiftRules() - eventExtractingTestRules.javaScriptSettings.default.set(() => () => Empty) - eventExtractingTestRules.autoIncludeAjaxCalc.default.set(() => () => (_: LiftSession) => false) - eventExtractingTestRules.extractInlineJavaScript = true - - "LiftMerge when doing the final page merge" should { - "merge head segments in the page body in order into main head" in withLiftRules(testRules) { - val result = - testSession.merge( - - - - - - - - - -
        -

        - - - -

        -
        - - , - mockReq - ) - - (result \ "head" \ "_") === (Seq( - , - , - , - - ): NodeSeq) - } - - "merge tail segments in the page body in order at the end of the body" in withLiftRules(testRules) { - val result = - testSession.merge( - - - - - - - - - -
        -

        - - - -

        -
        - -

        Thingies

        -

        More thingies

        - - , - mockReq - ) - - (result \ "body" \ "_").takeRight(3) === (Seq( - , - , - - ): NodeSeq) - } - - "not merge tail segments in the head" in withLiftRules(testRules) { - val result = - testSession.merge( - - - - - - - - - - - -
        -

        - - - -

        -
        - -

        Thingies

        -

        More thingies

        - - , - mockReq - ) - - (result \ "body" \ "_").takeRight(3) === (Seq( - , - , - - ): NodeSeq) - } - - "normalize absolute link hrefs everywhere" in withLiftContext(testRules, testSession) { - val result = - testSession.merge( - - - - - - - - - - -
        -

        - - - -

        -
        - -

        Thingies

        -

        More thingies

        - - , - mockReq - ) - - (result \\ "link").map(_ \@ "href") === - "/context-path/testlink" :: - "/context-path/testlink2" :: - "/context-path/testlink3" :: Nil - } - - "normalize absolute script srcs everywhere" in withLiftContext(testRules, testSession) { - val result = - testSession.merge( - - - - - - - - - - -
        -

        - - - -

        -
        - -

        Thingies

        -

        More thingies

        - - , - mockReq - ) - - (result \\ "script").map(_ \@ "src") === - "/context-path/testscript" :: - "/context-path/testscript2" :: Nil - } - - "normalize absolute a hrefs everywhere" in withLiftContext(testRules, testSession) { - val result = - testSession.merge( - - - Booyan - - - Booyan - - Booyan - -
        - Booyan -

        - - Booyan - -

        -
        - -

        Thingies Booyan

        -

        More thingies

        - - , - mockReq - ) - - (result \\ "a").map(_ \@ "href") === - "/context-path/testa1" :: - "testa3" :: - "/context-path/testa2" :: - "testa4" :: - "/context-path/testa6" :: - "/context-path/testa5" :: Nil - } - - "normalize absolute form actions everywhere" in withLiftContext(testRules, testSession) { - val result = - testSession.merge( - - -
        Booyan
        - - -
        Booyan
        - -
        Booyan
        - -
        -
        Booyan
        -

        - -

        Booyan
        - -

        -
        - -

        Thingies

        Booyan

        -

        More thingies

        - - , - mockReq - ) - - (result \\ "form").map(_ \@ "action") === - "/context-path/testform1" :: - "testform3" :: - "/context-path/testform2" :: - "testform4" :: - "/context-path/testform6" :: - "/context-path/testform5" :: Nil - } - - "not rewrite script srcs anywhere" in withLiftContext(testRules, testSession) { - val result = - URLRewriter.doWith((_: String) => "rewritten") { - testSession.merge( - - - - - - - - -
        -

        - -