diff --git a/munit/shared/src/main/scala/munit/Assertions.scala b/munit/shared/src/main/scala/munit/Assertions.scala index a6397f65..e8db68d2 100644 --- a/munit/shared/src/main/scala/munit/Assertions.scala +++ b/munit/shared/src/main/scala/munit/Assertions.scala @@ -160,6 +160,16 @@ trait Assertions extends MacroCompat.CompileErrorMacro { ) } + def failSuite( + message: String, + clues: Clues = new Clues(Nil) + )(implicit loc: Location): Nothing = { + throw new FailSuiteException( + munitFilterAnsi(munitLines.formatLine(loc, message, clues)), + loc + ) + } + private val munitCapturedClues: mutable.ListBuffer[Clue[_]] = mutable.ListBuffer.empty def munitCaptureClues[T](thunk: => T): (T, Clues) = diff --git a/munit/shared/src/main/scala/munit/FailSuiteException.scala b/munit/shared/src/main/scala/munit/FailSuiteException.scala new file mode 100644 index 00000000..4167b7dd --- /dev/null +++ b/munit/shared/src/main/scala/munit/FailSuiteException.scala @@ -0,0 +1,6 @@ +package munit + +class FailSuiteException( + override val message: String, + override val location: Location +) extends FailException(message, location) diff --git a/munit/shared/src/main/scala/munit/MUnitRunner.scala b/munit/shared/src/main/scala/munit/MUnitRunner.scala index 95d9c9c2..0857bf2e 100644 --- a/munit/shared/src/main/scala/munit/MUnitRunner.scala +++ b/munit/shared/src/main/scala/munit/MUnitRunner.scala @@ -31,6 +31,7 @@ class MUnitRunner(val cls: Class[_ <: Suite], newInstance: () => Suite) private val suiteDescription = Description.createSuiteDescription(cls) private implicit val ec: ExecutionContext = suite.munitExecutionContext @volatile private var filter: Filter = Filter.ALL + @volatile private var suiteAborted: Boolean = false val descriptions: mutable.Map[suite.Test, Description] = mutable.Map.empty[suite.Test, Description] val testNames: mutable.Set[String] = mutable.Set.empty[String] @@ -200,6 +201,16 @@ class MUnitRunner(val cls: Class[_ <: Suite], newInstance: () => Suite) if (!filter.shouldRun(description)) { return Future.successful(false) } + if (suiteAborted) { + notifier.fireTestAssumptionFailed( + new Failure( + description, + new FailSuiteException("Suite has been aborted", test.location) + ) + ) + return Future.successful(false) + } + notifier.fireTestStarted(description) val onError: PartialFunction[Throwable, Future[Unit]] = { case ex: AssumptionViolatedException => @@ -211,6 +222,9 @@ class MUnitRunner(val cls: Class[_ <: Suite], newInstance: () => Suite) ex match { case _: AssumptionViolatedException => notifier.fireTestAssumptionFailed(failure) + case _: FailSuiteException => + suiteAborted = true + notifier.fireTestFailure(failure) case _ => notifier.fireTestFailure(failure) } diff --git a/tests/shared/src/main/scala/munit/FailSuiteFrameworkSuite.scala b/tests/shared/src/main/scala/munit/FailSuiteFrameworkSuite.scala new file mode 100644 index 00000000..b22a9d36 --- /dev/null +++ b/tests/shared/src/main/scala/munit/FailSuiteFrameworkSuite.scala @@ -0,0 +1,25 @@ +package munit + +class FailSuiteFrameworkSuite extends FunSuite { + test("pass") { + // println("pass") + } + test("fail") { + failSuite("Oops, can not do anything.") + } + test(name = "not gonna run") { + // println("not pass") + } +} + +object FailSuiteFrameworkSuite + extends FrameworkTest( + classOf[FailSuiteFrameworkSuite], + """|==> success munit.FailSuiteFrameworkSuite.pass + |==> failure munit.FailSuiteFrameworkSuite.fail - /scala/munit/FailSuiteFrameworkSuite.scala:8 Oops, can not do anything. + |7: test("fail") { + |8: failSuite("Oops, can not do anything.") + |9: } + |==> skipped munit.FailSuiteFrameworkSuite.not gonna run - Suite has been aborted + |""".stripMargin + ) diff --git a/tests/shared/src/test/scala/munit/FrameworkSuite.scala b/tests/shared/src/test/scala/munit/FrameworkSuite.scala index cf4a3a07..6e8e2631 100644 --- a/tests/shared/src/test/scala/munit/FrameworkSuite.scala +++ b/tests/shared/src/test/scala/munit/FrameworkSuite.scala @@ -7,6 +7,7 @@ class FrameworkSuite extends BaseFrameworkSuite { CiOnlyFrameworkSuite, DiffProductFrameworkSuite, FailFrameworkSuite, + FailSuiteFrameworkSuite, TestNameFrameworkSuite, ScalaVersionFrameworkSuite, FixtureFrameworkSuite,