All Downloads are FREE. Search and download functionalities are using the official Maven repository.

zio.test.ZIOSpecAbstract.scala Maven / Gradle / Ivy

There is a newer version: 2.1.14
Show newest version
/*
 * Copyright 2021-2024 John A. De Goes and the ZIO 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 zio.test

import org.portablescala.reflect.annotation.EnableReflectiveInstantiation
import zio._
import zio.stacktracer.TracingImplicits.disableAutoTrace
import zio.test.render.ConsoleRenderer

@EnableReflectiveInstantiation
abstract class ZIOSpecAbstract extends ZIOApp with ZIOSpecAbstractVersionSpecific {
  self =>

  def spec: Spec[Environment with TestEnvironment with Scope, Any]

  def aspects: Chunk[TestAspectAtLeastR[Environment with TestEnvironment]] =
    Chunk(TestAspect.fibers, TestAspect.timeoutWarning(60.seconds))

  def bootstrap: ZLayer[Any, Any, Environment]

  final def run: ZIO[Environment with ZIOAppArgs with Scope, Any, Summary] = {
    implicit val trace = Trace.empty

    runSpec.provideSomeLayer[Environment with ZIOAppArgs with Scope](
      ZLayer.environment[Environment with ZIOAppArgs with Scope] +!+
        (liveEnvironment >>> TestEnvironment.live +!+ TestLogger.fromConsole(Console.ConsoleLive))
    )
  }

  final def <>(that: ZIOSpecAbstract)(implicit trace: Trace): ZIOSpecAbstract =
    new ZIOSpecAbstract {
      type Environment = self.Environment with that.Environment

      def bootstrap: ZLayer[Any, Any, Environment] =
        self.bootstrap +!+ that.bootstrap

      def spec: Spec[Environment with TestEnvironment with Scope, Any] =
        self.aspects.foldLeft(self.spec)(_ @@ _) + that.aspects.foldLeft(that.spec)(_ @@ _)

      def environmentTag: EnvironmentTag[Environment] = {
        implicit val selfTag: EnvironmentTag[self.Environment] = self.environmentTag
        implicit val thatTag: EnvironmentTag[that.Environment] = that.environmentTag
        val _                                                  = (selfTag, thatTag)
        EnvironmentTag[Environment]
      }

      override def aspects: Chunk[TestAspectAtLeastR[Environment with TestEnvironment]] =
        Chunk.empty
    }

  protected final def runSpec(implicit trace: Trace): ZIO[
    Environment with TestEnvironment with ZIOAppArgs with Scope,
    Throwable,
    Summary
  ] =
    for {
      args    <- ZIO.service[ZIOAppArgs]
      console <- ZIO.console
      testArgs = TestArgs.parse(args.getArgs.toArray)
      summary <- runSpecAsApp(spec, testArgs, console)
      _ <- ZIO.when(testArgs.printSummary) {
             console.printLine(testArgs.testRenderer.renderSummary(summary)).orDie
           }
      _ <- ZIO
             .when(summary.status == Summary.Failure) {
               ZIO.fail(new RuntimeException("Tests failed."))
             }
             .unless(testArgs.ignoreFailures)
    } yield summary

  /*
   * Regardless of test assertion or runtime failures, this method will always return a summary
   * capturing this information
   */
  private[zio] def runSpecAsApp(
    spec: Spec[Environment with TestEnvironment with Scope, Any],
    testArgs: TestArgs,
    console: Console,
    testEventHandler: ZTestEventHandler = ZTestEventHandler.silent
  )(implicit
    trace: Trace
  ): URIO[
    Environment with TestEnvironment with Scope,
    Summary
  ] = {
    val filteredSpec: Spec[Environment with TestEnvironment with Scope, Any] = FilteredSpec(spec, testArgs)

    for {
      runtime <-
        ZIO.runtime[
          TestEnvironment with Scope
        ]

      scopeEnv: ZEnvironment[Scope] = runtime.environment
      perTestLayer = (ZLayer.succeedEnvironment(scopeEnv) ++ liveEnvironment) >>>
                       (TestEnvironment.live ++ ZLayer.environment[Scope])

      executionEventSinkLayer = ExecutionEventSink.live(console, testArgs.testEventRenderer)
      environment            <- ZIO.environment[Environment]
      runner =
        TestRunner(
          TestExecutor
            .default[Environment, Any](
              ZLayer.succeedEnvironment(environment),
              perTestLayer,
              executionEventSinkLayer,
              testEventHandler
            )
        )
      randomId <- ZIO.withRandom(Random.RandomLive)(Random.nextInt).map("test_case_" + _)
      summary <-
        runner.run(randomId, aspects.foldLeft(filteredSpec)(_ @@ _) @@ TestAspect.fibers)
    } yield summary
  }

  private[zio] def runSpecWithSharedRuntimeLayer(
    fullyQualifiedName: String,
    spec: Spec[Environment with TestEnvironment with Scope, Any],
    testArgs: TestArgs,
    runtime: Runtime[_],
    testEventHandler: ZTestEventHandler,
    console: Console
  )(implicit
    trace: Trace
  ): UIO[Summary] = {
    val filteredSpec = FilteredSpec(spec, testArgs)

    val castedRuntime: Runtime[Environment with TestOutput] =
      runtime.asInstanceOf[Runtime[Environment with TestOutput]]

    TestRunner(
      TestExecutor
        .default[Environment, Any](
          ZLayer.succeedEnvironment(castedRuntime.environment),
          testEnvironment ++ Scope.default,
          ZLayer.succeedEnvironment(castedRuntime.environment) >>> ExecutionEventSink.live,
          testEventHandler
        )
    ).run(fullyQualifiedName, aspects.foldLeft(filteredSpec)(_ @@ _) @@ TestAspect.fibers)
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy