From 106fe8b5bd1ff1e548f43fd1764f2281865505f7 Mon Sep 17 00:00:00 2001 From: Andrew Valencik Date: Sat, 25 Jun 2022 13:37:18 -0400 Subject: [PATCH 1/8] Make rootCause cross-platform without shims --- .../scala/munit/internal/InvocationTargetException.scala | 3 --- munit/js/src/main/scala/munit/internal/PlatformCompat.scala | 4 ---- .../scala/munit/internal/UndeclaredThrowableException.scala | 3 --- munit/shared/src/main/scala/munit/MUnitRunner.scala | 5 +---- 4 files changed, 1 insertion(+), 14 deletions(-) delete mode 100644 munit/js/src/main/scala/munit/internal/InvocationTargetException.scala delete mode 100644 munit/js/src/main/scala/munit/internal/UndeclaredThrowableException.scala diff --git a/munit/js/src/main/scala/munit/internal/InvocationTargetException.scala b/munit/js/src/main/scala/munit/internal/InvocationTargetException.scala deleted file mode 100644 index d83734e3..00000000 --- a/munit/js/src/main/scala/munit/internal/InvocationTargetException.scala +++ /dev/null @@ -1,3 +0,0 @@ -package munit.internal - -class InvocationTargetException extends java.lang.RuntimeException diff --git a/munit/js/src/main/scala/munit/internal/PlatformCompat.scala b/munit/js/src/main/scala/munit/internal/PlatformCompat.scala index f5fb39dd..3c238de7 100644 --- a/munit/js/src/main/scala/munit/internal/PlatformCompat.scala +++ b/munit/js/src/main/scala/munit/internal/PlatformCompat.scala @@ -75,8 +75,4 @@ object PlatformCompat { private var myClassLoader: ClassLoader = _ def setThisClassLoader(loader: ClassLoader): Unit = myClassLoader = loader def getThisClassLoader: ClassLoader = myClassLoader - - type InvocationTargetException = munit.internal.InvocationTargetException - type UndeclaredThrowableException = - munit.internal.UndeclaredThrowableException } diff --git a/munit/js/src/main/scala/munit/internal/UndeclaredThrowableException.scala b/munit/js/src/main/scala/munit/internal/UndeclaredThrowableException.scala deleted file mode 100644 index 86497cb6..00000000 --- a/munit/js/src/main/scala/munit/internal/UndeclaredThrowableException.scala +++ /dev/null @@ -1,3 +0,0 @@ -package munit.internal - -class UndeclaredThrowableException extends java.lang.RuntimeException diff --git a/munit/shared/src/main/scala/munit/MUnitRunner.scala b/munit/shared/src/main/scala/munit/MUnitRunner.scala index 13f442b3..481e00ad 100644 --- a/munit/shared/src/main/scala/munit/MUnitRunner.scala +++ b/munit/shared/src/main/scala/munit/MUnitRunner.scala @@ -1,9 +1,7 @@ package munit import munit.internal.FutureCompat._ -import munit.internal.PlatformCompat.InvocationTargetException import munit.internal.PlatformCompat -import munit.internal.PlatformCompat.UndeclaredThrowableException import munit.internal.console.Printers import munit.internal.console.StackTraces import munit.internal.junitinterface.Configurable @@ -318,8 +316,7 @@ class MUnitRunner(val cls: Class[_ <: Suite], newInstance: () => Suite) // NOTE(olafur): these exceptions appear when we await on futures. We unwrap // these exception in order to provide more helpful error messages. private def rootCause(x: Throwable): Throwable = x match { - case _: InvocationTargetException | _: ExceptionInInitializerError | - _: UndeclaredThrowableException | _: ExecutionException + case _: ExceptionInInitializerError | _: ExecutionException if x.getCause != null => rootCause(x.getCause) case _ => x From 80b6e87bc5993be76860cac588e6fe3b74834de1 Mon Sep 17 00:00:00 2001 From: Andrew Valencik Date: Sat, 25 Jun 2022 13:50:19 -0400 Subject: [PATCH 2/8] Move rootCause to MUnitRunner companion object --- .../src/main/scala/munit/MUnitRunner.scala | 24 ++++++++++--------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/munit/shared/src/main/scala/munit/MUnitRunner.scala b/munit/shared/src/main/scala/munit/MUnitRunner.scala index 481e00ad..977173a1 100644 --- a/munit/shared/src/main/scala/munit/MUnitRunner.scala +++ b/munit/shared/src/main/scala/munit/MUnitRunner.scala @@ -291,7 +291,7 @@ class MUnitRunner(val cls: Class[_ <: Suite], newInstance: () => Suite) Future.successful(()) case NonFatal(ex) => trimStackTrace(ex) - val cause = rootCause(ex) + val cause = MUnitRunner.rootCause(ex) val failure = new Failure(description, cause) cause match { case _: AssumptionViolatedException => @@ -313,15 +313,6 @@ class MUnitRunner(val cls: Class[_ <: Suite], newInstance: () => Suite) } } - // NOTE(olafur): these exceptions appear when we await on futures. We unwrap - // these exception in order to provide more helpful error messages. - private def rootCause(x: Throwable): Throwable = x match { - case _: ExceptionInInitializerError | _: ExecutionException - if x.getCause != null => - rootCause(x.getCause) - case _ => x - } - private def futureFromAny(any: Any): Future[Any] = any match { case f: Future[_] => f case _ => Future.successful(any) @@ -425,7 +416,9 @@ class MUnitRunner(val cls: Class[_ <: Suite], newInstance: () => Suite) val description = createTestDescription(test) notifier.fireTestStarted(description) trimStackTrace(ex) - notifier.fireTestFailure(new Failure(description, rootCause(ex))) + notifier.fireTestFailure( + new Failure(description, MUnitRunner.rootCause(ex)) + ) notifier.fireTestFinished(description) } private def trimStackTrace(ex: Throwable): Unit = { @@ -462,4 +455,13 @@ object MUnitRunner { case nsme: NoSuchMethodException => false } } + + // NOTE(olafur): these exceptions appear when we await on futures. We unwrap + // these exception in order to provide more helpful error messages. + private def rootCause(x: Throwable): Throwable = x match { + case _: ExceptionInInitializerError | _: ExecutionException + if x.getCause != null => + rootCause(x.getCause) + case _ => x + } } From 1d46809e99a2094160816a4c5d64a91fd20b5cd7 Mon Sep 17 00:00:00 2001 From: Andrew Valencik Date: Sat, 25 Jun 2022 13:52:29 -0400 Subject: [PATCH 3/8] Expose rootCause in private[munit] --- munit/shared/src/main/scala/munit/MUnitRunner.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/munit/shared/src/main/scala/munit/MUnitRunner.scala b/munit/shared/src/main/scala/munit/MUnitRunner.scala index 977173a1..7f6aff9e 100644 --- a/munit/shared/src/main/scala/munit/MUnitRunner.scala +++ b/munit/shared/src/main/scala/munit/MUnitRunner.scala @@ -458,7 +458,7 @@ object MUnitRunner { // NOTE(olafur): these exceptions appear when we await on futures. We unwrap // these exception in order to provide more helpful error messages. - private def rootCause(x: Throwable): Throwable = x match { + private[munit] def rootCause(x: Throwable): Throwable = x match { case _: ExceptionInInitializerError | _: ExecutionException if x.getCause != null => rootCause(x.getCause) From 038e96b719f20410210821b7302a2eb017c77e9b Mon Sep 17 00:00:00 2001 From: Andrew Valencik Date: Sat, 25 Jun 2022 14:52:54 -0400 Subject: [PATCH 4/8] Remove unused type aliases from PlatformCompat --- munit/jvm/src/main/scala/munit/internal/PlatformCompat.scala | 4 ---- .../native/src/main/scala/munit/internal/PlatformCompat.scala | 4 ---- 2 files changed, 8 deletions(-) diff --git a/munit/jvm/src/main/scala/munit/internal/PlatformCompat.scala b/munit/jvm/src/main/scala/munit/internal/PlatformCompat.scala index 276307a0..d8b85a31 100644 --- a/munit/jvm/src/main/scala/munit/internal/PlatformCompat.scala +++ b/munit/jvm/src/main/scala/munit/internal/PlatformCompat.scala @@ -69,8 +69,4 @@ object PlatformCompat { def isJS: Boolean = false def isNative: Boolean = false def getThisClassLoader: ClassLoader = this.getClass().getClassLoader() - - type InvocationTargetException = java.lang.reflect.InvocationTargetException - type UndeclaredThrowableException = - java.lang.reflect.UndeclaredThrowableException } diff --git a/munit/native/src/main/scala/munit/internal/PlatformCompat.scala b/munit/native/src/main/scala/munit/internal/PlatformCompat.scala index a4ab1294..c08636e4 100644 --- a/munit/native/src/main/scala/munit/internal/PlatformCompat.scala +++ b/munit/native/src/main/scala/munit/internal/PlatformCompat.scala @@ -56,8 +56,4 @@ object PlatformCompat { private var myClassLoader: ClassLoader = _ def setThisClassLoader(loader: ClassLoader): Unit = myClassLoader = loader def getThisClassLoader: ClassLoader = myClassLoader - - type InvocationTargetException = java.lang.reflect.InvocationTargetException - type UndeclaredThrowableException = - java.lang.reflect.UndeclaredThrowableException } From 86430de1a071273b9cd0acf57597dae568698c91 Mon Sep 17 00:00:00 2001 From: Andrew Valencik Date: Sat, 25 Jun 2022 14:58:17 -0400 Subject: [PATCH 5/8] Add note about bin compat on rootCause --- munit/shared/src/main/scala/munit/MUnitRunner.scala | 2 ++ 1 file changed, 2 insertions(+) diff --git a/munit/shared/src/main/scala/munit/MUnitRunner.scala b/munit/shared/src/main/scala/munit/MUnitRunner.scala index 7f6aff9e..418a5658 100644 --- a/munit/shared/src/main/scala/munit/MUnitRunner.scala +++ b/munit/shared/src/main/scala/munit/MUnitRunner.scala @@ -458,6 +458,8 @@ object MUnitRunner { // NOTE(olafur): these exceptions appear when we await on futures. We unwrap // these exception in order to provide more helpful error messages. + // NOTE(valencik): preserve binary compatibility as this util is used in + // downstream integration libraries. private[munit] def rootCause(x: Throwable): Throwable = x match { case _: ExceptionInInitializerError | _: ExecutionException if x.getCause != null => From faeee8a183267407d49147f275cd30458acf57f0 Mon Sep 17 00:00:00 2001 From: Andrew Valencik Date: Sat, 25 Jun 2022 15:08:44 -0400 Subject: [PATCH 6/8] Add tailrec to rootCause --- munit/shared/src/main/scala/munit/MUnitRunner.scala | 2 ++ 1 file changed, 2 insertions(+) diff --git a/munit/shared/src/main/scala/munit/MUnitRunner.scala b/munit/shared/src/main/scala/munit/MUnitRunner.scala index 418a5658..77457486 100644 --- a/munit/shared/src/main/scala/munit/MUnitRunner.scala +++ b/munit/shared/src/main/scala/munit/MUnitRunner.scala @@ -16,6 +16,7 @@ import org.junit.runner.notification.RunNotifier import java.lang.reflect.Modifier import java.util.concurrent.ExecutionException +import scala.annotation.tailrec import scala.collection.mutable import scala.concurrent.Await import scala.concurrent.ExecutionContext @@ -460,6 +461,7 @@ object MUnitRunner { // these exception in order to provide more helpful error messages. // NOTE(valencik): preserve binary compatibility as this util is used in // downstream integration libraries. + @tailrec private[munit] def rootCause(x: Throwable): Throwable = x match { case _: ExceptionInInitializerError | _: ExecutionException if x.getCause != null => From ddf112081c8937799c825bdf06607ede85a7d51f Mon Sep 17 00:00:00 2001 From: Andrew Valencik Date: Tue, 28 Jun 2022 08:45:17 -0400 Subject: [PATCH 7/8] Move rootCause to public Exceptions object --- .../src/main/scala/munit/Exceptions.scala | 17 +++++++++++++++++ .../src/main/scala/munit/MUnitRunner.scala | 18 ++---------------- 2 files changed, 19 insertions(+), 16 deletions(-) create mode 100644 munit/shared/src/main/scala/munit/Exceptions.scala diff --git a/munit/shared/src/main/scala/munit/Exceptions.scala b/munit/shared/src/main/scala/munit/Exceptions.scala new file mode 100644 index 00000000..550a436c --- /dev/null +++ b/munit/shared/src/main/scala/munit/Exceptions.scala @@ -0,0 +1,17 @@ +package munit + +import java.util.concurrent.ExecutionException +import scala.annotation.tailrec + +object Exceptions { + + // NOTE(olafur): these exceptions appear when we await on futures. We unwrap + // these exception in order to provide more helpful error messages. + @tailrec + def rootCause(x: Throwable): Throwable = x match { + case _: ExceptionInInitializerError | _: ExecutionException + if x.getCause != null => + rootCause(x.getCause) + case _ => x + } +} diff --git a/munit/shared/src/main/scala/munit/MUnitRunner.scala b/munit/shared/src/main/scala/munit/MUnitRunner.scala index 77457486..ce4c0ecc 100644 --- a/munit/shared/src/main/scala/munit/MUnitRunner.scala +++ b/munit/shared/src/main/scala/munit/MUnitRunner.scala @@ -15,8 +15,6 @@ import org.junit.runner.notification.Failure import org.junit.runner.notification.RunNotifier import java.lang.reflect.Modifier -import java.util.concurrent.ExecutionException -import scala.annotation.tailrec import scala.collection.mutable import scala.concurrent.Await import scala.concurrent.ExecutionContext @@ -292,7 +290,7 @@ class MUnitRunner(val cls: Class[_ <: Suite], newInstance: () => Suite) Future.successful(()) case NonFatal(ex) => trimStackTrace(ex) - val cause = MUnitRunner.rootCause(ex) + val cause = Exceptions.rootCause(ex) val failure = new Failure(description, cause) cause match { case _: AssumptionViolatedException => @@ -418,7 +416,7 @@ class MUnitRunner(val cls: Class[_ <: Suite], newInstance: () => Suite) notifier.fireTestStarted(description) trimStackTrace(ex) notifier.fireTestFailure( - new Failure(description, MUnitRunner.rootCause(ex)) + new Failure(description, Exceptions.rootCause(ex)) ) notifier.fireTestFinished(description) } @@ -456,16 +454,4 @@ object MUnitRunner { case nsme: NoSuchMethodException => false } } - - // NOTE(olafur): these exceptions appear when we await on futures. We unwrap - // these exception in order to provide more helpful error messages. - // NOTE(valencik): preserve binary compatibility as this util is used in - // downstream integration libraries. - @tailrec - private[munit] def rootCause(x: Throwable): Throwable = x match { - case _: ExceptionInInitializerError | _: ExecutionException - if x.getCause != null => - rootCause(x.getCause) - case _ => x - } } From de2997f21d39ded60c0006e9365188fd6a6616d5 Mon Sep 17 00:00:00 2001 From: Andrew Valencik Date: Tue, 28 Jun 2022 08:54:30 -0400 Subject: [PATCH 8/8] Bring back cross-platform compat for rootCause Revert "Make rootCause cross-platform without shims" This reverts commit 106fe8b5bd1ff1e548f43fd1764f2281865505f7. And commit 038e96b719f20410210821b7302a2eb017c77e9b. --- .../scala/munit/internal/InvocationTargetException.scala | 3 +++ munit/js/src/main/scala/munit/internal/PlatformCompat.scala | 4 ++++ .../scala/munit/internal/UndeclaredThrowableException.scala | 3 +++ .../jvm/src/main/scala/munit/internal/PlatformCompat.scala | 4 ++++ .../src/main/scala/munit/internal/PlatformCompat.scala | 4 ++++ munit/shared/src/main/scala/munit/Exceptions.scala | 6 +++++- 6 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 munit/js/src/main/scala/munit/internal/InvocationTargetException.scala create mode 100644 munit/js/src/main/scala/munit/internal/UndeclaredThrowableException.scala diff --git a/munit/js/src/main/scala/munit/internal/InvocationTargetException.scala b/munit/js/src/main/scala/munit/internal/InvocationTargetException.scala new file mode 100644 index 00000000..d83734e3 --- /dev/null +++ b/munit/js/src/main/scala/munit/internal/InvocationTargetException.scala @@ -0,0 +1,3 @@ +package munit.internal + +class InvocationTargetException extends java.lang.RuntimeException diff --git a/munit/js/src/main/scala/munit/internal/PlatformCompat.scala b/munit/js/src/main/scala/munit/internal/PlatformCompat.scala index 3c238de7..f5fb39dd 100644 --- a/munit/js/src/main/scala/munit/internal/PlatformCompat.scala +++ b/munit/js/src/main/scala/munit/internal/PlatformCompat.scala @@ -75,4 +75,8 @@ object PlatformCompat { private var myClassLoader: ClassLoader = _ def setThisClassLoader(loader: ClassLoader): Unit = myClassLoader = loader def getThisClassLoader: ClassLoader = myClassLoader + + type InvocationTargetException = munit.internal.InvocationTargetException + type UndeclaredThrowableException = + munit.internal.UndeclaredThrowableException } diff --git a/munit/js/src/main/scala/munit/internal/UndeclaredThrowableException.scala b/munit/js/src/main/scala/munit/internal/UndeclaredThrowableException.scala new file mode 100644 index 00000000..86497cb6 --- /dev/null +++ b/munit/js/src/main/scala/munit/internal/UndeclaredThrowableException.scala @@ -0,0 +1,3 @@ +package munit.internal + +class UndeclaredThrowableException extends java.lang.RuntimeException diff --git a/munit/jvm/src/main/scala/munit/internal/PlatformCompat.scala b/munit/jvm/src/main/scala/munit/internal/PlatformCompat.scala index d8b85a31..276307a0 100644 --- a/munit/jvm/src/main/scala/munit/internal/PlatformCompat.scala +++ b/munit/jvm/src/main/scala/munit/internal/PlatformCompat.scala @@ -69,4 +69,8 @@ object PlatformCompat { def isJS: Boolean = false def isNative: Boolean = false def getThisClassLoader: ClassLoader = this.getClass().getClassLoader() + + type InvocationTargetException = java.lang.reflect.InvocationTargetException + type UndeclaredThrowableException = + java.lang.reflect.UndeclaredThrowableException } diff --git a/munit/native/src/main/scala/munit/internal/PlatformCompat.scala b/munit/native/src/main/scala/munit/internal/PlatformCompat.scala index c08636e4..a4ab1294 100644 --- a/munit/native/src/main/scala/munit/internal/PlatformCompat.scala +++ b/munit/native/src/main/scala/munit/internal/PlatformCompat.scala @@ -56,4 +56,8 @@ object PlatformCompat { private var myClassLoader: ClassLoader = _ def setThisClassLoader(loader: ClassLoader): Unit = myClassLoader = loader def getThisClassLoader: ClassLoader = myClassLoader + + type InvocationTargetException = java.lang.reflect.InvocationTargetException + type UndeclaredThrowableException = + java.lang.reflect.UndeclaredThrowableException } diff --git a/munit/shared/src/main/scala/munit/Exceptions.scala b/munit/shared/src/main/scala/munit/Exceptions.scala index 550a436c..11709a5d 100644 --- a/munit/shared/src/main/scala/munit/Exceptions.scala +++ b/munit/shared/src/main/scala/munit/Exceptions.scala @@ -1,5 +1,8 @@ package munit +import munit.internal.PlatformCompat.InvocationTargetException +import munit.internal.PlatformCompat.UndeclaredThrowableException + import java.util.concurrent.ExecutionException import scala.annotation.tailrec @@ -9,7 +12,8 @@ object Exceptions { // these exception in order to provide more helpful error messages. @tailrec def rootCause(x: Throwable): Throwable = x match { - case _: ExceptionInInitializerError | _: ExecutionException + case _: InvocationTargetException | _: ExceptionInInitializerError | + _: UndeclaredThrowableException | _: ExecutionException if x.getCause != null => rootCause(x.getCause) case _ => x