diff --git a/test-sbt/shared/src/main/scala/zio/test/sbt/BaseTestTask.scala b/test-sbt/shared/src/main/scala/zio/test/sbt/BaseTestTask.scala index 17bdc4a16402..c571132cf82c 100644 --- a/test-sbt/shared/src/main/scala/zio/test/sbt/BaseTestTask.scala +++ b/test-sbt/shared/src/main/scala/zio/test/sbt/BaseTestTask.scala @@ -27,9 +27,9 @@ abstract class BaseTestTask( protected def run(eventHandler: EventHandler): ZIO[TestLogger with Clock, Throwable, Unit] = for { spec <- specInstance.runSpec(FilteredSpec(specInstance.spec, args)) - summary <- SummaryBuilder.buildSummary(spec) + summary = SummaryBuilder.buildSummary(spec) _ <- sendSummary.provide(summary) - events <- ZTestEvent.from(spec, taskDef.fullyQualifiedName, taskDef.fingerprint) + events = ZTestEvent.from(spec, taskDef.fullyQualifiedName, taskDef.fingerprint) _ <- ZIO.foreach(events)(e => ZIO.effect(eventHandler.handle(e))) } yield () diff --git a/test-sbt/shared/src/main/scala/zio/test/sbt/ZTestEvent.scala b/test-sbt/shared/src/main/scala/zio/test/sbt/ZTestEvent.scala index 5e55cf4db772..47da38157980 100644 --- a/test-sbt/shared/src/main/scala/zio/test/sbt/ZTestEvent.scala +++ b/test-sbt/shared/src/main/scala/zio/test/sbt/ZTestEvent.scala @@ -2,8 +2,7 @@ package zio.test.sbt import sbt.testing._ -import zio.UIO -import zio.test.{ ExecutedSpec, Spec, TestFailure, TestSuccess } +import zio.test.{ ExecutedSpec, TestFailure, TestSuccess } final case class ZTestEvent( fullyQualifiedName: String, @@ -21,14 +20,11 @@ object ZTestEvent { executedSpec: ExecutedSpec[E], fullyQualifiedName: String, fingerprint: Fingerprint - ): UIO[Seq[ZTestEvent]] = - executedSpec.fold[UIO[Seq[ZTestEvent]]] { - case Spec.SuiteCase(_, results, _) => - results.use(UIO.collectAll(_).map(_.flatten)) - case Spec.TestCase(label, result, _) => - result.map { result => - Seq(ZTestEvent(fullyQualifiedName, new TestSelector(label), toStatus(result), None, 0, fingerprint)) - } + ): Seq[ZTestEvent] = + executedSpec.fold[Seq[ZTestEvent]] { + case ExecutedSpec.SuiteCase(_, results) => results.flatten + case ExecutedSpec.TestCase(label, result, _) => + Seq(ZTestEvent(fullyQualifiedName, new TestSelector(label), toStatus(result), None, 0, fingerprint)) } private def toStatus[E](result: Either[TestFailure[E], TestSuccess]) = result match { diff --git a/test-tests/shared/src/test/scala/zio/test/ReportingTestUtils.scala b/test-tests/shared/src/test/scala/zio/test/ReportingTestUtils.scala index fd457349a52e..8a06c8a2cfa4 100644 --- a/test-tests/shared/src/test/scala/zio/test/ReportingTestUtils.scala +++ b/test-tests/shared/src/test/scala/zio/test/ReportingTestUtils.scala @@ -59,7 +59,7 @@ object ReportingTestUtils { .provideLayer[Nothing, TestEnvironment, TestLogger with Clock]( TestLogger.fromConsole ++ TestClock.default ) - actualSummary <- SummaryBuilder.buildSummary(results) + actualSummary = SummaryBuilder.buildSummary(results) } yield actualSummary.summary private[this] def TestTestRunner(testEnvironment: Layer[Nothing, TestEnvironment]) = diff --git a/test-tests/shared/src/test/scala/zio/test/SpecSpec.scala b/test-tests/shared/src/test/scala/zio/test/SpecSpec.scala index 674dcaaaeaa9..1fe0feb75f09 100644 --- a/test-tests/shared/src/test/scala/zio/test/SpecSpec.scala +++ b/test-tests/shared/src/test/scala/zio/test/SpecSpec.scala @@ -69,8 +69,14 @@ object SpecSpec extends ZIOBaseSpec { ).provideLayerShared(ZLayer.succeed(43)) for { executedSpec <- execute(spec) - successes <- executedSpec.countTests(_.isRight).useNow - failures <- executedSpec.countTests(_.isLeft).useNow + successes = executedSpec.fold[Int] { + case ExecutedSpec.SuiteCase(_, counts) => counts.sum + case ExecutedSpec.TestCase(_, test, _) => if (test.isRight) 1 else 0 + } + failures = executedSpec.fold[Int] { + case ExecutedSpec.SuiteCase(_, counts) => counts.sum + case ExecutedSpec.TestCase(_, test, _) => if (test.isLeft) 1 else 0 + } } yield assert(successes)(equalTo(1)) && assert(failures)(equalTo(2)) } ), diff --git a/test-tests/shared/src/test/scala/zio/test/TestUtils.scala b/test-tests/shared/src/test/scala/zio/test/TestUtils.scala index c18a68203add..229557f97f24 100644 --- a/test-tests/shared/src/test/scala/zio/test/TestUtils.scala +++ b/test-tests/shared/src/test/scala/zio/test/TestUtils.scala @@ -1,7 +1,7 @@ package zio.test import zio.test.environment.TestEnvironment -import zio.{ ExecutionStrategy, UIO, ZIO } +import zio.{ ExecutionStrategy, UIO } object TestUtils { @@ -9,28 +9,26 @@ object TestUtils { TestExecutor.default(environment.testEnvironment).run(spec, ExecutionStrategy.Sequential) def forAllTests[E]( - execSpec: UIO[ExecutedSpec[E]] - )(f: Either[TestFailure[E], TestSuccess] => Boolean): UIO[Boolean] = - execSpec.flatMap { results => - results.forall { - case Spec.TestCase(_, test, _) => test.map(r => f(r)) - case _ => ZIO.succeed(true) - }.useNow + execSpec: ExecutedSpec[E] + )(f: Either[TestFailure[E], TestSuccess] => Boolean): Boolean = + execSpec.forall { + case ExecutedSpec.TestCase(_, test, _) => f(test) + case _ => true } - def isIgnored[E](spec: ZSpec[environment.TestEnvironment, E]): UIO[Boolean] = { - val execSpec = execute(spec) - forAllTests(execSpec) { - case Right(TestSuccess.Ignored) => true - case _ => false + def isIgnored[E](spec: ZSpec[environment.TestEnvironment, E]): UIO[Boolean] = + execute(spec).map { executedSpec => + forAllTests(executedSpec) { + case Right(TestSuccess.Ignored) => true + case _ => false + } } - } - def succeeded[E](spec: ZSpec[environment.TestEnvironment, E]): UIO[Boolean] = { - val execSpec = execute(spec) - forAllTests(execSpec) { - case Right(TestSuccess.Succeeded(_)) => true - case _ => false + def succeeded[E](spec: ZSpec[environment.TestEnvironment, E]): UIO[Boolean] = + execute(spec).map { executedSpec => + forAllTests(executedSpec) { + case Right(TestSuccess.Succeeded(_)) => true + case _ => false + } } - } } diff --git a/test/shared/src/main/scala/zio/test/DefaultTestReporter.scala b/test/shared/src/main/scala/zio/test/DefaultTestReporter.scala index 0edb07e7958f..c1e69b9486a9 100644 --- a/test/shared/src/main/scala/zio/test/DefaultTestReporter.scala +++ b/test/shared/src/main/scala/zio/test/DefaultTestReporter.scala @@ -29,103 +29,86 @@ import zio.test.RenderedResult.Status._ import zio.test.RenderedResult.{ CaseType, Status } import zio.test.mock.Expectation import zio.test.mock.internal.{ InvalidCall, MockException } -import zio.{ Cause, Has, UIO, URIO } +import zio.{ Cause, Has } object DefaultTestReporter { def render[E]( executedSpec: ExecutedSpec[E], testAnnotationRenderer: TestAnnotationRenderer - ): UIO[Seq[RenderedResult[String]]] = { + ): Seq[RenderedResult[String]] = { def loop( executedSpec: ExecutedSpec[E], depth: Int, ancestors: List[TestAnnotationMap] - ): UIO[Seq[RenderedResult[String]]] = + ): Seq[RenderedResult[String]] = executedSpec.caseValue match { - case c @ Spec.SuiteCase(label, executedSpecs, _) => - for { - specs <- executedSpecs.useNow - failures <- UIO.foreach(specs) { specs => - specs.exists { - case Spec.TestCase(_, test, _) => test.map(_.isLeft) - case _ => UIO.succeedNow(false) - }.useNow - } - annotations <- Spec(c).fold[UIO[TestAnnotationMap]] { - case Spec.SuiteCase(_, specs, _) => - specs.use(UIO.collectAll(_).map(_.foldLeft(TestAnnotationMap.empty)(_ ++ _))) - case Spec.TestCase(_, _, annotations) => UIO.succeedNow(annotations) - } - hasFailures = failures.exists(identity) - status = if (hasFailures) Failed else Passed - renderedLabel = if (specs.isEmpty) Seq.empty + case ExecutedSpec.SuiteCase(label, specs) => + val hasFailures = executedSpec.exists { + case ExecutedSpec.TestCase(_, test, _) => test.isLeft + case _ => false + } + val annotations = executedSpec.fold[TestAnnotationMap] { + case ExecutedSpec.SuiteCase(_, annotations) => annotations.foldLeft(TestAnnotationMap.empty)(_ ++ _) + case ExecutedSpec.TestCase(_, _, annotations) => annotations + } + val status = if (hasFailures) Failed else Passed + val renderedLabel = + if (specs.isEmpty) Seq.empty else if (hasFailures) Seq(renderFailureLabel(label, depth)) else Seq(renderSuccessLabel(label, depth)) - renderedAnnotations = testAnnotationRenderer.run(ancestors, annotations) - rest <- UIO.foreach(specs)(loop(_, depth + tabSize, annotations :: ancestors)).map(_.flatten) - } yield rendered(Suite, label, status, depth, (renderedLabel): _*) - .withAnnotations(renderedAnnotations) +: rest - case Spec.TestCase(label, result, annotations) => - result.map { result => - val renderedAnnotations = testAnnotationRenderer.run(ancestors, annotations) - val renderedResult = result match { - case Right(TestSuccess.Succeeded(_)) => - rendered(Test, label, Passed, depth, withOffset(depth)(green("+") + " " + label)) - case Right(TestSuccess.Ignored) => - rendered(Test, label, Ignored, depth) - case Left(TestFailure.Assertion(result)) => - result.fold(details => rendered(Test, label, Failed, depth, renderFailure(label, depth, details): _*))( - _ && _, - _ || _, - !_ - ) - case Left(TestFailure.Runtime(cause)) => - rendered( - Test, - label, - Failed, - depth, - (Seq(renderFailureLabel(label, depth)) ++ Seq(renderCause(cause, depth))): _* - ) - } - Seq(renderedResult.withAnnotations(renderedAnnotations)) + val renderedAnnotations = testAnnotationRenderer.run(ancestors, annotations) + val rest = specs.flatMap(loop(_, depth + tabSize, annotations :: ancestors)) + rendered(Suite, label, status, depth, (renderedLabel): _*).withAnnotations(renderedAnnotations) +: rest + case ExecutedSpec.TestCase(label, result, annotations) => + val renderedAnnotations = testAnnotationRenderer.run(ancestors, annotations) + val renderedResult = result match { + case Right(TestSuccess.Succeeded(_)) => + rendered(Test, label, Passed, depth, withOffset(depth)(green("+") + " " + label)) + case Right(TestSuccess.Ignored) => + rendered(Test, label, Ignored, depth) + case Left(TestFailure.Assertion(result)) => + result.fold(details => rendered(Test, label, Failed, depth, renderFailure(label, depth, details): _*))( + _ && _, + _ || _, + !_ + ) + case Left(TestFailure.Runtime(cause)) => + rendered( + Test, + label, + Failed, + depth, + (Seq(renderFailureLabel(label, depth)) ++ Seq(renderCause(cause, depth))): _* + ) } + Seq(renderedResult.withAnnotations(renderedAnnotations)) } loop(executedSpec, 0, List.empty) } def apply[E](testAnnotationRenderer: TestAnnotationRenderer): TestReporter[E] = { (duration: Duration, executedSpec: ExecutedSpec[E]) => - for { - rendered <- render(executedSpec, testAnnotationRenderer).map(_.flatMap(_.rendered)) - stats <- logStats(duration, executedSpec) - _ <- TestLogger.logLine((rendered ++ Seq(stats)).mkString("\n")) - } yield () + val rendered = render(executedSpec, testAnnotationRenderer).flatMap(_.rendered) + val stats = logStats(duration, executedSpec) + TestLogger.logLine((rendered ++ Seq(stats)).mkString("\n")) } - private def logStats[E](duration: Duration, executedSpec: ExecutedSpec[E]): URIO[TestLogger, String] = { - def loop(executedSpec: ExecutedSpec[E]): UIO[(Int, Int, Int)] = - executedSpec.caseValue match { - case Spec.SuiteCase(_, executedSpecs, _) => - for { - specs <- executedSpecs.useNow - stats <- UIO.foreach(specs)(loop) - } yield stats.foldLeft((0, 0, 0)) { - case ((x1, x2, x3), (y1, y2, y3)) => (x1 + y1, x2 + y2, x3 + y3) - } - case Spec.TestCase(_, result, _) => - result.map { - case Left(_) => (0, 0, 1) - case Right(TestSuccess.Succeeded(_)) => (1, 0, 0) - case Right(TestSuccess.Ignored) => (0, 1, 0) - } - } - for { - stats <- loop(executedSpec) - (success, ignore, failure) = stats - total = success + ignore + failure - } yield cyan( + private def logStats[E](duration: Duration, executedSpec: ExecutedSpec[E]): String = { + val (success, ignore, failure) = executedSpec.fold[(Int, Int, Int)] { + case ExecutedSpec.SuiteCase(_, stats) => + stats.foldLeft((0, 0, 0)) { + case ((x1, x2, x3), (y1, y2, y3)) => (x1 + y1, x2 + y2, x3 + y3) + } + case ExecutedSpec.TestCase(_, result, _) => + result match { + case Left(_) => (0, 0, 1) + case Right(TestSuccess.Succeeded(_)) => (1, 0, 0) + case Right(TestSuccess.Ignored) => (0, 1, 0) + } + } + val total = success + ignore + failure + cyan( s"Ran $total test${if (total == 1) "" else "s"} in ${duration.render}: $success succeeded, $ignore ignored, $failure failed" ) } diff --git a/test/shared/src/main/scala/zio/test/ExecutedSpec.scala b/test/shared/src/main/scala/zio/test/ExecutedSpec.scala new file mode 100644 index 000000000000..9a9cb6850456 --- /dev/null +++ b/test/shared/src/main/scala/zio/test/ExecutedSpec.scala @@ -0,0 +1,107 @@ +package zio.test + +import zio.test.ExecutedSpec._ + +/** + * An `ExecutedSpec` is a spec that has been run to produce test results. + */ +final case class ExecutedSpec[+E](caseValue: SpecCase[E, ExecutedSpec[E]]) { self => + + /** + * Determines if any node in the spec is satisfied by the given predicate. + */ + def exists(f: SpecCase[E, Boolean] => Boolean): Boolean = + fold[Boolean] { + case c @ SuiteCase(_, specs) => specs.exists(identity) || f(c) + case c @ TestCase(_, _, _) => f(c) + } + + /** + * Folds over all nodes to produce a final result. + */ + def fold[Z](f: SpecCase[E, Z] => Z): Z = + caseValue match { + case SuiteCase(label, specs) => f(SuiteCase(label, specs.map(_.fold(f)))) + case t @ TestCase(_, _, _) => f(t) + } + + /** + * Determines if all nodes in the spec are satisfied by the given predicate. + */ + def forall(f: SpecCase[E, Boolean] => Boolean): Boolean = + fold[Boolean] { + case c @ SuiteCase(_, specs) => specs.forall(identity) && f(c) + case c @ TestCase(_, _, _) => f(c) + } + + /** + * Computes the size of the spec, i.e. the number of tests in the spec. + */ + def size: Int = + fold[Int] { + case SuiteCase(_, counts) => counts.sum + case TestCase(_, _, _) => 1 + } + + /** + * Transforms the spec one layer at a time. + */ + def transform[E1](f: SpecCase[E, ExecutedSpec[E1]] => SpecCase[E1, ExecutedSpec[E1]]): ExecutedSpec[E1] = + caseValue match { + case SuiteCase(label, specs) => ExecutedSpec(f(SuiteCase(label, specs.map(_.transform(f))))) + case t @ TestCase(_, _, _) => ExecutedSpec(f(t)) + } + + /** + * Transforms the spec statefully, one layer at a time. + */ + def transformAccum[E1, Z]( + z0: Z + )(f: (Z, SpecCase[E, ExecutedSpec[E1]]) => (Z, SpecCase[E1, ExecutedSpec[E1]])): (Z, ExecutedSpec[E1]) = + caseValue match { + case SuiteCase(label, specs) => + val (z, specs1) = + specs.foldLeft(z0 -> Vector.empty[ExecutedSpec[E1]]) { + case ((z, vector), spec) => + val (z1, spec1) = spec.transformAccum(z)(f) + + z1 -> (vector :+ spec1) + } + + val (z1, caseValue) = f(z, SuiteCase(label, specs1)) + + z1 -> ExecutedSpec(caseValue) + case t @ TestCase(_, _, _) => + val (z, caseValue) = f(z0, t) + z -> ExecutedSpec(caseValue) + } +} + +object ExecutedSpec { + + trait SpecCase[+E, +A] { self => + def map[B](f: A => B): SpecCase[E, B] = + self match { + case SuiteCase(label, specs) => SuiteCase(label, specs.map(f)) + case TestCase(label, test, annotations) => TestCase(label, test, annotations) + } + } + + final case class SuiteCase[+A](label: String, specs: Vector[A]) extends SpecCase[Nothing, A] + + final case class TestCase[+E]( + label: String, + test: Either[TestFailure[E], TestSuccess], + annotations: TestAnnotationMap + ) extends SpecCase[E, Nothing] + + def suite[E](label: String, specs: Vector[ExecutedSpec[E]]): ExecutedSpec[E] = + ExecutedSpec(SuiteCase(label, specs)) + + def test[E]( + label: String, + test: Either[TestFailure[E], TestSuccess], + annotations: TestAnnotationMap + ): ExecutedSpec[E] = + ExecutedSpec(TestCase(label, test, annotations)) +} diff --git a/test/shared/src/main/scala/zio/test/RunnableSpec.scala b/test/shared/src/main/scala/zio/test/RunnableSpec.scala index b2c4c25c17c1..5925a7652b0b 100644 --- a/test/shared/src/main/scala/zio/test/RunnableSpec.scala +++ b/test/shared/src/main/scala/zio/test/RunnableSpec.scala @@ -17,8 +17,7 @@ package zio.test import zio.clock.Clock -import zio.test.Spec.TestCase -import zio.{ Has, UIO, URIO } +import zio.{ Has, URIO } /** * A `RunnableSpec` has a main function and can be run by the JVM / Scala.js. @@ -30,11 +29,11 @@ abstract class RunnableSpec[R <: Has[_], E] extends AbstractRunnableSpec { private def run(spec: ZSpec[Environment, Failure]): URIO[TestLogger with Clock, Int] = for { results <- runSpec(spec) - hasFailures <- results.exists { - case TestCase(_, test, _) => test.map(_.isLeft) - case _ => UIO.succeedNow(false) - }.useNow - summary <- SummaryBuilder.buildSummary(results) + hasFailures = results.exists { + case ExecutedSpec.TestCase(_, test, _) => test.isLeft + case _ => false + } + summary = SummaryBuilder.buildSummary(results) _ <- TestLogger.logLine(summary.summary) } yield if (hasFailures) 1 else 0 diff --git a/test/shared/src/main/scala/zio/test/SummaryBuilder.scala b/test/shared/src/main/scala/zio/test/SummaryBuilder.scala index 5155766d5def..e517ae8c1dc3 100644 --- a/test/shared/src/main/scala/zio/test/SummaryBuilder.scala +++ b/test/shared/src/main/scala/zio/test/SummaryBuilder.scala @@ -1,59 +1,37 @@ package zio.test -import zio.test.Spec._ -import zio.{ UIO, ZIO } - object SummaryBuilder { - def buildSummary[E](executedSpec: ExecutedSpec[E]): UIO[Summary] = - for { - success <- countTestResults(executedSpec) { - case Right(TestSuccess.Succeeded(_)) => true - case _ => false - } - fail <- countTestResults(executedSpec)(_.isLeft) - ignore <- countTestResults(executedSpec) { - case Right(TestSuccess.Ignored) => true - case _ => false - } - failures <- extractFailures(executedSpec) - rendered <- ZIO.foreach(failures)(DefaultTestReporter.render(_, TestAnnotationRenderer.silent)) - } yield Summary(success, fail, ignore, rendered.flatten.flatMap(_.rendered).mkString("\n")) + def buildSummary[E](executedSpec: ExecutedSpec[E]): Summary = { + val success = countTestResults(executedSpec) { + case Right(TestSuccess.Succeeded(_)) => true + case _ => false + } + val fail = countTestResults(executedSpec)(_.isLeft) + val ignore = countTestResults(executedSpec) { + case Right(TestSuccess.Ignored) => true + case _ => false + } + val failures = extractFailures(executedSpec) + val rendered = failures + .flatMap(DefaultTestReporter.render(_, TestAnnotationRenderer.silent)) + .flatMap(_.rendered) + .mkString("\n") + Summary(success, fail, ignore, rendered) + } private def countTestResults[E]( executedSpec: ExecutedSpec[E] - )(pred: Either[TestFailure[E], TestSuccess] => Boolean): UIO[Int] = - executedSpec.fold[UIO[Int]] { - case SuiteCase(_, counts, _) => counts.use(ZIO.collectAll(_).map(_.sum)) - case TestCase(_, test, _) => - test.map(r => if (pred(r)) 1 else 0) + )(pred: Either[TestFailure[E], TestSuccess] => Boolean): Int = + executedSpec.fold[Int] { + case ExecutedSpec.SuiteCase(_, counts) => counts.sum + case ExecutedSpec.TestCase(_, test, _) => if (pred(test)) 1 else 0 } - private def extractFailures[E](executedSpec: ExecutedSpec[E]): UIO[Seq[ExecutedSpec[E]]] = { - def ifM[A](condition: UIO[Boolean])(success: UIO[A])(failure: UIO[A]): UIO[A] = - condition.flatMap(result => if (result) success else failure) - - def append[A](collection: UIO[Seq[A]], item: A): UIO[Seq[A]] = collection.map(_ :+ item) - - def hasFailures(spec: ExecutedSpec[E]): UIO[Boolean] = - spec.exists { - case Spec.TestCase(_, test, _) => test.map(_.isLeft) - case _ => UIO.succeedNow(false) - }.useNow - - def loop(current: ExecutedSpec[E], accM: UIO[Seq[ExecutedSpec[E]]]): UIO[Seq[ExecutedSpec[E]]] = - ifM(hasFailures(current)) { - current.caseValue match { - case suite @ Spec.SuiteCase(_, specs, _) => - val newSpecs = specs.use(ZIO.foreach(_)(extractFailures).map(_.flatten.toVector)) - append(accM, Spec(suite.copy(specs = newSpecs.toManaged_))) - - case Spec.TestCase(_, _, _) => - append(accM, current) - } - } { - accM - } - - loop(executedSpec, UIO.succeedNow(Vector.empty[ExecutedSpec[E]])) - } + private def extractFailures[E](executedSpec: ExecutedSpec[E]): Seq[ExecutedSpec[E]] = + executedSpec.fold[Seq[ExecutedSpec[E]]] { + case ExecutedSpec.SuiteCase(label, specs) => + val newSpecs = specs.flatten + if (newSpecs.nonEmpty) Seq(ExecutedSpec(ExecutedSpec.SuiteCase(label, newSpecs))) else Seq.empty + case c @ ExecutedSpec.TestCase(_, test, _) => if (test.isLeft) Seq(ExecutedSpec(c)) else Seq.empty + } } diff --git a/test/shared/src/main/scala/zio/test/TestExecutor.scala b/test/shared/src/main/scala/zio/test/TestExecutor.scala index 139f964c4037..efcf1b84c143 100644 --- a/test/shared/src/main/scala/zio/test/TestExecutor.scala +++ b/test/shared/src/main/scala/zio/test/TestExecutor.scala @@ -43,15 +43,15 @@ object TestExecutor { case (success, annotations) => ZIO.succeedNow((Right(success), annotations)) } ) - .use(_.fold[UIO[ExecutedSpec[E]]] { - case Spec.SuiteCase(label, specs, exec) => - UIO.succeedNow(Spec.suite(label, specs.mapM(UIO.collectAll(_)).map(_.toVector), exec)) - case Spec.TestCase(label, test, annotations) => + .use(_.foldM[Any, Nothing, ExecutedSpec[E]](defExec) { + case Spec.SuiteCase(label, specs, _) => + specs.map(specs => ExecutedSpec.suite(label, specs)) + case Spec.TestCase(label, test, staticAnnotations) => test.map { - case (result, annotations1) => - Spec.test(label, UIO.succeedNow(result), annotations ++ annotations1) - } - }) + case (result, dynamicAnnotations) => + ExecutedSpec.test(label, result, staticAnnotations ++ dynamicAnnotations) + }.toManaged_ + }.useNow) val environment = env } } diff --git a/test/shared/src/main/scala/zio/test/package.scala b/test/shared/src/main/scala/zio/test/package.scala index a9221cf8a3b8..15aa1b14eb58 100644 --- a/test/shared/src/main/scala/zio/test/package.scala +++ b/test/shared/src/main/scala/zio/test/package.scala @@ -118,16 +118,6 @@ package object test extends CompileVariants { */ type ZSpec[-R, +E] = Spec[R, TestFailure[E], TestSuccess] - /** - * An `ExecutedResult[E] is either a `TestSuccess` or a `TestFailure[E]`. - */ - type ExecutedResult[+E] = Either[TestFailure[E], TestSuccess] - - /** - * An `ExecutedSpec` is a spec that has been run to produce test results. - */ - type ExecutedSpec[+E] = Spec[Any, Nothing, ExecutedResult[E]] - /** * An `Annotated[A]` contains a value of type `A` along with zero or more * test annotations.