diff --git a/build.sbt b/build.sbt index a54a012..881d447 100644 --- a/build.sbt +++ b/build.sbt @@ -23,7 +23,19 @@ developers := List( ) ) -crossScalaVersions := List("2.10.7", "2.11.12", "2.12.10", "2.13.1") +crossScalaVersions := List( + "2.10.7", "2.11.12", "2.12.10", "2.13.1", + "0.22.0", "0.23.0", "0.24.0-RC1" +) + +/** Add src/main/scala-{2|3} to Compile / unmanagedSourceDirectories */ +Compile / unmanagedSourceDirectories ++= { + val sourceDir = (Compile / sourceDirectory).value + CrossVersion.partialVersion(scalaVersion.value).map { + case (0 | 3, _) => sourceDir / "scala-3" + case (n, _) => sourceDir / s"scala-$n" + } +} libraryDependencies ++= Seq( "org.scalatest" %% "scalatest-core" % "3.2.0-M4", @@ -33,6 +45,7 @@ libraryDependencies ++= Seq( "org.scalatest" %% "scalatest-shouldmatchers" % "3.2.0-M4" % "test", "junit" % "junit" % "4.12" ) +Test / scalacOptions ++= (if (isDotty.value) Seq("-language:implicitConversions") else Nil) import scala.xml.{Node => XmlNode, NodeSeq => XmlNodeSeq, _} import scala.xml.transform.{RewriteRule, RuleTransformer} diff --git a/project/plugins.sbt b/project/plugins.sbt index 34cc200..5f2c6b3 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -3,3 +3,5 @@ addSbtPlugin("com.jsuereth" % "sbt-pgp" % "1.1.1") addSbtPlugin("com.geirsson" % "sbt-ci-release" % "1.2.2") addSbtPlugin("com.typesafe.sbt" % "sbt-osgi" % "0.9.4") + +addSbtPlugin("ch.epfl.lamp" % "sbt-dotty" % "0.4.1") diff --git a/src/main/scala/org/scalatestplus/junit/AssertionsForJUnitMacro.scala b/src/main/scala-2/org/scalatestplus/junit/AssertionsForJUnitMacro.scala similarity index 100% rename from src/main/scala/org/scalatestplus/junit/AssertionsForJUnitMacro.scala rename to src/main/scala-2/org/scalatestplus/junit/AssertionsForJUnitMacro.scala diff --git a/src/main/scala-2/org/scalatestplus/junit/VersionSpecificAssertionsForJUnit.scala b/src/main/scala-2/org/scalatestplus/junit/VersionSpecificAssertionsForJUnit.scala new file mode 100644 index 0000000..aab15ee --- /dev/null +++ b/src/main/scala-2/org/scalatestplus/junit/VersionSpecificAssertionsForJUnit.scala @@ -0,0 +1,16 @@ +package org.scalatestplus.junit + +import org.scalactic.{Prettifier, source} +import org.scalatest.{Assertion, Assertions} + +trait VersionSpecificAssertionsForJUnit extends Assertions { + import scala.language.experimental.macros + + override def assert(condition: Boolean)(implicit prettifier: Prettifier, pos: source.Position): Assertion = macro AssertionsForJUnitMacro.assert + + override def assert(condition: Boolean, clue: Any)(implicit prettifier: Prettifier, pos: source.Position): Assertion = macro AssertionsForJUnitMacro.assertWithClue + + override def assume(condition: Boolean)(implicit prettifier: Prettifier, pos: source.Position): Assertion = macro AssertionsForJUnitMacro.assume + + override def assume(condition: Boolean, clue: Any)(implicit prettifier: Prettifier, pos: source.Position): Assertion = macro AssertionsForJUnitMacro.assumeWithClue +} diff --git a/src/main/scala-3/org/scalatestplus/junit/AssertionsForJUnitMacro.scala b/src/main/scala-3/org/scalatestplus/junit/AssertionsForJUnitMacro.scala new file mode 100644 index 0000000..f391cd4 --- /dev/null +++ b/src/main/scala-3/org/scalatestplus/junit/AssertionsForJUnitMacro.scala @@ -0,0 +1,16 @@ +package org.scalatestplus.junit + +import org.scalactic.{Prettifier, source} +import org.scalatest.Assertions +import org.scalatest.AssertionsMacro.transform +import org.scalatest.compatible.Assertion + +import scala.quoted.{Expr, QuoteContext} + +object AssertionsForJUnitMacro { + def assert(condition: Expr[Boolean], prettifier: Expr[Prettifier], pos: Expr[source.Position], clue: Expr[Any])(implicit qctx: QuoteContext): Expr[Assertion] = + transform('{AssertionsForJUnit.assertionsHelper.macroAssert}, condition, prettifier, pos, clue) + + def assume(condition: Expr[Boolean], prettifier: Expr[Prettifier], pos: Expr[source.Position], clue: Expr[Any])(implicit qctx: QuoteContext): Expr[Assertion] = + transform('{AssertionsForJUnit.assertionsHelper.macroAssume}, condition, prettifier, pos, clue) +} diff --git a/src/main/scala-3/org/scalatestplus/junit/VersionSpecificAssertionsForJUnit.scala b/src/main/scala-3/org/scalatestplus/junit/VersionSpecificAssertionsForJUnit.scala new file mode 100644 index 0000000..231997f --- /dev/null +++ b/src/main/scala-3/org/scalatestplus/junit/VersionSpecificAssertionsForJUnit.scala @@ -0,0 +1,23 @@ +package org.scalatestplus.junit + +import org.scalactic.{Prettifier, source} +import org.scalatest.{Assertions, AssertionsMacro} +import org.scalatest.compatible.Assertion + +trait VersionSpecificAssertionsForJUnit extends Assertions { + // https://github.com/lampepfl/dotty/pull/8601#pullrequestreview-380646858 + implicit object UseJUnitAssertions + + inline def assert(inline condition: Boolean)(implicit prettifier: Prettifier, pos: source.Position, use: UseJUnitAssertions.type): Assertion = + ${ AssertionsForJUnitMacro.assert('{condition}, '{prettifier}, '{pos}, '{""}) } + + inline def assert(inline condition: Boolean, clue: Any)(implicit prettifier: Prettifier, pos: source.Position, use: UseJUnitAssertions.type): Assertion = + ${ AssertionsForJUnitMacro.assert('{condition}, '{prettifier}, '{pos}, '{clue}) } + + inline def assume(inline condition: Boolean)(implicit prettifier: Prettifier, pos: source.Position, use: UseJUnitAssertions.type): Assertion = + ${ AssertionsForJUnitMacro.assume('{condition}, '{prettifier}, '{pos}, '{""}) } + + inline def assume(inline condition: Boolean, clue: Any)(implicit prettifier: Prettifier, pos: source.Position, use: UseJUnitAssertions.type): Assertion = + ${ AssertionsForJUnitMacro.assume('{condition}, '{prettifier}, '{pos}, '{clue}) } + +} diff --git a/src/main/scala/org/scalatestplus/junit/AssertionsForJUnit.scala b/src/main/scala/org/scalatestplus/junit/AssertionsForJUnit.scala index c06f9b4..599baa2 100644 --- a/src/main/scala/org/scalatestplus/junit/AssertionsForJUnit.scala +++ b/src/main/scala/org/scalatestplus/junit/AssertionsForJUnit.scala @@ -95,7 +95,7 @@ import org.scalatest.exceptions.{StackDepthException, TestCanceledException} * * @author Bill Venners */ -trait AssertionsForJUnit extends Assertions { +trait AssertionsForJUnit extends VersionSpecificAssertionsForJUnit { private[org] override def newAssertionFailedException(optionalMessage: Option[String], optionalCause: Option[Throwable], pos: source.Position, differences: scala.collection.immutable.IndexedSeq[String]): Throwable = { new JUnitTestFailedError(optionalMessage, optionalCause, pos, None) @@ -116,16 +116,6 @@ trait AssertionsForJUnit extends Assertions { } } - import scala.language.experimental.macros - - override def assert(condition: Boolean)(implicit prettifier: Prettifier, pos: source.Position): Assertion = macro AssertionsForJUnitMacro.assert - - override def assert(condition: Boolean, clue: Any)(implicit prettifier: Prettifier, pos: source.Position): Assertion = macro AssertionsForJUnitMacro.assertWithClue - - override def assume(condition: Boolean)(implicit prettifier: Prettifier, pos: source.Position): Assertion = macro AssertionsForJUnitMacro.assume - - override def assume(condition: Boolean, clue: Any)(implicit prettifier: Prettifier, pos: source.Position): Assertion = macro AssertionsForJUnitMacro.assumeWithClue - /* private[scalatest] override def newAssertionFailedException(optionalMessage: Option[Any], optionalCause: Option[Throwable], stackDepth: Int): Throwable = { @@ -222,6 +212,9 @@ object AssertionsForJUnit extends AssertionsForJUnit { Succeeded } + def macroAssert(bool: Bool, clue: Any, pos: source.Position): Assertion = + macroAssert(bool, clue, bool.prettifier, pos) + /** * Assume that the passed in Bool is true, else throw TestCanceledException. * @@ -236,6 +229,9 @@ object AssertionsForJUnit extends AssertionsForJUnit { } Succeeded } + + def macroAssume(bool: Bool, clue: Any, pos: source.Position): Assertion = + macroAssume(bool, clue, bool.prettifier, pos) } /** diff --git a/src/main/scala/org/scalatestplus/junit/JUnitHelper.scala b/src/main/scala/org/scalatestplus/junit/JUnitHelper.scala index 36f95ef..22a5582 100644 --- a/src/main/scala/org/scalatestplus/junit/JUnitHelper.scala +++ b/src/main/scala/org/scalatestplus/junit/JUnitHelper.scala @@ -23,7 +23,7 @@ import org.scalatest.{Suite, TagAnnotation} private[junit] object JUnitHelper { def mergeMap[A, B](ms: List[Map[A, B]])(f: (B, B) => B): Map[A, B] = - (Map[A, B]() /: (for (m <- ms; kv <- m) yield kv)) { (a, kv) => + (for (m <- ms; kv <- m) yield kv).foldLeft(Map[A, B]()) { (a, kv) => a + (if (a.contains(kv._1)) kv._1 -> f(a(kv._1), kv._2) else kv) } @@ -47,7 +47,7 @@ private[junit] object JUnitHelper { val decodedTestText = scala.reflect.NameTransformer.decode(testText) val formattedText = if (includeIcon) { - val testSucceededIcon = Resources.testSucceededIconChar + val testSucceededIcon = Resources.testSucceededIconChar() (" " * (if (level == 0) 0 else (level - 1))) + Resources.iconPlusShortName(testSucceededIcon, decodedTestText) } else { @@ -59,7 +59,7 @@ private[junit] object JUnitHelper { def checkForPublicNoArgConstructor(clazz: java.lang.Class[_]) = { try { - val constructor = clazz.getConstructor(new Array[java.lang.Class[T] forSome { type T }](0): _*) + val constructor = clazz.getConstructor(new Array[java.lang.Class[_]](0): _*) Modifier.isPublic(constructor.getModifiers) } diff --git a/src/main/scala/org/scalatestplus/junit/JUnitWrapperSuite.scala b/src/main/scala/org/scalatestplus/junit/JUnitWrapperSuite.scala index 3b3f2bc..1eaee29 100644 --- a/src/main/scala/org/scalatestplus/junit/JUnitWrapperSuite.scala +++ b/src/main/scala/org/scalatestplus/junit/JUnitWrapperSuite.scala @@ -85,7 +85,7 @@ class JUnitWrapperSuite(junitClassName: String, loader: ClassLoader) extends Sui * @return number of expected test count */ override def expectedTestCount(filter: Filter): Int = { - getRequest.getRunner.getDescription.testCount + getRequest().getRunner.getDescription.testCount } /** diff --git a/src/main/scala/org/scalatestplus/junit/MyRunListener.scala b/src/main/scala/org/scalatestplus/junit/MyRunListener.scala index 8e7aa33..5b78363 100644 --- a/src/main/scala/org/scalatestplus/junit/MyRunListener.scala +++ b/src/main/scala/org/scalatestplus/junit/MyRunListener.scala @@ -52,7 +52,7 @@ import exceptions._ if (throwableOrNull != null) throwableOrNull.toString else - Resources.jUnitTestFailed + Resources.jUnitTestFailed() val formatter = getIndentedTextForTest(testName, 1, true) val payload = diff --git a/src/main/scala/org/scalatestplus/junit/RunNotifierReporter.scala b/src/main/scala/org/scalatestplus/junit/RunNotifierReporter.scala index 042964c..77d1656 100644 --- a/src/main/scala/org/scalatestplus/junit/RunNotifierReporter.scala +++ b/src/main/scala/org/scalatestplus/junit/RunNotifierReporter.scala @@ -98,7 +98,7 @@ private[junit] class RunNotifierReporter(runNotifier: RunNotifier) extends Repor case None => null // Yuck. Not sure if the exception passed to new Failure can be null, but it could be given this code. Usually throwable would be defined. } val possiblyEmptyMessage = messageOrThrowablesDetailMessage(message, throwable) - val description = Description.createSuiteDescription(Resources.runAborted + " " + possiblyEmptyMessage) + val description = Description.createSuiteDescription(Resources.runAborted() + " " + possiblyEmptyMessage) runNotifier.fireTestFailure(new Failure(description, throwableOrNull)) // Best we can do in JUnit, as far as I know runNotifier.fireTestFinished(description) diff --git a/src/test/scala/org/scalatestplus/junit/JUnitRunnerSuite.scala b/src/test/scala/org/scalatestplus/junit/JUnitRunnerSuite.scala index 31994be..2f72b4b 100644 --- a/src/test/scala/org/scalatestplus/junit/JUnitRunnerSuite.scala +++ b/src/test/scala/org/scalatestplus/junit/JUnitRunnerSuite.scala @@ -105,15 +105,15 @@ package org.scalatestplus.junit { test("a test failure is reported due to an exception thrown from " + "beforeAll when JUnitRunner.run is called directly") { - val runNotifier = - new RunNotifier { - var methodInvocationCount = 0 - var passed: Option[Failure] = None - override def fireTestFailure(failure: Failure): Unit = { - methodInvocationCount += 1 - passed = Some(failure) - } + class MyRunNotifier extends RunNotifier { + var methodInvocationCount = 0 + var passed: Option[Failure] = None + override def fireTestFailure(failure: Failure): Unit = { + methodInvocationCount += 1 + passed = Some(failure) } + } + val runNotifier = new MyRunNotifier (new JUnitRunner(classOf[KerblooeySuite])).run(runNotifier) diff --git a/src/test/scala/org/scalatestplus/junit/JUnitSuiteSuite.scala b/src/test/scala/org/scalatestplus/junit/JUnitSuiteSuite.scala index 844f62a..f58c2b2 100644 --- a/src/test/scala/org/scalatestplus/junit/JUnitSuiteSuite.scala +++ b/src/test/scala/org/scalatestplus/junit/JUnitSuiteSuite.scala @@ -15,7 +15,7 @@ */ package org.scalatestplus.junit { - import org.scalatest._ +import org.scalatest._ import org.scalatest.events._ // Put fixture suites in a subpackage, so they won't be discovered by @@ -23,7 +23,7 @@ import org.scalatest.events._ package helpers { import _root_.org.junit.Ignore -import _root_.org.junit.Test + import _root_.org.junit.Test class HappySuite extends JUnitSuite { diff --git a/src/test/scala/org/scalatestplus/junit/RunNotifierSuite.scala b/src/test/scala/org/scalatestplus/junit/RunNotifierSuite.scala index 96c7519..b8c256c 100644 --- a/src/test/scala/org/scalatestplus/junit/RunNotifierSuite.scala +++ b/src/test/scala/org/scalatestplus/junit/RunNotifierSuite.scala @@ -33,16 +33,15 @@ class RunNotifierSuite extends funsuite.AnyFunSuite { val ordinal = new Ordinal(99) test("report(TestStarting) generates a fireTestStarted invocation") { - - val runNotifier = - new RunNotifier { - var fireTestStartedInvocationCount = 0 - var passedDesc: Option[Description] = None - override def fireTestStarted(description: Description): Unit = { - fireTestStartedInvocationCount += 1 - passedDesc = Some(description) - } + class MyRunNotifier extends RunNotifier { + var fireTestStartedInvocationCount = 0 + var passedDesc: Option[Description] = None + override def fireTestStarted(description: Description): Unit = { + fireTestStartedInvocationCount += 1 + passedDesc = Some(description) } + } + val runNotifier = new MyRunNotifier import scala.language.reflectiveCalls @@ -60,16 +59,15 @@ class RunNotifierSuite extends funsuite.AnyFunSuite { } test("report(TestFailed) generates a fireTestFailure invocation") { - - val runNotifier = - new RunNotifier { - var methodInvocationCount = 0 - var passed: Option[Failure] = None - override def fireTestFailure(failure: Failure): Unit = { - methodInvocationCount += 1 - passed = Some(failure) - } + class MyRunNotifier extends RunNotifier { + var methodInvocationCount = 0 + var passed: Option[Failure] = None + override def fireTestFailure(failure: Failure): Unit = { + methodInvocationCount += 1 + passed = Some(failure) } + } + val runNotifier = new MyRunNotifier val reporter = new RunNotifierReporter(runNotifier) val exception = new IllegalArgumentException @@ -83,16 +81,15 @@ class RunNotifierSuite extends funsuite.AnyFunSuite { } test("report(TestSucceeded) generates a fireTestFinished invocation") { - - val runNotifier = - new RunNotifier { - var methodInvocationCount = 0 - var passed: Option[Description] = None - override def fireTestFinished(description: Description): Unit = { - methodInvocationCount += 1 - passed = Some(description) - } + class MyRunNotifier extends RunNotifier { + var methodInvocationCount = 0 + var passed: Option[Description] = None + override def fireTestFinished(description: Description): Unit = { + methodInvocationCount += 1 + passed = Some(description) } + } + val runNotifier = new MyRunNotifier import scala.language.reflectiveCalls @@ -104,16 +101,15 @@ class RunNotifierSuite extends funsuite.AnyFunSuite { } test("report(TestIgnored) generates a fireTestIgnored invocation") { - - val runNotifier = - new RunNotifier { - var methodInvocationCount = 0 - var passed: Option[Description] = None - override def fireTestIgnored(description: Description): Unit = { - methodInvocationCount += 1 - passed = Some(description) - } + class MyRunNotifier extends RunNotifier { + var methodInvocationCount = 0 + var passed: Option[Description] = None + override def fireTestIgnored(description: Description): Unit = { + methodInvocationCount += 1 + passed = Some(description) } + } + val runNotifier = new MyRunNotifier import scala.language.reflectiveCalls @@ -134,16 +130,15 @@ class RunNotifierSuite extends funsuite.AnyFunSuite { // fireTestFailure is the best we could do given the RunNotifier interface test("report(SuiteAborted) generates a fireTestFailure invocation") { - - val runNotifier = - new RunNotifier { - var methodInvocationCount = 0 - var passed: Option[Failure] = None - override def fireTestFailure(failure: Failure): Unit = { - methodInvocationCount += 1 - passed = Some(failure) - } + class MyRunNotifier extends RunNotifier { + var methodInvocationCount = 0 + var passed: Option[Failure] = None + override def fireTestFailure(failure: Failure): Unit = { + methodInvocationCount += 1 + passed = Some(failure) } + } + val runNotifier = new MyRunNotifier import scala.language.reflectiveCalls @@ -169,16 +164,15 @@ class RunNotifierSuite extends funsuite.AnyFunSuite { // fireTestFailure is the best we could do given the RunNotifier interface test("report(RunAborted) generates a fireTestFailure invocation") { - - val runNotifier = - new RunNotifier { - var methodInvocationCount = 0 - var passed: Option[Failure] = None - override def fireTestFailure(failure: Failure): Unit = { - methodInvocationCount += 1 - passed = Some(failure) - } + class MyRunNotifier extends RunNotifier { + var methodInvocationCount = 0 + var passed: Option[Failure] = None + override def fireTestFailure(failure: Failure): Unit = { + methodInvocationCount += 1 + passed = Some(failure) } + } + val runNotifier = new MyRunNotifier val reporter = new RunNotifierReporter(runNotifier) val exception = new IllegalArgumentException