diff --git a/core-tests/shared/src/test/scala/zio/ZIOBaseSpec.scala b/core-tests/shared/src/test/scala/zio/ZIOBaseSpec.scala index a63660cf8696..c4188b1a3f24 100644 --- a/core-tests/shared/src/test/scala/zio/ZIOBaseSpec.scala +++ b/core-tests/shared/src/test/scala/zio/ZIOBaseSpec.scala @@ -5,7 +5,14 @@ import zio.test._ import scala.annotation.tailrec trait ZIOBaseSpec extends DefaultRunnableSpec { - override def aspects: List[TestAspectAtLeastR[Has[Live]]] = + override def aspects: List[TestAspect.WithOut[ + Nothing, + TestEnvironment, + Nothing, + Any, + ({ type OutEnv[Env] = Env })#OutEnv, + ({ type OutErr[Err] = Err })#OutErr + ]] = if (TestPlatform.isJVM) List(TestAspect.timeout(120.seconds)) else List(TestAspect.sequential, TestAspect.timeout(120.seconds)) @@ -30,7 +37,14 @@ trait ZIOBaseSpec extends DefaultRunnableSpec { case object supervision extends ZIOTag { override val value = "supervision" } } - def zioTag(zioTag: ZIOTag, zioTags: ZIOTag*): TestAspectPoly = { + def zioTag(zioTag: ZIOTag, zioTags: ZIOTag*): TestAspect.WithOut[ + Nothing, + Any, + Nothing, + Any, + ({ type OutEnv[Env] = Env })#OutEnv, + ({ type OutErr[Err] = Err })#OutErr + ] = { val tags = zioTags.map(_.value) ++ getSubTags(zioTag) ++ zioTags.flatMap(getSubTags) TestAspect.tag(zioTag.value, tags.distinct: _*) } diff --git a/core/shared/src/main/scala/zio/ZCompose.scala b/core/shared/src/main/scala/zio/ZCompose.scala new file mode 100644 index 000000000000..1bee952775ad --- /dev/null +++ b/core/shared/src/main/scala/zio/ZCompose.scala @@ -0,0 +1,191 @@ +/* + * Copyright 2017-2021 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 + +trait ZCompose[+LeftLower, -LeftUpper, LeftOut[In], +RightLower, -RightUpper, RightOut[In]] { + type Lower + type Upper + type Out[In] +} + +object ZCompose extends ComposeLowPriorityImplicits { + type WithOut[LeftLower, LeftUpper, LeftOut[In], RightLower, RightUpper, RightOut[In], Lower0, Upper0, Out0[In]] = + ZCompose[LeftLower, LeftUpper, LeftOut, RightLower, RightUpper, RightOut] { + type Lower = Lower0 + type Upper = Upper0 + type Out[In] = Out0[In] + } + + implicit def compose[ + LeftLower, + LeftUpper, + LeftOut >: RightLower <: RightUpper, + RightLower, + RightUpper, + RightOut + ]: ZCompose.WithOut[ + LeftLower, + LeftUpper, + ({ type Out[In] = LeftOut })#Out, + RightLower, + RightUpper, + ({ type Out[In] = RightOut })#Out, + LeftLower, + LeftUpper, + ({ type Out[In] = RightOut })#Out + ] = + new ZCompose[ + LeftLower, + LeftUpper, + ({ type Out[In] = LeftOut })#Out, + RightLower, + RightUpper, + ({ type Out[In] = RightOut })#Out + ] { + type Lower = LeftLower + type Upper = LeftUpper + type Out[In] = RightOut + } + + implicit def identity[LeftLower <: RightLower, LeftUpper, RightLower, RightUpper]: ZCompose.WithOut[ + LeftLower, + LeftUpper, + Identity, + RightLower, + RightUpper, + Identity, + RightLower, + LeftUpper with RightUpper, + Identity + ] = + new ZCompose[ + LeftLower, + LeftUpper, + Identity, + RightLower, + RightUpper, + Identity + ] { + type Lower = RightLower + type Upper = LeftUpper with RightUpper + type Out[In] = In + } + + implicit def leftIdentity[LeftLower <: RightLower, LeftUpper, RightLower, RightUpper, RightOut]: ZCompose.WithOut[ + LeftLower, + LeftUpper, + Identity, + RightLower, + RightUpper, + ({ type Out[In] = RightOut })#Out, + RightLower, + LeftUpper with RightUpper, + ({ type Out[In] = RightOut })#Out + ] = + new ZCompose[ + LeftLower, + LeftUpper, + Identity, + RightLower, + RightUpper, + ({ type Out[In] = RightOut })#Out + ] { + type Lower = RightLower + type Upper = LeftUpper with RightUpper + type Out[In] = RightOut + } + + implicit def rightIdentity[LeftLower, LeftUpper, LeftOut >: RightLower <: RightUpper, RightLower, RightUpper] + : ZCompose.WithOut[ + LeftLower, + LeftUpper, + ({ type Out[In] = LeftOut })#Out, + RightLower, + RightUpper, + Identity, + LeftLower, + LeftUpper, + ({ type Out[In] = LeftOut })#Out + ] = + new ZCompose[ + LeftLower, + LeftUpper, + ({ type Out[In] = LeftOut })#Out, + RightLower, + RightUpper, + Identity + ] { + type Lower = LeftLower + type Upper = LeftUpper + type Out[In] = LeftOut + } +} + +trait ComposeLowPriorityImplicits { + + type Identity[A] = A + + implicit def identityLowPriority[LeftLowerElem, LeftUpperElem, RightLowerElem <: LeftLowerElem, RightUpperElem] + : ZCompose.WithOut[ + LeftLowerElem, + LeftUpperElem, + Identity, + RightLowerElem, + RightUpperElem, + Identity, + LeftLowerElem, + LeftUpperElem with RightUpperElem, + Identity + ] = + new ZCompose[ + LeftLowerElem, + LeftUpperElem, + Identity, + RightLowerElem, + RightUpperElem, + Identity + ] { + type Lower = LeftLowerElem + type Upper = LeftUpperElem with RightUpperElem + type Out[In] = In + } + + implicit def leftIdentityLowPriority[LeftLower, LeftUpper, RightLower <: LeftLower, RightUpper, RightOut] + : ZCompose.WithOut[ + LeftLower, + LeftUpper, + Identity, + RightLower, + RightUpper, + ({ type Out[In] = RightOut })#Out, + LeftLower, + LeftUpper with RightUpper, + ({ type Out[In] = RightOut })#Out + ] = + new ZCompose[ + LeftLower, + LeftUpper, + Identity, + RightLower, + RightUpper, + ({ type Out[In] = RightOut })#Out + ] { + type Lower = LeftLower + type Upper = LeftUpper with RightUpper + type Out[In] = RightOut + } +} diff --git a/streams-tests/jvm/src/test/scala/zio/stream/ZPipelinePlatformSpecificSpec.scala b/streams-tests/jvm/src/test/scala/zio/stream/ZPipelinePlatformSpecificSpec.scala index efe67e6008eb..63056dbd2680 100644 --- a/streams-tests/jvm/src/test/scala/zio/stream/ZPipelinePlatformSpecificSpec.scala +++ b/streams-tests/jvm/src/test/scala/zio/stream/ZPipelinePlatformSpecificSpec.scala @@ -8,7 +8,14 @@ import zio.test.Assertion._ import java.util.zip.Deflater object ZPipelinePlatformSpecificSpec extends ZIOBaseSpec { - override def aspects: List[TestAspectAtLeastR[Has[Live]]] = + override def aspects: List[TestAspect.WithOut[ + Nothing, + TestEnvironment, + Nothing, + Any, + ({ type OutEnv[Env] = Env })#OutEnv, + ({ type OutErr[Err] = Err })#OutErr + ]] = List(TestAspect.timeout(300.seconds)) def spec: ZSpec[Environment, Failure] = suite("ZPipeline JVM")( diff --git a/streams/shared/src/main/scala-2.11-2.12/zio/stream/ZPipelineVersionSpecific.scala b/streams/shared/src/main/scala-2.11-2.12/zio/stream/ZPipelineVersionSpecific.scala index b6b710237287..3b5dc023a69a 100644 --- a/streams/shared/src/main/scala-2.11-2.12/zio/stream/ZPipelineVersionSpecific.scala +++ b/streams/shared/src/main/scala-2.11-2.12/zio/stream/ZPipelineVersionSpecific.scala @@ -23,7 +23,6 @@ import scala.annotation.unchecked.uncheckedVariance trait ZPipelineVersionSpecific[+LowerEnv, -UpperEnv, +LowerErr, -UpperErr, +LowerElem, -UpperElem] { self: ZPipeline[LowerEnv, UpperEnv, LowerErr, UpperErr, LowerElem, UpperElem] => - import ZPipeline._ /** * Composes two pipelines into one pipeline, by first applying the @@ -40,9 +39,9 @@ trait ZPipelineVersionSpecific[+LowerEnv, -UpperEnv, +LowerErr, -UpperErr, +Lowe UpperElem2 ] )(implicit - composeEnv: Compose[LowerEnv2, UpperEnv2, that.OutEnv, LowerEnv, UpperEnv, OutEnv] @uncheckedVariance, - composeErr: Compose[LowerErr2, UpperErr2, that.OutErr, LowerErr, UpperErr, OutErr] @uncheckedVariance, - composeElem: Compose[LowerElem2, UpperElem2, that.OutElem, LowerElem, UpperElem, OutElem] @uncheckedVariance + composeEnv: ZCompose[LowerEnv2, UpperEnv2, that.OutEnv, LowerEnv, UpperEnv, OutEnv] @uncheckedVariance, + composeErr: ZCompose[LowerErr2, UpperErr2, that.OutErr, LowerErr, UpperErr, OutErr] @uncheckedVariance, + composeElem: ZCompose[LowerElem2, UpperElem2, that.OutElem, LowerElem, UpperElem, OutElem] @uncheckedVariance ): ZPipeline.WithOut[ composeEnv.Lower, composeEnv.Upper, @@ -93,9 +92,9 @@ trait ZPipelineVersionSpecific[+LowerEnv, -UpperEnv, +LowerErr, -UpperErr, +Lowe UpperElem2 ] )(implicit - composeEnv: Compose[LowerEnv, UpperEnv, OutEnv, LowerEnv2, UpperEnv2, that.OutEnv] @uncheckedVariance, - composeErr: Compose[LowerErr, UpperErr, OutErr, LowerErr2, UpperErr2, that.OutErr] @uncheckedVariance, - composeElem: Compose[LowerElem, UpperElem, OutElem, LowerElem2, UpperElem2, that.OutElem] @uncheckedVariance + composeEnv: ZCompose[LowerEnv, UpperEnv, OutEnv, LowerEnv2, UpperEnv2, that.OutEnv] @uncheckedVariance, + composeErr: ZCompose[LowerErr, UpperErr, OutErr, LowerErr2, UpperErr2, that.OutErr] @uncheckedVariance, + composeElem: ZCompose[LowerElem, UpperElem, OutElem, LowerElem2, UpperElem2, that.OutElem] @uncheckedVariance ): ZPipeline.WithOut[ composeEnv.Lower, composeEnv.Upper, @@ -146,9 +145,9 @@ trait ZPipelineVersionSpecific[+LowerEnv, -UpperEnv, +LowerErr, -UpperErr, +Lowe UpperElem2 ] )(implicit - composeEnv: Compose[LowerEnv, UpperEnv, OutEnv, LowerEnv2, UpperEnv2, that.OutEnv] @uncheckedVariance, - composeErr: Compose[LowerErr, UpperErr, OutErr, LowerErr2, UpperErr2, that.OutErr] @uncheckedVariance, - composeElem: Compose[LowerElem, UpperElem, OutElem, LowerElem2, UpperElem2, that.OutElem] @uncheckedVariance + composeEnv: ZCompose[LowerEnv, UpperEnv, OutEnv, LowerEnv2, UpperEnv2, that.OutEnv] @uncheckedVariance, + composeErr: ZCompose[LowerErr, UpperErr, OutErr, LowerErr2, UpperErr2, that.OutErr] @uncheckedVariance, + composeElem: ZCompose[LowerElem, UpperElem, OutElem, LowerElem2, UpperElem2, that.OutElem] @uncheckedVariance ): ZPipeline.WithOut[ composeEnv.Lower, composeEnv.Upper, @@ -197,9 +196,9 @@ trait ZPipelineVersionSpecific[+LowerEnv, -UpperEnv, +LowerErr, -UpperErr, +Lowe UpperElem2 ] )(implicit - composeEnv: Compose[LowerEnv, UpperEnv, OutEnv, LowerEnv2, UpperEnv2, that.OutEnv] @uncheckedVariance, - composeErr: Compose[LowerErr, UpperErr, OutErr, LowerErr2, UpperErr2, that.OutErr] @uncheckedVariance, - composeElem: Compose[LowerElem, UpperElem, OutElem, LowerElem2, UpperElem2, that.OutElem] @uncheckedVariance + composeEnv: ZCompose[LowerEnv, UpperEnv, OutEnv, LowerEnv2, UpperEnv2, that.OutEnv] @uncheckedVariance, + composeErr: ZCompose[LowerErr, UpperErr, OutErr, LowerErr2, UpperErr2, that.OutErr] @uncheckedVariance, + composeElem: ZCompose[LowerElem, UpperElem, OutElem, LowerElem2, UpperElem2, that.OutElem] @uncheckedVariance ): ZPipeline.WithOut[ composeEnv.Lower, composeEnv.Upper, @@ -248,9 +247,9 @@ trait ZPipelineVersionSpecific[+LowerEnv, -UpperEnv, +LowerErr, -UpperErr, +Lowe UpperElem2 ] )(implicit - composeEnv: Compose[LowerEnv2, UpperEnv2, that.OutEnv, LowerEnv, UpperEnv, OutEnv] @uncheckedVariance, - composeErr: Compose[LowerErr2, UpperErr2, that.OutErr, LowerErr, UpperErr, OutErr] @uncheckedVariance, - composeElem: Compose[LowerElem2, UpperElem2, that.OutElem, LowerElem, UpperElem, OutElem] @uncheckedVariance + composeEnv: ZCompose[LowerEnv2, UpperEnv2, that.OutEnv, LowerEnv, UpperEnv, OutEnv] @uncheckedVariance, + composeErr: ZCompose[LowerErr2, UpperErr2, that.OutErr, LowerErr, UpperErr, OutErr] @uncheckedVariance, + composeElem: ZCompose[LowerElem2, UpperElem2, that.OutElem, LowerElem, UpperElem, OutElem] @uncheckedVariance ): ZPipeline.WithOut[ composeEnv.Lower, composeEnv.Upper, diff --git a/streams/shared/src/main/scala-2.13+/zio/stream/ZPipelineCompanionVersionSpecific.scala b/streams/shared/src/main/scala-2.13+/zio/stream/ZPipelineCompanionVersionSpecific.scala index 259d45c2f3a5..eae63684c418 100644 --- a/streams/shared/src/main/scala-2.13+/zio/stream/ZPipelineCompanionVersionSpecific.scala +++ b/streams/shared/src/main/scala-2.13+/zio/stream/ZPipelineCompanionVersionSpecific.scala @@ -20,7 +20,6 @@ import zio._ import zio.stacktracer.TracingImplicits.disableAutoTrace trait ZPipelineCompanionVersionSpecific { - import ZPipeline._ implicit final class ZPipelineSyntax[LowerEnv, UpperEnv, LowerErr, UpperErr, LowerElem, UpperElem, OutEnv[ Env @@ -58,9 +57,9 @@ trait ZPipelineCompanionVersionSpecific { OutElem2 ] )(implicit - composeEnv: Compose[LowerEnv2, UpperEnv2, OutEnv2, LowerEnv, UpperEnv, OutEnv], - composeErr: Compose[LowerErr2, UpperErr2, OutErr2, LowerErr, UpperErr, OutErr], - composeElem: Compose[LowerElem2, UpperElem2, OutElem2, LowerElem, UpperElem, OutElem] + composeEnv: ZCompose[LowerEnv2, UpperEnv2, OutEnv2, LowerEnv, UpperEnv, OutEnv], + composeErr: ZCompose[LowerErr2, UpperErr2, OutErr2, LowerErr, UpperErr, OutErr], + composeElem: ZCompose[LowerElem2, UpperElem2, OutElem2, LowerElem, UpperElem, OutElem] ): ZPipeline.WithOut[ composeEnv.Lower, composeEnv.Upper, @@ -94,9 +93,9 @@ trait ZPipelineCompanionVersionSpecific { OutElem2 ] )(implicit - composeEnv: Compose[LowerEnv, UpperEnv, OutEnv, LowerEnv2, UpperEnv2, OutEnv2], - composeErr: Compose[LowerErr, UpperErr, OutErr, LowerErr2, UpperErr2, OutErr2], - composeElem: Compose[LowerElem, UpperElem, OutElem, LowerElem2, UpperElem2, OutElem2] + composeEnv: ZCompose[LowerEnv, UpperEnv, OutEnv, LowerEnv2, UpperEnv2, OutEnv2], + composeErr: ZCompose[LowerErr, UpperErr, OutErr, LowerErr2, UpperErr2, OutErr2], + composeElem: ZCompose[LowerElem, UpperElem, OutElem, LowerElem2, UpperElem2, OutElem2] ): ZPipeline.WithOut[ composeEnv.Lower, composeEnv.Upper, @@ -152,9 +151,9 @@ trait ZPipelineCompanionVersionSpecific { OutElem2 ] )(implicit - composeEnv: Compose[LowerEnv, UpperEnv, OutEnv, LowerEnv2, UpperEnv2, OutEnv2], - composeErr: Compose[LowerErr, UpperErr, OutErr, LowerErr2, UpperErr2, OutErr2], - composeElem: Compose[LowerElem, UpperElem, OutElem, LowerElem2, UpperElem2, OutElem2] + composeEnv: ZCompose[LowerEnv, UpperEnv, OutEnv, LowerEnv2, UpperEnv2, OutEnv2], + composeErr: ZCompose[LowerErr, UpperErr, OutErr, LowerErr2, UpperErr2, OutErr2], + composeElem: ZCompose[LowerElem, UpperElem, OutElem, LowerElem2, UpperElem2, OutElem2] ): ZPipeline.WithOut[ composeEnv.Lower, composeEnv.Upper, @@ -186,9 +185,9 @@ trait ZPipelineCompanionVersionSpecific { OutElem2 ] )(implicit - composeEnv: Compose[LowerEnv, UpperEnv, OutEnv, LowerEnv2, UpperEnv2, OutEnv2], - composeErr: Compose[LowerErr, UpperErr, OutErr, LowerErr2, UpperErr2, OutErr2], - composeElem: Compose[LowerElem, UpperElem, OutElem, LowerElem2, UpperElem2, OutElem2] + composeEnv: ZCompose[LowerEnv, UpperEnv, OutEnv, LowerEnv2, UpperEnv2, OutEnv2], + composeErr: ZCompose[LowerErr, UpperErr, OutErr, LowerErr2, UpperErr2, OutErr2], + composeElem: ZCompose[LowerElem, UpperElem, OutElem, LowerElem2, UpperElem2, OutElem2] ): ZPipeline.WithOut[ composeEnv.Lower, composeEnv.Upper, @@ -220,9 +219,9 @@ trait ZPipelineCompanionVersionSpecific { OutElem2 ] )(implicit - composeEnv: Compose[LowerEnv2, UpperEnv2, OutEnv2, LowerEnv, UpperEnv, OutEnv], - composeErr: Compose[LowerErr2, UpperErr2, OutErr2, LowerErr, UpperErr, OutErr], - composeElem: Compose[LowerElem2, UpperElem2, OutElem2, LowerElem, UpperElem, OutElem] + composeEnv: ZCompose[LowerEnv2, UpperEnv2, OutEnv2, LowerEnv, UpperEnv, OutEnv], + composeErr: ZCompose[LowerErr2, UpperErr2, OutErr2, LowerErr, UpperErr, OutErr], + composeElem: ZCompose[LowerElem2, UpperElem2, OutElem2, LowerElem, UpperElem, OutElem] ): ZPipeline.WithOut[ composeEnv.Lower, composeEnv.Upper, diff --git a/streams/shared/src/main/scala/zio/stream/ZPipeline.scala b/streams/shared/src/main/scala/zio/stream/ZPipeline.scala index 157d39a30c29..dd38851f9525 100644 --- a/streams/shared/src/main/scala/zio/stream/ZPipeline.scala +++ b/streams/shared/src/main/scala/zio/stream/ZPipeline.scala @@ -76,8 +76,6 @@ object ZPipeline extends ZPipelineCompanionVersionSpecific with ZPipelinePlatfor type OutElem[Elem] = Out0[Elem] } - type Identity[A] = A - def branchAfter[LowerEnv, UpperEnv, LowerErr, UpperErr, LowerElem, UpperElem, OutElem[Elem]](n: Int)( f: Chunk[UpperElem] => ZPipeline.WithOut[ LowerEnv, @@ -1130,178 +1128,6 @@ object ZPipeline extends ZPipelineCompanionVersionSpecific with ZPipelinePlatfor ] = utf32BEWithBomEncode - trait Compose[+LeftLower, -LeftUpper, LeftOut[In], +RightLower, -RightUpper, RightOut[In]] { - type Lower - type Upper - type Out[In] - } - - object Compose extends ComposeLowPriorityImplicits { - type WithOut[LeftLower, LeftUpper, LeftOut[In], RightLower, RightUpper, RightOut[In], Lower0, Upper0, Out0[In]] = - Compose[LeftLower, LeftUpper, LeftOut, RightLower, RightUpper, RightOut] { - type Lower = Lower0 - type Upper = Upper0 - type Out[In] = Out0[In] - } - - implicit def compose[ - LeftLower, - LeftUpper, - LeftOut >: RightLower <: RightUpper, - RightLower, - RightUpper, - RightOut - ]: Compose.WithOut[ - LeftLower, - LeftUpper, - ({ type Out[In] = LeftOut })#Out, - RightLower, - RightUpper, - ({ type Out[In] = RightOut })#Out, - LeftLower, - LeftUpper, - ({ type Out[In] = RightOut })#Out - ] = - new Compose[ - LeftLower, - LeftUpper, - ({ type Out[In] = LeftOut })#Out, - RightLower, - RightUpper, - ({ type Out[In] = RightOut })#Out - ] { - type Lower = LeftLower - type Upper = LeftUpper - type Out[In] = RightOut - } - - implicit def identity[LeftLower <: RightLower, LeftUpper, RightLower, RightUpper]: Compose.WithOut[ - LeftLower, - LeftUpper, - Identity, - RightLower, - RightUpper, - Identity, - RightLower, - LeftUpper with RightUpper, - Identity - ] = - new Compose[ - LeftLower, - LeftUpper, - Identity, - RightLower, - RightUpper, - Identity - ] { - type Lower = RightLower - type Upper = LeftUpper with RightUpper - type Out[In] = In - } - - implicit def leftIdentity[LeftLower <: RightLower, LeftUpper, RightLower, RightUpper, RightOut]: Compose.WithOut[ - LeftLower, - LeftUpper, - Identity, - RightLower, - RightUpper, - ({ type Out[In] = RightOut })#Out, - RightLower, - LeftUpper with RightUpper, - ({ type Out[In] = RightOut })#Out - ] = - new Compose[ - LeftLower, - LeftUpper, - Identity, - RightLower, - RightUpper, - ({ type Out[In] = RightOut })#Out - ] { - type Lower = RightLower - type Upper = LeftUpper with RightUpper - type Out[In] = RightOut - } - - implicit def rightIdentity[LeftLower, LeftUpper, LeftOut >: RightLower <: RightUpper, RightLower, RightUpper] - : Compose.WithOut[ - LeftLower, - LeftUpper, - ({ type Out[In] = LeftOut })#Out, - RightLower, - RightUpper, - Identity, - LeftLower, - LeftUpper, - ({ type Out[In] = LeftOut })#Out - ] = - new Compose[ - LeftLower, - LeftUpper, - ({ type Out[In] = LeftOut })#Out, - RightLower, - RightUpper, - Identity - ] { - type Lower = LeftLower - type Upper = LeftUpper - type Out[In] = LeftOut - } - } - - trait ComposeLowPriorityImplicits { - - implicit def identityLowPriority[LeftLowerElem, LeftUpperElem, RightLowerElem <: LeftLowerElem, RightUpperElem] - : Compose.WithOut[ - LeftLowerElem, - LeftUpperElem, - Identity, - RightLowerElem, - RightUpperElem, - Identity, - LeftLowerElem, - LeftUpperElem with RightUpperElem, - Identity - ] = - new Compose[ - LeftLowerElem, - LeftUpperElem, - Identity, - RightLowerElem, - RightUpperElem, - Identity - ] { - type Lower = LeftLowerElem - type Upper = LeftUpperElem with RightUpperElem - type Out[In] = In - } - - implicit def leftIdentityLowPriority[LeftLower, LeftUpper, RightLower <: LeftLower, RightUpper, RightOut] - : Compose.WithOut[ - LeftLower, - LeftUpper, - Identity, - RightLower, - RightUpper, - ({ type Out[In] = RightOut })#Out, - LeftLower, - LeftUpper with RightUpper, - ({ type Out[In] = RightOut })#Out - ] = - new Compose[ - LeftLower, - LeftUpper, - Identity, - RightLower, - RightUpper, - ({ type Out[In] = RightOut })#Out - ] { - type Lower = LeftLower - type Upper = LeftUpper with RightUpper - type Out[In] = RightOut - } - } - private def textDecodeUsing(charset: Charset): ZPipeline.WithOut[ Nothing, Any, diff --git a/test-tests/shared/src/test/scala/zio/test/SmartAssertionSpec.scala b/test-tests/shared/src/test/scala/zio/test/SmartAssertionSpec.scala index 17c95290777e..0b1a9f163988 100644 --- a/test-tests/shared/src/test/scala/zio/test/SmartAssertionSpec.scala +++ b/test-tests/shared/src/test/scala/zio/test/SmartAssertionSpec.scala @@ -13,7 +13,15 @@ object SmartAssertionSpec extends ZIOBaseSpec { * Switch TestAspect.failing to TestAspect.identity to easily preview * the error messages. */ - val failing: TestAspectPoly = TestAspect.failing + val failing: TestAspect.WithOut[ + Nothing, + Any, + Nothing, + Any, + ({ type OutEnv[Env] = Env })#OutEnv, + ({ type OutErr[Err] = Err })#OutErr + ] = + TestAspect.failing private val company: Company = Company("Ziverge", List(User("Bobo", List.tabulate(2)(n => Post(s"Post #$n"))))) diff --git a/test-tests/shared/src/test/scala/zio/test/TestAspectSpec.scala b/test-tests/shared/src/test/scala/zio/test/TestAspectSpec.scala index 24202cca7c6e..4a1510bb2fbc 100644 --- a/test-tests/shared/src/test/scala/zio/test/TestAspectSpec.scala +++ b/test-tests/shared/src/test/scala/zio/test/TestAspectSpec.scala @@ -229,6 +229,17 @@ object TestAspectSpec extends ZIOBaseSpec { assertM(ZIO.fail("fail"))(anything) } @@ nonTermination(1.minute) @@ failing ), + test("provideLayer provides a test with its required environment") { + for { + time <- Clock.nanoTime + } yield assert(time)(isGreaterThan(0L)) + } @@ provideLayer(Clock.live), + test("provideCustomLayer provides a test with part of its required environment") { + for { + time <- Clock.nanoTime + _ <- Random.nextInt + } yield assert(time)(isGreaterThan(0L)) + } @@ provideCustomLayer(Clock.live), test("repeats sets the number of times to repeat a test to the specified value") { for { ref <- Ref.make(0) diff --git a/test-tests/shared/src/test/scala/zio/test/ZIOBaseSpec.scala b/test-tests/shared/src/test/scala/zio/test/ZIOBaseSpec.scala index 8cb9ec278c3a..8feaf46a7a18 100644 --- a/test-tests/shared/src/test/scala/zio/test/ZIOBaseSpec.scala +++ b/test-tests/shared/src/test/scala/zio/test/ZIOBaseSpec.scala @@ -3,7 +3,14 @@ package zio.test import zio._ trait ZIOBaseSpec extends DefaultRunnableSpec { - override def aspects: List[TestAspectAtLeastR[Has[Live]]] = + override def aspects: List[TestAspect.WithOut[ + Nothing, + TestEnvironment, + Nothing, + Any, + ({ type OutEnv[Env] = Env })#OutEnv, + ({ type OutErr[Err] = Err })#OutErr + ]] = if (TestPlatform.isJVM) List(TestAspect.timeout(60.seconds)) else List(TestAspect.sequential, TestAspect.timeout(60.seconds)) } diff --git a/test/shared/src/main/scala-2.11-2.12/TestAspectCompanionVersionSpecific.scala b/test/shared/src/main/scala-2.11-2.12/TestAspectCompanionVersionSpecific.scala new file mode 100644 index 000000000000..7789f62a25f9 --- /dev/null +++ b/test/shared/src/main/scala-2.11-2.12/TestAspectCompanionVersionSpecific.scala @@ -0,0 +1,21 @@ +/* + * Copyright 2021 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 zio.stacktracer.TracingImplicits.disableAutoTrace + +trait TestAspectCompanionVersionSpecific diff --git a/test/shared/src/main/scala-2.11-2.12/TestAspectVersionSpecific.scala b/test/shared/src/main/scala-2.11-2.12/TestAspectVersionSpecific.scala new file mode 100644 index 000000000000..2d70a2b6affe --- /dev/null +++ b/test/shared/src/main/scala-2.11-2.12/TestAspectVersionSpecific.scala @@ -0,0 +1,192 @@ +/* + * Copyright 2021 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 zio._ +import zio.stacktracer.TracingImplicits.disableAutoTrace + +import scala.annotation.unchecked.uncheckedVariance + +trait TestAspectVersionSpecific[+LowerEnv, -UpperEnv, +LowerErr, -UpperErr] { + self: TestAspect[LowerEnv, UpperEnv, LowerErr, UpperErr] => + + /** + * Composes two test aspects into one test aspect, by first applying the + * transformation of the specified test aspect, and then applying the + * transformation of this test aspect. + */ + def <<<[LowerEnv2, UpperEnv2, LowerErr2, UpperErr2](that: TestAspect[LowerEnv2, UpperEnv2, LowerErr2, UpperErr2])( + implicit + composeEnv: ZCompose[LowerEnv2, UpperEnv2, that.OutEnv, LowerEnv, UpperEnv, OutEnv] @uncheckedVariance, + composeErr: ZCompose[LowerErr2, UpperErr2, that.OutErr, LowerErr, UpperErr, OutErr] @uncheckedVariance + ): TestAspect.WithOut[ + composeEnv.Lower, + composeEnv.Upper, + composeErr.Lower, + composeErr.Upper, + composeEnv.Out, + composeErr.Out + ] = + new TestAspect[ + composeEnv.Lower, + composeEnv.Upper, + composeErr.Lower, + composeErr.Upper + ] { + type OutEnv[Env] = composeEnv.Out[Env] + type OutErr[Err] = composeErr.Out[Err] + def apply[Env >: composeEnv.Lower <: composeEnv.Upper, Err >: composeErr.Lower <: composeErr.Upper]( + spec: Spec[Env, TestFailure[Err], TestSuccess] + )(implicit trace: ZTraceElement): Spec[OutEnv[Env], TestFailure[OutErr[Err]], TestSuccess] = { + val right = that.asInstanceOf[TestAspect[Nothing, Any, Nothing, Any]](spec) + val left = self.asInstanceOf[TestAspect[Nothing, Any, Nothing, Any]](right) + left.asInstanceOf[Spec[OutEnv[Env], TestFailure[OutErr[Err]], TestSuccess]] + } + } + + /** + * Composes two test aspects into one test aspect, by first applying the + * transformation of this test aspect, and then applying the transformation + * of the specified test aspect. + */ + def >>>[LowerEnv2, UpperEnv2, LowerErr2, UpperErr2](that: TestAspect[LowerEnv2, UpperEnv2, LowerErr2, UpperErr2])( + implicit + composeEnv: ZCompose[LowerEnv, UpperEnv, OutEnv, LowerEnv2, UpperEnv2, that.OutEnv] @uncheckedVariance, + composeErr: ZCompose[LowerErr, UpperErr, OutErr, LowerErr2, UpperErr2, that.OutErr] @uncheckedVariance + ): TestAspect.WithOut[ + composeEnv.Lower, + composeEnv.Upper, + composeErr.Lower, + composeErr.Upper, + composeEnv.Out, + composeErr.Out + ] = + new TestAspect[ + composeEnv.Lower, + composeEnv.Upper, + composeErr.Lower, + composeErr.Upper + ] { + type OutEnv[Env] = composeEnv.Out[Env] + type OutErr[Err] = composeErr.Out[Err] + def apply[Env >: composeEnv.Lower <: composeEnv.Upper, Err >: composeErr.Lower <: composeErr.Upper]( + spec: Spec[Env, TestFailure[Err], TestSuccess] + )(implicit trace: ZTraceElement): Spec[OutEnv[Env], TestFailure[OutErr[Err]], TestSuccess] = { + val left = self.asInstanceOf[TestAspect[Nothing, Any, Nothing, Any]](spec) + val right = that.asInstanceOf[TestAspect[Nothing, Any, Nothing, Any]](left) + right.asInstanceOf[Spec[OutEnv[Env], TestFailure[OutErr[Err]], TestSuccess]] + } + } + + /** + * Composes two test aspects into one test aspect, by first applying the + * transformation of this test aspect, and then applying the transformation + * of the specified test aspect. + */ + def @@[LowerEnv2, UpperEnv2, LowerErr2, UpperErr2](that: TestAspect[LowerEnv2, UpperEnv2, LowerErr2, UpperErr2])( + implicit + composeEnv: ZCompose[LowerEnv, UpperEnv, OutEnv, LowerEnv2, UpperEnv2, that.OutEnv] @uncheckedVariance, + composeErr: ZCompose[LowerErr, UpperErr, OutErr, LowerErr2, UpperErr2, that.OutErr] @uncheckedVariance + ): TestAspect.WithOut[ + composeEnv.Lower, + composeEnv.Upper, + composeErr.Lower, + composeErr.Upper, + composeEnv.Out, + composeErr.Out + ] = + new TestAspect[ + composeEnv.Lower, + composeEnv.Upper, + composeErr.Lower, + composeErr.Upper + ] { + type OutEnv[Env] = composeEnv.Out[Env] + type OutErr[Err] = composeErr.Out[Err] + def apply[Env >: composeEnv.Lower <: composeEnv.Upper, Err >: composeErr.Lower <: composeErr.Upper]( + spec: Spec[Env, TestFailure[Err], TestSuccess] + )(implicit trace: ZTraceElement): Spec[OutEnv[Env], TestFailure[OutErr[Err]], TestSuccess] = { + val left = self.asInstanceOf[TestAspect[Nothing, Any, Nothing, Any]](spec) + val right = that.asInstanceOf[TestAspect[Nothing, Any, Nothing, Any]](left) + right.asInstanceOf[Spec[OutEnv[Env], TestFailure[OutErr[Err]], TestSuccess]] + } + } + + /** + * A named version of the `>>>` operator. + */ + def andThen[LowerEnv2, UpperEnv2, LowerErr2, UpperErr2](that: TestAspect[LowerEnv2, UpperEnv2, LowerErr2, UpperErr2])( + implicit + composeEnv: ZCompose[LowerEnv, UpperEnv, OutEnv, LowerEnv2, UpperEnv2, that.OutEnv] @uncheckedVariance, + composeErr: ZCompose[LowerErr, UpperErr, OutErr, LowerErr2, UpperErr2, that.OutErr] @uncheckedVariance + ): TestAspect.WithOut[ + composeEnv.Lower, + composeEnv.Upper, + composeErr.Lower, + composeErr.Upper, + composeEnv.Out, + composeErr.Out + ] = + new TestAspect[ + composeEnv.Lower, + composeEnv.Upper, + composeErr.Lower, + composeErr.Upper + ] { + type OutEnv[Env] = composeEnv.Out[Env] + type OutErr[Err] = composeErr.Out[Err] + def apply[Env >: composeEnv.Lower <: composeEnv.Upper, Err >: composeErr.Lower <: composeErr.Upper]( + spec: Spec[Env, TestFailure[Err], TestSuccess] + )(implicit trace: ZTraceElement): Spec[OutEnv[Env], TestFailure[OutErr[Err]], TestSuccess] = { + val left = self.asInstanceOf[TestAspect[Nothing, Any, Nothing, Any]](spec) + val right = that.asInstanceOf[TestAspect[Nothing, Any, Nothing, Any]](left) + right.asInstanceOf[Spec[OutEnv[Env], TestFailure[OutErr[Err]], TestSuccess]] + } + } + + /** + * A named version of the `<<<` operator. + */ + def compose[LowerEnv2, UpperEnv2, LowerErr2, UpperErr2](that: TestAspect[LowerEnv2, UpperEnv2, LowerErr2, UpperErr2])( + implicit + composeEnv: ZCompose[LowerEnv2, UpperEnv2, that.OutEnv, LowerEnv, UpperEnv, OutEnv] @uncheckedVariance, + composeErr: ZCompose[LowerErr2, UpperErr2, that.OutErr, LowerErr, UpperErr, OutErr] @uncheckedVariance + ): TestAspect.WithOut[ + composeEnv.Lower, + composeEnv.Upper, + composeErr.Lower, + composeErr.Upper, + composeEnv.Out, + composeErr.Out + ] = + new TestAspect[ + composeEnv.Lower, + composeEnv.Upper, + composeErr.Lower, + composeErr.Upper + ] { + type OutEnv[Env] = composeEnv.Out[Env] + type OutErr[Err] = composeErr.Out[Err] + def apply[Env >: composeEnv.Lower <: composeEnv.Upper, Err >: composeErr.Lower <: composeErr.Upper]( + spec: Spec[Env, TestFailure[Err], TestSuccess] + )(implicit trace: ZTraceElement): ZSpec[OutEnv[Env], OutErr[Err]] = { + val right = that.asInstanceOf[TestAspect[Nothing, Any, Nothing, Any]](spec) + val left = self.asInstanceOf[TestAspect[Nothing, Any, Nothing, Any]](right) + left.asInstanceOf[Spec[OutEnv[Env], TestFailure[OutErr[Err]], TestSuccess]] + } + } +} diff --git a/test/shared/src/main/scala-2.13+/TestAspectCompanionVersionSpecific.scala b/test/shared/src/main/scala-2.13+/TestAspectCompanionVersionSpecific.scala new file mode 100644 index 000000000000..1e2fabc73f7f --- /dev/null +++ b/test/shared/src/main/scala-2.13+/TestAspectCompanionVersionSpecific.scala @@ -0,0 +1,139 @@ +/* + * Copyright 2021 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 zio._ +import zio.stacktracer.TracingImplicits.disableAutoTrace + +trait TestAspectCompanionVersionSpecific { + + implicit final class TestAspectSyntax[LowerEnv, UpperEnv, LowerErr, UpperErr, OutEnv[Env], OutErr[Err]]( + private val self: TestAspect.WithOut[LowerEnv, UpperEnv, LowerErr, UpperErr, OutEnv, OutErr] + ) { + + /** + * Composes two test aspects into one test aspect, by first applying the + * transformation of the specified test aspect, and then applying the + * transformation of this test aspect. + */ + def <<<[LowerEnv2, UpperEnv2, LowerErr2, UpperErr2, OutEnv2[Env], OutErr2[Err]]( + that: TestAspect.WithOut[LowerEnv2, UpperEnv2, LowerErr2, UpperErr2, OutEnv2, OutErr2] + )(implicit + composeEnv: ZCompose[LowerEnv2, UpperEnv2, OutEnv2, LowerEnv, UpperEnv, OutEnv], + composeErr: ZCompose[LowerErr2, UpperErr2, OutErr2, LowerErr, UpperErr, OutErr] + ): TestAspect.WithOut[ + composeEnv.Lower, + composeEnv.Upper, + composeErr.Lower, + composeErr.Upper, + composeEnv.Out, + composeErr.Out + ] = + that >>> self + + /** + * Composes two test aspects into one test aspect, by first applying the + * transformation of this test aspect, and then applying the transformation + * of the specified test aspect. + */ + def >>>[LowerEnv2, UpperEnv2, LowerErr2, UpperErr2, OutEnv2[Env], OutErr2[Err]]( + that: TestAspect.WithOut[LowerEnv2, UpperEnv2, LowerErr2, UpperErr2, OutEnv2, OutErr2] + )(implicit + composeEnv: ZCompose[LowerEnv, UpperEnv, OutEnv, LowerEnv2, UpperEnv2, OutEnv2], + composeErr: ZCompose[LowerErr, UpperErr, OutErr, LowerErr2, UpperErr2, OutErr2] + ): TestAspect.WithOut[ + composeEnv.Lower, + composeEnv.Upper, + composeErr.Lower, + composeErr.Upper, + composeEnv.Out, + composeErr.Out + ] = + new TestAspect[ + composeEnv.Lower, + composeEnv.Upper, + composeErr.Lower, + composeErr.Upper, + ] { + type OutEnv[Env] = composeEnv.Out[Env] + type OutErr[Err] = composeErr.Out[Err] + def apply[Env >: composeEnv.Lower <: composeEnv.Upper, Err >: composeErr.Lower <: composeErr.Upper]( + spec: Spec[Env, TestFailure[Err], TestSuccess] + )(implicit trace: ZTraceElement): Spec[OutEnv[Env], TestFailure[OutErr[Err]], TestSuccess] = { + val left = self.asInstanceOf[TestAspect[Nothing, Any, Nothing, Any]](spec) + val right = that.asInstanceOf[TestAspect[Nothing, Any, Nothing, Any]](left) + right.asInstanceOf[Spec[OutEnv[Env], TestFailure[OutErr[Err]], TestSuccess]] + } + } + + /** + * Composes two test aspects into one test aspect, by first applying the + * transformation of this test aspect, and then applying the transformation + * of the specified test aspect. + */ + def @@[LowerEnv2, UpperEnv2, LowerErr2, UpperErr2, OutEnv2[Env], OutErr2[Err]]( + that: TestAspect.WithOut[LowerEnv2, UpperEnv2, LowerErr2, UpperErr2, OutEnv2, OutErr2] + )(implicit + composeEnv: ZCompose[LowerEnv, UpperEnv, OutEnv, LowerEnv2, UpperEnv2, OutEnv2], + composeErr: ZCompose[LowerErr, UpperErr, OutErr, LowerErr2, UpperErr2, OutErr2] + ): TestAspect.WithOut[ + composeEnv.Lower, + composeEnv.Upper, + composeErr.Lower, + composeErr.Upper, + composeEnv.Out, + composeErr.Out + ] = + self >>> that + + /** + * A named version of the `>>>` operator. + */ + def andThen[LowerEnv2, UpperEnv2, LowerErr2, UpperErr2, OutEnv2[Env], OutErr2[Err]]( + that: TestAspect.WithOut[LowerEnv2, UpperEnv2, LowerErr2, UpperErr2, OutEnv2, OutErr2] + )(implicit + composeEnv: ZCompose[LowerEnv, UpperEnv, OutEnv, LowerEnv2, UpperEnv2, OutEnv2], + composeErr: ZCompose[LowerErr, UpperErr, OutErr, LowerErr2, UpperErr2, OutErr2] + ): TestAspect.WithOut[ + composeEnv.Lower, + composeEnv.Upper, + composeErr.Lower, + composeErr.Upper, + composeEnv.Out, + composeErr.Out + ] = + self >>> that + + /** + * A named version of the `<<<` operator. + */ + def compose[LowerEnv2, UpperEnv2, LowerErr2, UpperErr2, OutEnv2[Env], OutErr2[Err]]( + that: TestAspect.WithOut[LowerEnv2, UpperEnv2, LowerErr2, UpperErr2, OutEnv2, OutErr2] + )(implicit + composeEnv: ZCompose[LowerEnv2, UpperEnv2, OutEnv2, LowerEnv, UpperEnv, OutEnv], + composeErr: ZCompose[LowerErr2, UpperErr2, OutErr2, LowerErr, UpperErr, OutErr] + ): TestAspect.WithOut[ + composeEnv.Lower, + composeEnv.Upper, + composeErr.Lower, + composeErr.Upper, + composeEnv.Out, + composeErr.Out, + ] = + self <<< that + } +} diff --git a/test/shared/src/main/scala-2.13+/TestAspectVersionSpecific.scala b/test/shared/src/main/scala-2.13+/TestAspectVersionSpecific.scala new file mode 100644 index 000000000000..f7c4c19d1d05 --- /dev/null +++ b/test/shared/src/main/scala-2.13+/TestAspectVersionSpecific.scala @@ -0,0 +1,21 @@ +/* + * Copyright 2021 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 zio.stacktracer.TracingImplicits.disableAutoTrace + +trait TestAspectVersionSpecific[+LowerEnv, -UpperEnv, +LowerErr, -UpperErr] diff --git a/test/shared/src/main/scala/zio/test/AbstractRunnableSpec.scala b/test/shared/src/main/scala/zio/test/AbstractRunnableSpec.scala index db5475bd32ce..6094a264da2c 100644 --- a/test/shared/src/main/scala/zio/test/AbstractRunnableSpec.scala +++ b/test/shared/src/main/scala/zio/test/AbstractRunnableSpec.scala @@ -26,7 +26,14 @@ abstract class AbstractRunnableSpec { type Environment type Failure - def aspects: List[TestAspect[Nothing, Environment, Nothing, Any]] + def aspects: List[TestAspect.WithOut[ + Nothing, + Environment, + Nothing, + Any, + ({ type OutEnv[Env] = Env })#OutEnv, + ({ type OutErr[Err] = Err })#OutErr + ]] def runner: TestRunner[Environment, Failure] def spec: ZSpec[Environment, Failure] diff --git a/test/shared/src/main/scala/zio/test/DefaultRunnableSpec.scala b/test/shared/src/main/scala/zio/test/DefaultRunnableSpec.scala index ce155b2c5db4..7cb8c463c109 100644 --- a/test/shared/src/main/scala/zio/test/DefaultRunnableSpec.scala +++ b/test/shared/src/main/scala/zio/test/DefaultRunnableSpec.scala @@ -25,7 +25,14 @@ import zio.stacktracer.TracingImplicits.disableAutoTrace */ abstract class DefaultRunnableSpec extends RunnableSpec[TestEnvironment, Any] { - override def aspects: List[TestAspect[Nothing, TestEnvironment, Nothing, Any]] = + override def aspects: List[TestAspect.WithOut[ + Nothing, + TestEnvironment, + Nothing, + Any, + ({ type OutEnv[Env] = Env })#OutEnv, + ({ type OutErr[Err] = Err })#OutErr + ]] = List(TestAspect.timeoutWarning(60.seconds)) override def runner: TestRunner[TestEnvironment, Any] = diff --git a/test/shared/src/main/scala/zio/test/MutableRunnableSpec.scala b/test/shared/src/main/scala/zio/test/MutableRunnableSpec.scala index f26ce503f299..0415816791a0 100644 --- a/test/shared/src/main/scala/zio/test/MutableRunnableSpec.scala +++ b/test/shared/src/main/scala/zio/test/MutableRunnableSpec.scala @@ -42,7 +42,14 @@ import scala.util.control.NoStackTrace @deprecated("use RunnableSpec", "2.0.0") class MutableRunnableSpec[R <: Has[_]: Tag]( layer: ZLayer[TestEnvironment, Throwable, R], - aspect: TestAspect[R with TestEnvironment, R with TestEnvironment, Any, Any] = TestAspect.identity + aspect: TestAspect.WithOut[ + R with TestEnvironment, + R with TestEnvironment, + Any, + Any, + ({ type OutEnv[Env] = Env })#OutEnv, + ({ type OutErr[Err] = Err })#OutErr + ] = TestAspect.identity ) extends RunnableSpec[TestEnvironment, Any] { self => @@ -58,7 +65,14 @@ class MutableRunnableSpec[R <: Has[_]: Tag]( sealed case class SuiteBuilder(label: String) extends SpecBuilder { private[test] var nested: Chunk[SpecBuilder] = Chunk.empty - private var aspects: Chunk[TestAspect[R with TestEnvironment, R with TestEnvironment, Failure, Failure]] = + private var aspects: Chunk[TestAspect.WithOut[ + R with TestEnvironment, + R with TestEnvironment, + Failure, + Failure, + ({ type OutEnv[Env] = Env })#OutEnv, + ({ type OutErr[Err] = Err })#OutErr + ]] = Chunk.empty /** @@ -68,7 +82,14 @@ class MutableRunnableSpec[R <: Has[_]: Tag]( * }}} */ final def @@( - aspect: TestAspect[R with TestEnvironment, R with TestEnvironment, Failure, Failure] + aspect: TestAspect.WithOut[ + R with TestEnvironment, + R with TestEnvironment, + Failure, + Failure, + ({ type OutEnv[Env] = Env })#OutEnv, + ({ type OutErr[Err] = Err })#OutErr + ] )(implicit trace: ZTraceElement): SuiteBuilder = { aspects = aspects :+ aspect this @@ -93,7 +114,14 @@ class MutableRunnableSpec[R <: Has[_]: Tag]( * }}} */ final def @@( - aspect: TestAspect[R with TestEnvironment, R with TestEnvironment, Failure, Failure] + aspect: TestAspect.WithOut[ + R with TestEnvironment, + R with TestEnvironment, + Failure, + Failure, + ({ type OutEnv[Env] = Env })#OutEnv, + ({ type OutErr[Err] = Err })#OutErr + ] )(implicit trace: ZTraceElement): TestBuilder = { toSpec = toSpec @@ aspect this @@ -153,7 +181,14 @@ class MutableRunnableSpec[R <: Has[_]: Tag]( (stack.head @@ aspect).toSpec.provideCustomLayerShared(layer.mapError(TestFailure.fail)) } - override def aspects: List[TestAspect[Nothing, TestEnvironment, Nothing, Any]] = + override def aspects: List[TestAspect.WithOut[ + Nothing, + TestEnvironment, + Nothing, + Any, + ({ type OutEnv[Env] = Env })#OutEnv, + ({ type OutErr[Err] = Err })#OutErr + ]] = List(TestAspect.timeoutWarning(60.seconds)) override def runner: TestRunner[TestEnvironment, Any] = diff --git a/test/shared/src/main/scala/zio/test/Spec.scala b/test/shared/src/main/scala/zio/test/Spec.scala index 06afccfe4c3f..51e68941385c 100644 --- a/test/shared/src/main/scala/zio/test/Spec.scala +++ b/test/shared/src/main/scala/zio/test/Spec.scala @@ -40,17 +40,6 @@ final case class Spec[-R, +E, +T](caseValue: SpecCase[R, E, T, Spec[R, E, T]]) e case _ => Spec.multiple(Chunk(self, that)) } - /** - * Syntax for adding aspects. - * {{{ - * test("foo") { assert(42, equalTo(42)) } @@ ignore - * }}} - */ - final def @@[R0 <: R1, R1 <: R, E0, E1, E2 >: E0 <: E1]( - aspect: TestAspect[R0, R1, E0, E1] - )(implicit ev1: E <:< TestFailure[E2], ev2: T <:< TestSuccess, trace: ZTraceElement): ZSpec[R1, E2] = - aspect(self.asInstanceOf[ZSpec[R1, E2]]) - /** * Annotates each test in this spec with the specified test annotation. */ @@ -591,7 +580,7 @@ final case class Spec[-R, +E, +T](caseValue: SpecCase[R, E, T, Spec[R, E, T]]) e } } -object Spec { +object Spec extends SpecLowPriority { sealed abstract class SpecCase[-R, +E, +T, +A] { self => final def map[B](f: A => B)(implicit trace: ZTraceElement): SpecCase[R, E, T, B] = self match { case ExecCase(label, spec) => ExecCase(label, f(spec)) @@ -668,4 +657,67 @@ object Spec { )(implicit ev: Has.IsHas[R1], tag: Tag[Map[Key, Service]], trace: ZTraceElement): Spec[R1, E, T] = self.provideSome(ev.updateAt(_, key, f)) } + + implicit final class ZSpecSyntax[Env, Err](private val self: ZSpec[Env, Err]) extends AnyVal { + + /** + * Syntax for adding aspects. + * {{{ + * test("foo") { assert(42, equalTo(42)) } @@ ignore + * }}} + */ + final def @@[LowerEnv <: UpperEnv, UpperEnv <: Env, LowerErr >: Err, UpperErr >: LowerErr]( + aspect: TestAspect[LowerEnv, UpperEnv, LowerErr, UpperErr] + )(implicit + trace: ZTraceElement + ): Spec[aspect.OutEnv[UpperEnv], TestFailure[aspect.OutErr[LowerErr]], TestSuccess] = + aspect(self.asInstanceOf[ZSpec[UpperEnv, LowerErr]]) + + /** + * Syntax for adding aspects. + * {{{ + * test("foo") { assert(42, equalTo(42)) } @@ ignore + * }}} + */ + final def @@[LowerEnv <: Env, LowerErr >: Err, UpperErr >: LowerErr]( + aspect: TestAspect[LowerEnv, Any, LowerErr, UpperErr] + )(implicit + dummy: DummyImplicit, + trace: ZTraceElement + ): Spec[aspect.OutEnv[Env], TestFailure[aspect.OutErr[LowerErr]], TestSuccess] = + aspect(self.asInstanceOf[ZSpec[Env, LowerErr]]) + } +} + +trait SpecLowPriority { + + implicit final class ZSpecSyntaxLowPriority[Env, Err](private val self: ZSpec[Env, Err]) { + + /** + * Syntax for adding aspects. + * {{{ + * test("foo") { assert(42, equalTo(42)) } @@ ignore + * }}} + */ + final def @@[LowerEnv <: UpperEnv, UpperEnv <: Env, LowerErr >: Err]( + aspect: TestAspect[LowerEnv, UpperEnv, LowerErr, Any] + )(implicit + trace: ZTraceElement + ): Spec[aspect.OutEnv[UpperEnv], TestFailure[aspect.OutErr[LowerErr]], TestSuccess] = + aspect(self.asInstanceOf[ZSpec[UpperEnv, LowerErr]]) + + /** + * Syntax for adding aspects. + * {{{ + * test("foo") { assert(42, equalTo(42)) } @@ ignore + * }}} + */ + final def @@[LowerEnv <: Env, LowerErr >: Err]( + aspect: TestAspect[LowerEnv, Any, LowerErr, Any] + )(implicit + dummy: DummyImplicit, + trace: ZTraceElement + ): Spec[aspect.OutEnv[Env], TestFailure[aspect.OutErr[LowerErr]], TestSuccess] = + aspect(self.asInstanceOf[ZSpec[Env, LowerErr]]) + } } diff --git a/test/shared/src/main/scala/zio/test/TestAspect.scala b/test/shared/src/main/scala/zio/test/TestAspect.scala index 1cff4bdc9ef7..505d7097bf5a 100644 --- a/test/shared/src/main/scala/zio/test/TestAspect.scala +++ b/test/shared/src/main/scala/zio/test/TestAspect.scala @@ -27,82 +27,74 @@ import scala.collection.immutable.SortedSet * an aspect as a polymorphic function, capable of transforming one test into * another, possibly enlarging the environment or error type. */ -abstract class TestAspect[+LowerR, -UpperR, +LowerE, -UpperE] { self => - - /** - * Applies the aspect to some tests in the spec, chosen by the provided - * predicate. - */ - def some[R >: LowerR <: UpperR, E >: LowerE <: UpperE](spec: ZSpec[R, E])(implicit trace: ZTraceElement): ZSpec[R, E] +trait TestAspect[+LowerEnv, -UpperEnv, +LowerErr, -UpperErr] + extends TestAspectVersionSpecific[LowerEnv, UpperEnv, LowerErr, UpperErr] { self => + type OutEnv[Env] + type OutErr[Err] /** * An alias for [[all]]. */ - final def apply[R >: LowerR <: UpperR, E >: LowerE <: UpperE](spec: ZSpec[R, E])(implicit - trace: ZTraceElement - ): ZSpec[R, E] = - all(spec) + def apply[Env >: LowerEnv <: UpperEnv, Err >: LowerErr <: UpperErr](spec: Spec[Env, TestFailure[Err], TestSuccess])( + implicit trace: ZTraceElement + ): Spec[OutEnv[Env], TestFailure[OutErr[Err]], TestSuccess] +} - /** - * Applies the aspect to every test in the spec. - */ - final def all[R >: LowerR <: UpperR, E >: LowerE <: UpperE](spec: ZSpec[R, E])(implicit - trace: ZTraceElement - ): ZSpec[R, E] = - some[R, E](spec) +object TestAspect extends TestAspectCompanionVersionSpecific with TimeoutVariants { - /** - * Returns a new aspect that represents the sequential composition of this - * aspect with the specified one. - */ - final def >>>[LowerR1 >: LowerR, UpperR1 <: UpperR, LowerE1 >: LowerE, UpperE1 <: UpperE]( - that: TestAspect[LowerR1, UpperR1, LowerE1, UpperE1] - ): TestAspect[LowerR1, UpperR1, LowerE1, UpperE1] = - new TestAspect[LowerR1, UpperR1, LowerE1, UpperE1] { - def some[R >: LowerR1 <: UpperR1, E >: LowerE1 <: UpperE1]( - spec: ZSpec[R, E] - )(implicit trace: ZTraceElement): ZSpec[R, E] = - that.some(self.some(spec)) + type WithOut[+LowerEnv, -UpperEnv, +LowerErr, -UpperErr, OutEnv0[Err], OutErr0[Env]] = + TestAspect[LowerEnv, UpperEnv, LowerErr, UpperErr] { + type OutEnv[Env] = OutEnv0[Env] + type OutErr[Err] = OutErr0[Err] } - /** - * Returns a new aspect that represents the sequential composition of this - * aspect with the specified one. - */ - final def @@[LowerR1 >: LowerR, UpperR1 <: UpperR, LowerE1 >: LowerE, UpperE1 <: UpperE]( - that: TestAspect[LowerR1, UpperR1, LowerE1, UpperE1] - ): TestAspect[LowerR1, UpperR1, LowerE1, UpperE1] = - self >>> that - - final def andThen[LowerR1 >: LowerR, UpperR1 <: UpperR, LowerE1 >: LowerE, UpperE1 <: UpperE]( - that: TestAspect[LowerR1, UpperR1, LowerE1, UpperE1] - ): TestAspect[LowerR1, UpperR1, LowerE1, UpperE1] = - self >>> that -} -object TestAspect extends TimeoutVariants { - /** * An aspect that returns the tests unchanged */ - val identity: TestAspectPoly = - new TestAspectPoly { - def some[R, E](spec: ZSpec[R, E])(implicit trace: ZTraceElement): ZSpec[R, E] = + val identity: TestAspect.WithOut[ + Nothing, + Any, + Nothing, + Any, + ({ type OutEnv[Env] = Env })#OutEnv, + ({ type OutErr[Err] = Err })#OutErr + ] = + new TestAspect[Nothing, Any, Nothing, Any] { + type OutEnv[Env] = Env + type OutErr[Err] = Err + def apply[R, E](spec: ZSpec[R, E])(implicit trace: ZTraceElement): ZSpec[R, E] = spec } /** * An aspect that marks tests as ignored. */ - val ignore: TestAspectAtLeastR[Has[Annotations]] = - new TestAspectAtLeastR[Has[Annotations]] { - def some[R <: Has[Annotations], E](spec: ZSpec[R, E])(implicit trace: ZTraceElement): ZSpec[R, E] = + val ignore: TestAspect.WithOut[ + Nothing, + Has[Annotations], + Nothing, + Any, + ({ type OutEnv[Env] = Env })#OutEnv, + ({ type OutErr[Err] = Err })#OutErr + ] = + new TestAspect[Nothing, Has[Annotations], Nothing, Any] { + type OutEnv[Env] = Env + type OutErr[Err] = Err + def apply[R <: Has[Annotations], E](spec: ZSpec[R, E])(implicit trace: ZTraceElement): ZSpec[R, E] = spec.when(false) } /** * Constructs an aspect that runs the specified effect after every test. */ - def after[R0, E0](effect: ZIO[R0, E0, Any]): TestAspect[Nothing, R0, E0, Any] = + def after[R0, E0](effect: ZIO[R0, E0, Any]): TestAspect.WithOut[ + Nothing, + R0, + E0, + Any, + ({ type OutEnv[Env] = Env })#OutEnv, + ({ type OutErr[Err] = Err })#OutErr + ] = new TestAspect.PerTest[Nothing, R0, E0, Any] { def perTest[R <: R0, E >: E0]( test: ZIO[R, TestFailure[E], TestSuccess] @@ -115,15 +107,31 @@ object TestAspect extends TimeoutVariants { /** * Constructs an aspect that runs the specified effect after all tests. */ - def afterAll[R0](effect: ZIO[R0, Nothing, Any]): TestAspect[Nothing, R0, Nothing, Any] = + def afterAll[R0](effect: ZIO[R0, Nothing, Any]): TestAspect.WithOut[ + Nothing, + R0, + Nothing, + Any, + ({ type OutEnv[Env] = Env })#OutEnv, + ({ type OutErr[Err] = Err })#OutErr + ] = aroundAll(ZIO.unit, effect) /** * Annotates tests with the specified test annotation. */ - def annotate[V](key: TestAnnotation[V], value: V): TestAspectPoly = - new TestAspectPoly { - def some[R, E](spec: ZSpec[R, E])(implicit trace: ZTraceElement): ZSpec[R, E] = + def annotate[V](key: TestAnnotation[V], value: V): TestAspect.WithOut[ + Nothing, + Any, + Nothing, + Any, + ({ type OutEnv[Env] = Env })#OutEnv, + ({ type OutErr[Err] = Err })#OutErr + ] = + new TestAspect[Nothing, Any, Nothing, Any] { + type OutEnv[Env] = Env + type OutErr[Err] = Err + def apply[R, E](spec: ZSpec[R, E])(implicit trace: ZTraceElement): ZSpec[R, E] = spec.annotate(key, value) } @@ -133,7 +141,14 @@ object TestAspect extends TimeoutVariants { */ def aroundWith[R0, E0, A0]( before: ZIO[R0, E0, A0] - )(after: A0 => ZIO[R0, Nothing, Any]): TestAspect[Nothing, R0, E0, Any] = + )(after: A0 => ZIO[R0, Nothing, Any]): TestAspect.WithOut[ + Nothing, + R0, + E0, + Any, + ({ type OutEnv[Env] = Env })#OutEnv, + ({ type OutErr[Err] = Err })#OutErr + ] = new TestAspect.PerTest[Nothing, R0, E0, Any] { def perTest[R <: R0, E >: E0](test: ZIO[R, TestFailure[E], TestSuccess])(implicit trace: ZTraceElement @@ -145,7 +160,14 @@ object TestAspect extends TimeoutVariants { * A less powerful variant of `around` where the result of `before` is not * required by after. */ - def around[R0, E0](before: ZIO[R0, E0, Any], after: ZIO[R0, Nothing, Any]): TestAspect[Nothing, R0, E0, Any] = + def around[R0, E0](before: ZIO[R0, E0, Any], after: ZIO[R0, Nothing, Any]): TestAspect.WithOut[ + Nothing, + R0, + E0, + Any, + ({ type OutEnv[Env] = Env })#OutEnv, + ({ type OutErr[Err] = Err })#OutErr + ] = aroundWith(before)(_ => after) /** @@ -154,9 +176,18 @@ object TestAspect extends TimeoutVariants { */ def aroundAllWith[R0, E0, A0]( before: ZIO[R0, E0, A0] - )(after: A0 => ZIO[R0, Nothing, Any]): TestAspect[Nothing, R0, E0, Any] = + )(after: A0 => ZIO[R0, Nothing, Any]): TestAspect.WithOut[ + Nothing, + R0, + E0, + Any, + ({ type OutEnv[Env] = Env })#OutEnv, + ({ type OutErr[Err] = Err })#OutErr + ] = new TestAspect[Nothing, R0, E0, Any] { - def some[R <: R0, E >: E0](spec: ZSpec[R, E])(implicit trace: ZTraceElement): ZSpec[R, E] = + type OutEnv[Env] = Env + type OutErr[Err] = Err + def apply[R <: R0, E >: E0](spec: ZSpec[R, E])(implicit trace: ZTraceElement): ZSpec[R, E] = Spec.managed(ZManaged.acquireReleaseWith(before)(after).mapError(TestFailure.fail).as(spec)) } @@ -164,7 +195,14 @@ object TestAspect extends TimeoutVariants { * A less powerful variant of `aroundAll` where the result of `before` is not * required by `after`. */ - def aroundAll[R0, E0](before: ZIO[R0, E0, Any], after: ZIO[R0, Nothing, Any]): TestAspect[Nothing, R0, E0, Any] = + def aroundAll[R0, E0](before: ZIO[R0, E0, Any], after: ZIO[R0, Nothing, Any]): TestAspect.WithOut[ + Nothing, + R0, + E0, + Any, + ({ type OutEnv[Env] = Env })#OutEnv, + ({ type OutErr[Err] = Err })#OutErr + ] = aroundAllWith(before)(_ => after) /** @@ -173,7 +211,14 @@ object TestAspect extends TimeoutVariants { */ def aroundTest[R0, E0]( managed: ZManaged[R0, TestFailure[E0], TestSuccess => ZIO[R0, TestFailure[E0], TestSuccess]] - ): TestAspect[Nothing, R0, E0, Any] = + ): TestAspect.WithOut[ + Nothing, + R0, + E0, + Any, + ({ type OutEnv[Env] = Env })#OutEnv, + ({ type OutErr[Err] = Err })#OutErr + ] = new TestAspect.PerTest[Nothing, R0, E0, Any] { def perTest[R <: R0, E >: E0](test: ZIO[R, TestFailure[E], TestSuccess])(implicit trace: ZTraceElement @@ -187,7 +232,7 @@ object TestAspect extends TimeoutVariants { */ def aspect[R0, E0]( f: ZIO[R0, TestFailure[E0], TestSuccess] => ZIO[R0, TestFailure[E0], TestSuccess] - ): TestAspect[R0, R0, E0, E0] = + ): TestAspect.WithOut[R0, R0, E0, E0, ({ type OutEnv[Env] = Env })#OutEnv, ({ type OutErr[Err] = Err })#OutErr] = new TestAspect.PerTest[R0, R0, E0, E0] { def perTest[R >: R0 <: R0, E >: E0 <: E0]( test: ZIO[R, TestFailure[E], TestSuccess] @@ -198,7 +243,14 @@ object TestAspect extends TimeoutVariants { /** * Constructs an aspect that runs the specified effect before every test. */ - def before[R0, E0](effect: ZIO[R0, E0, Any]): TestAspect[Nothing, R0, E0, Any] = + def before[R0, E0](effect: ZIO[R0, E0, Any]): TestAspect.WithOut[ + Nothing, + R0, + E0, + Any, + ({ type OutEnv[Env] = Env })#OutEnv, + ({ type OutErr[Err] = Err })#OutErr + ] = new TestAspect.PerTest[Nothing, R0, E0, Any] { def perTest[R <: R0, E >: E0](test: ZIO[R, TestFailure[E], TestSuccess])(implicit trace: ZTraceElement @@ -210,16 +262,27 @@ object TestAspect extends TimeoutVariants { * Constructs an aspect that runs the specified effect a single time before * all tests. */ - def beforeAll[R0, E0](effect: ZIO[R0, E0, Any]): TestAspect[Nothing, R0, E0, Any] = + def beforeAll[R0, E0](effect: ZIO[R0, E0, Any]): TestAspect.WithOut[ + Nothing, + R0, + E0, + Any, + ({ type OutEnv[Env] = Env })#OutEnv, + ({ type OutErr[Err] = Err })#OutErr + ] = aroundAll(effect, ZIO.unit) /** * An aspect that runs each test on a separate fiber and prints a fiber dump * if the test fails or has not terminated within the specified duration. */ - def diagnose(duration: Duration): TestAspectAtLeastR[Has[Live] with Has[Annotations]] = - new TestAspectAtLeastR[Has[Live] with Has[Annotations]] { - def some[R <: Has[Live] with Has[Annotations], E]( + def diagnose(duration: Duration): TestAspect.WithOut[Nothing, Has[Live] with Has[ + Annotations + ], Nothing, Any, ({ type OutEnv[Env] = Env })#OutEnv, ({ type OutErr[Err] = Err })#OutErr] = + new TestAspect[Nothing, Has[Live] with Has[Annotations], Nothing, Any] { + type OutEnv[Env] = Env + type OutErr[Err] = Err + def apply[R <: Has[Live] with Has[Annotations], E]( spec: ZSpec[R, E] )(implicit trace: ZTraceElement): ZSpec[R, E] = { def diagnose[R <: Has[Live] with Has[Annotations], E]( @@ -246,8 +309,10 @@ object TestAspect extends TimeoutVariants { * environment set to debug mode so that console output is rendered to * standard output in addition to being written to the output buffer. */ - val debug: TestAspectAtLeastR[Has[TestConsole]] = - new PerTest.AtLeastR[Has[TestConsole]] { + val debug: TestAspect.WithOut[Nothing, Has[ + TestConsole + ], Nothing, Any, ({ type OutEnv[Env] = Env })#OutEnv, ({ type OutErr[Err] = Err })#OutErr] = + new TestAspect.PerTest[Nothing, Has[TestConsole], Nothing, Any] { def perTest[R <: Has[TestConsole], E]( test: ZIO[R, TestFailure[E], TestSuccess] )(implicit trace: ZTraceElement): ZIO[R, TestFailure[E], TestSuccess] = @@ -258,84 +323,185 @@ object TestAspect extends TimeoutVariants { * An aspect that applies the specified aspect on Dotty. */ def dotty[LowerR, UpperR, LowerE, UpperE]( - that: TestAspect[LowerR, UpperR, LowerE, UpperE] - ): TestAspect[LowerR, UpperR, LowerE, UpperE] = + that: TestAspect.WithOut[ + LowerR, + UpperR, + LowerE, + UpperE, + ({ type OutEnv[Env] = Env })#OutEnv, + ({ type OutErr[Err] = Err })#OutErr + ] + ): TestAspect.WithOut[ + LowerR, + UpperR, + LowerE, + UpperE, + ({ type OutEnv[Env] = Env })#OutEnv, + ({ type OutErr[Err] = Err })#OutErr + ] = if (TestVersion.isDotty) that else identity /** * An aspect that only runs tests on Dotty. */ - val dottyOnly: TestAspectAtLeastR[Has[Annotations]] = + val dottyOnly: TestAspect.WithOut[ + Nothing, + Has[Annotations], + Nothing, + Any, + ({ type OutEnv[Env] = Env })#OutEnv, + ({ type OutErr[Err] = Err })#OutErr + ] = if (TestVersion.isDotty) identity else ignore /** * An aspect that retries a test until success, without limit. */ - val eventually: TestAspectAtLeastR[ZTestEnv] = { - val eventually = new PerTest.Poly { + val eventually: TestAspect.WithOut[ + Nothing, + ZTestEnv, + Nothing, + Any, + ({ type OutEnv[Env] = Env })#OutEnv, + ({ type OutErr[Err] = Err })#OutErr + ] = { + val eventually: TestAspect.WithOut[ + Nothing, + Any, + Nothing, + Any, + ({ type OutEnv[Env] = Env })#OutEnv, + ({ type OutErr[Err] = Err })#OutErr + ] = new PerTest[Nothing, Any, Nothing, Any] { def perTest[R, E](test: ZIO[R, TestFailure[E], TestSuccess])(implicit trace: ZTraceElement ): ZIO[R, TestFailure[E], TestSuccess] = test.eventually } - restoreTestEnvironment >>> eventually + val restore = restoreTestEnvironment >>> eventually + restore } /** * An aspect that runs tests on all versions except Dotty. */ - val exceptDotty: TestAspectAtLeastR[Has[Annotations]] = + val exceptDotty: TestAspect.WithOut[ + Nothing, + Has[Annotations], + Nothing, + Any, + ({ type OutEnv[Env] = Env })#OutEnv, + ({ type OutErr[Err] = Err })#OutErr + ] = if (TestVersion.isDotty) ignore else identity /** * An aspect that runs tests on all platforms except ScalaJS. */ - val exceptJS: TestAspectAtLeastR[Has[Annotations]] = + val exceptJS: TestAspect.WithOut[ + Nothing, + Has[Annotations], + Nothing, + Any, + ({ type OutEnv[Env] = Env })#OutEnv, + ({ type OutErr[Err] = Err })#OutErr + ] = if (TestPlatform.isJS) ignore else identity /** * An aspect that runs tests on all platforms except the JVM. */ - val exceptJVM: TestAspectAtLeastR[Has[Annotations]] = + val exceptJVM: TestAspect.WithOut[ + Nothing, + Has[Annotations], + Nothing, + Any, + ({ type OutEnv[Env] = Env })#OutEnv, + ({ type OutErr[Err] = Err })#OutErr + ] = if (TestPlatform.isJVM) ignore else identity /** * An aspect that runs tests on all platforms except ScalaNative. */ - val exceptNative: TestAspectAtLeastR[Has[Annotations]] = + val exceptNative: TestAspect.WithOut[ + Nothing, + Has[Annotations], + Nothing, + Any, + ({ type OutEnv[Env] = Env })#OutEnv, + ({ type OutErr[Err] = Err })#OutErr + ] = if (TestPlatform.isNative) ignore else identity /** * An aspect that runs tests on all versions except Scala 2. */ - val exceptScala2: TestAspectAtLeastR[Has[Annotations]] = + val exceptScala2: TestAspect.WithOut[ + Nothing, + Has[Annotations], + Nothing, + Any, + ({ type OutEnv[Env] = Env })#OutEnv, + ({ type OutErr[Err] = Err })#OutErr + ] = if (TestVersion.isScala2) ignore else identity /** * An aspect that runs tests on all versions except Scala 2.11. */ - val exceptScala211: TestAspectAtLeastR[Has[Annotations]] = + val exceptScala211: TestAspect.WithOut[ + Nothing, + Has[Annotations], + Nothing, + Any, + ({ type OutEnv[Env] = Env })#OutEnv, + ({ type OutErr[Err] = Err })#OutErr + ] = if (TestVersion.isScala211) ignore else identity /** * An aspect that runs tests on all versions except Scala 2.12. */ - val exceptScala212: TestAspectAtLeastR[Has[Annotations]] = + val exceptScala212: TestAspect.WithOut[ + Nothing, + Has[Annotations], + Nothing, + Any, + ({ type OutEnv[Env] = Env })#OutEnv, + ({ type OutErr[Err] = Err })#OutErr + ] = if (TestVersion.isScala212) ignore else identity /** * An aspect that runs tests on all versions except Scala 2.13. */ - val exceptScala213: TestAspectAtLeastR[Has[Annotations]] = + val exceptScala213: TestAspect.WithOut[ + Nothing, + Has[Annotations], + Nothing, + Any, + ({ type OutEnv[Env] = Env })#OutEnv, + ({ type OutErr[Err] = Err })#OutErr + ] = if (TestVersion.isScala213) ignore else identity /** * An aspect that sets suites to the specified execution strategy, but only if * their current strategy is inherited (undefined). */ - def executionStrategy(exec: ExecutionStrategy): TestAspectPoly = - new TestAspectPoly { - def some[R, E](spec: ZSpec[R, E])(implicit trace: ZTraceElement): ZSpec[R, E] = + def executionStrategy(exec: ExecutionStrategy): TestAspect.WithOut[ + Nothing, + Any, + Nothing, + Any, + ({ type OutEnv[Env] = Env })#OutEnv, + ({ type OutErr[Err] = Err })#OutErr + ] = + new TestAspect[Nothing, Any, Nothing, Any] { + type OutEnv[Env] = Env + type OutErr[Err] = Err + def apply[R, E](spec: ZSpec[R, E])(implicit trace: ZTraceElement): ZSpec[R, E] = Spec.exec(exec, spec) } @@ -343,7 +509,14 @@ object TestAspect extends TimeoutVariants { * An aspect that makes a test that failed for any reason pass. Note that if * the test passes this aspect will make it fail. */ - val failing: TestAspectPoly = + val failing: TestAspect.WithOut[ + Nothing, + Any, + Nothing, + Any, + ({ type OutEnv[Env] = Env })#OutEnv, + ({ type OutErr[Err] = Err })#OutErr + ] = failing(_ => true) /** @@ -351,7 +524,14 @@ object TestAspect extends TimeoutVariants { * Note that the test will fail for other failures and also if it passes * correctly. */ - def failing[E0](assertion: TestFailure[E0] => Boolean): TestAspect[Nothing, Any, Nothing, E0] = + def failing[E0](assertion: TestFailure[E0] => Boolean): TestAspect.WithOut[ + Nothing, + Any, + Nothing, + E0, + ({ type OutEnv[Env] = Env })#OutEnv, + ({ type OutErr[Err] = Err })#OutErr + ] = new TestAspect.PerTest[Nothing, Any, Nothing, E0] { def perTest[R, E <: E0](test: ZIO[R, TestFailure[E], TestSuccess])(implicit trace: ZTraceElement @@ -370,7 +550,14 @@ object TestAspect extends TimeoutVariants { * but not in [[RunnableSpec]]. This aspect is required for the proper * functioning of `TestClock.adjust`. */ - lazy val fibers: TestAspect[Nothing, Has[Annotations], Nothing, Any] = + lazy val fibers: TestAspect.WithOut[ + Nothing, + Has[Annotations], + Nothing, + Any, + ({ type OutEnv[Env] = Env })#OutEnv, + ({ type OutErr[Err] = Err })#OutErr + ] = new TestAspect.PerTest[Nothing, Has[Annotations], Nothing, Any] { def perTest[R <: Has[Annotations], E]( test: ZIO[R, TestFailure[E], TestSuccess] @@ -398,37 +585,66 @@ object TestAspect extends TimeoutVariants { * An aspect that retries a test until success, with a default limit, for use * with flaky tests. */ - val flaky: TestAspectAtLeastR[Has[Annotations] with Has[TestConfig] with ZTestEnv] = { - val flaky = new PerTest.AtLeastR[Has[Annotations] with Has[TestConfig] with ZTestEnv] { - def perTest[R <: Has[Annotations] with Has[TestConfig] with ZTestEnv, E]( - test: ZIO[R, TestFailure[E], TestSuccess] - )(implicit trace: ZTraceElement): ZIO[R, TestFailure[E], TestSuccess] = - TestConfig.retries.flatMap { n => - test.catchAll(_ => test.tapError(_ => Annotations.annotate(TestAnnotation.retried, 1)).retryN(n - 1)) - } - } - restoreTestEnvironment >>> flaky + val flaky: TestAspect.WithOut[ + Nothing, + Has[Annotations] with Has[TestConfig] with ZTestEnv, + Nothing, + Any, + ({ type OutEnv[Env] = Env })#OutEnv, + ({ type OutErr[Err] = Err })#OutErr + ] = { + val flaky: TestAspect.WithOut[Nothing, Has[Annotations] with Has[ + TestConfig + ] with ZTestEnv, Nothing, Any, ({ type OutEnv[Env] = Env })#OutEnv, ({ type OutErr[Err] = Err })#OutErr] = + new PerTest[Nothing, Has[Annotations] with Has[TestConfig] with ZTestEnv, Nothing, Any] { + def perTest[R <: Has[Annotations] with Has[TestConfig] with ZTestEnv, E]( + test: ZIO[R, TestFailure[E], TestSuccess] + )(implicit trace: ZTraceElement): ZIO[R, TestFailure[E], TestSuccess] = + TestConfig.retries.flatMap { n => + test.catchAll(_ => test.tapError(_ => Annotations.annotate(TestAnnotation.retried, 1)).retryN(n - 1)) + } + } + val restore = restoreTestEnvironment >>> flaky + restore } /** * An aspect that retries a test until success, with the specified limit, for * use with flaky tests. */ - def flaky(n: Int): TestAspectAtLeastR[ZTestEnv with Has[Annotations]] = { - val flaky = new PerTest.AtLeastR[ZTestEnv with Has[Annotations]] { - def perTest[R <: ZTestEnv with Has[Annotations], E]( - test: ZIO[R, TestFailure[E], TestSuccess] - )(implicit trace: ZTraceElement): ZIO[R, TestFailure[E], TestSuccess] = - test.catchAll(_ => test.tapError(_ => Annotations.annotate(TestAnnotation.retried, 1)).retryN(n - 1)) - } - restoreTestEnvironment >>> flaky + def flaky(n: Int): TestAspect.WithOut[ + Nothing, + ZTestEnv with Has[Annotations], + Nothing, + Any, + ({ type OutEnv[Env] = Env })#OutEnv, + ({ type OutErr[Err] = Err })#OutErr + ] = { + val flaky: TestAspect.WithOut[Nothing, ZTestEnv with Has[ + Annotations + ], Nothing, Any, ({ type OutEnv[Env] = Env })#OutEnv, ({ type OutErr[Err] = Err })#OutErr] = + new PerTest[Nothing, ZTestEnv with Has[Annotations], Nothing, Any] { + def perTest[R <: ZTestEnv with Has[Annotations], E]( + test: ZIO[R, TestFailure[E], TestSuccess] + )(implicit trace: ZTraceElement): ZIO[R, TestFailure[E], TestSuccess] = + test.catchAll(_ => test.tapError(_ => Annotations.annotate(TestAnnotation.retried, 1)).retryN(n - 1)) + } + val restore = restoreTestEnvironment >>> flaky + restore } /** * An aspect that runs each test on its own separate fiber. */ - val forked: TestAspectPoly = - new PerTest.Poly { + val forked: TestAspect.WithOut[ + Nothing, + Any, + Nothing, + Any, + ({ type OutEnv[Env] = Env })#OutEnv, + ({ type OutErr[Err] = Err })#OutErr + ] = + new PerTest[Nothing, Any, Nothing, Any] { def perTest[R, E](test: ZIO[R, TestFailure[E], TestSuccess])(implicit trace: ZTraceElement ): ZIO[R, TestFailure[E], TestSuccess] = @@ -439,9 +655,20 @@ object TestAspect extends TimeoutVariants { * An aspect that only runs a test if the specified environment variable * satisfies the specified assertion. */ - def ifEnv(env: String)(assertion: String => Boolean): TestAspectAtLeastR[Has[Live] with Has[Annotations]] = - new TestAspectAtLeastR[Has[Live] with Has[Annotations]] { - def some[R <: Has[Live] with Has[Annotations], E](spec: ZSpec[R, E])(implicit trace: ZTraceElement): ZSpec[R, E] = + def ifEnv(env: String)(assertion: String => Boolean): TestAspect.WithOut[ + Nothing, + Has[Live] with Has[Annotations], + Nothing, + Any, + ({ type OutEnv[Env] = Env })#OutEnv, + ({ type OutErr[Err] = Err })#OutErr + ] = + new TestAspect[Nothing, Has[Live] with Has[Annotations], Nothing, Any] { + type OutEnv[Env] = Env + type OutErr[Err] = Err + def apply[R <: Has[Live] with Has[Annotations], E](spec: ZSpec[R, E])(implicit + trace: ZTraceElement + ): ZSpec[R, E] = spec.whenZIO(Live.live(System.env(env)).orDie.map(_.fold(false)(assertion))) } @@ -449,116 +676,247 @@ object TestAspect extends TimeoutVariants { * As aspect that only runs a test if the specified environment variable is * set. */ - def ifEnvSet(env: String): TestAspectAtLeastR[Has[Live] with Has[Annotations]] = + def ifEnvSet(env: String): TestAspect.WithOut[ + Nothing, + Has[Live] with Has[Annotations], + Nothing, + Any, + ({ type OutEnv[Env] = Env })#OutEnv, + ({ type OutErr[Err] = Err })#OutErr + ] = ifEnv(env)(_ => true) /** * An aspect that only runs a test if the specified Java property satisfies * the specified assertion. */ - def ifProp(prop: String)(assertion: String => Boolean): TestAspectAtLeastR[Has[Live] with Has[Annotations]] = - new TestAspectAtLeastR[Has[Live] with Has[Annotations]] { - def some[R <: Has[Live] with Has[Annotations], E](spec: ZSpec[R, E])(implicit trace: ZTraceElement): ZSpec[R, E] = + def ifProp(prop: String)(assertion: String => Boolean): TestAspect.WithOut[ + Nothing, + Has[Live] with Has[Annotations], + Nothing, + Any, + ({ type OutEnv[Env] = Env })#OutEnv, + ({ type OutErr[Err] = Err })#OutErr + ] = + new TestAspect[Nothing, Has[Live] with Has[Annotations], Nothing, Any] { + type OutEnv[Env] = Env + type OutErr[Err] = Err + def apply[R <: Has[Live] with Has[Annotations], E](spec: ZSpec[R, E])(implicit + trace: ZTraceElement + ): ZSpec[R, E] = spec.whenZIO(Live.live(System.property(prop)).orDie.map(_.fold(false)(assertion))) } /** * As aspect that only runs a test if the specified Java property is set. */ - def ifPropSet(prop: String): TestAspectAtLeastR[Has[Live] with Has[Annotations]] = + def ifPropSet(prop: String): TestAspect.WithOut[ + Nothing, + Has[Live] with Has[Annotations], + Nothing, + Any, + ({ type OutEnv[Env] = Env })#OutEnv, + ({ type OutErr[Err] = Err })#OutErr + ] = ifProp(prop)(_ => true) /** * An aspect that applies the specified aspect on ScalaJS. */ def js[LowerR, UpperR, LowerE, UpperE]( - that: TestAspect[LowerR, UpperR, LowerE, UpperE] - ): TestAspect[LowerR, UpperR, LowerE, UpperE] = + that: TestAspect.WithOut[ + LowerR, + UpperR, + LowerE, + UpperE, + ({ type OutEnv[Env] = Env })#OutEnv, + ({ type OutErr[Err] = Err })#OutErr + ] + ): TestAspect.WithOut[ + LowerR, + UpperR, + LowerE, + UpperE, + ({ type OutEnv[Env] = Env })#OutEnv, + ({ type OutErr[Err] = Err })#OutErr + ] = if (TestPlatform.isJS) that else identity /** * An aspect that only runs tests on ScalaJS. */ - val jsOnly: TestAspectAtLeastR[Has[Annotations]] = + val jsOnly: TestAspect.WithOut[ + Nothing, + Has[Annotations], + Nothing, + Any, + ({ type OutEnv[Env] = Env })#OutEnv, + ({ type OutErr[Err] = Err })#OutErr + ] = if (TestPlatform.isJS) identity else ignore /** * An aspect that applies the specified aspect on the JVM. */ def jvm[LowerR, UpperR, LowerE, UpperE]( - that: TestAspect[LowerR, UpperR, LowerE, UpperE] - ): TestAspect[LowerR, UpperR, LowerE, UpperE] = + that: TestAspect.WithOut[ + LowerR, + UpperR, + LowerE, + UpperE, + ({ type OutEnv[Env] = Env })#OutEnv, + ({ type OutErr[Err] = Err })#OutErr + ] + ): TestAspect.WithOut[ + LowerR, + UpperR, + LowerE, + UpperE, + ({ type OutEnv[Env] = Env })#OutEnv, + ({ type OutErr[Err] = Err })#OutErr + ] = if (TestPlatform.isJVM) that else identity /** * An aspect that only runs tests on the JVM. */ - val jvmOnly: TestAspectAtLeastR[Has[Annotations]] = + val jvmOnly: TestAspect.WithOut[ + Nothing, + Has[Annotations], + Nothing, + Any, + ({ type OutEnv[Env] = Env })#OutEnv, + ({ type OutErr[Err] = Err })#OutErr + ] = if (TestPlatform.isJVM) identity else ignore /** * An aspect that runs only on operating systems accepted by the specified * predicate. */ - def os(f: System.OS => Boolean): TestAspectAtLeastR[Has[Annotations]] = + def os(f: System.OS => Boolean): TestAspect.WithOut[ + Nothing, + Has[Annotations], + Nothing, + Any, + ({ type OutEnv[Env] = Env })#OutEnv, + ({ type OutErr[Err] = Err })#OutErr + ] = if (f(System.os)) identity else ignore /** * Runs only on Mac operating systems. */ - val mac: TestAspectAtLeastR[Has[Annotations]] = os(_.isMac) + val mac: TestAspect.WithOut[ + Nothing, + Has[Annotations], + Nothing, + Any, + ({ type OutEnv[Env] = Env })#OutEnv, + ({ type OutErr[Err] = Err })#OutErr + ] = os(_.isMac) /** * An aspect that applies the specified aspect on ScalaNative. */ def native[LowerR, UpperR, LowerE, UpperE]( - that: TestAspect[LowerR, UpperR, LowerE, UpperE] - ): TestAspect[LowerR, UpperR, LowerE, UpperE] = + that: TestAspect.WithOut[ + LowerR, + UpperR, + LowerE, + UpperE, + ({ type OutEnv[Env] = Env })#OutEnv, + ({ type OutErr[Err] = Err })#OutErr + ] + ): TestAspect.WithOut[ + LowerR, + UpperR, + LowerE, + UpperE, + ({ type OutEnv[Env] = Env })#OutEnv, + ({ type OutErr[Err] = Err })#OutErr + ] = if (TestPlatform.isNative) that else identity /** * An aspect that only runs tests on ScalaNative. */ - val nativeOnly: TestAspectAtLeastR[Has[Annotations]] = + val nativeOnly: TestAspect.WithOut[ + Nothing, + Has[Annotations], + Nothing, + Any, + ({ type OutEnv[Env] = Env })#OutEnv, + ({ type OutErr[Err] = Err })#OutErr + ] = if (TestPlatform.isNative) identity else ignore /** * An aspect that repeats the test a default number of times, ensuring it is * stable ("non-flaky"). Stops at the first failure. */ - val nonFlaky: TestAspectAtLeastR[ZTestEnv with Has[Annotations] with Has[TestConfig]] = { - val nonFlaky = new PerTest.AtLeastR[ZTestEnv with Has[Annotations] with Has[TestConfig]] { - def perTest[R <: ZTestEnv with Has[Annotations] with Has[TestConfig], E]( - test: ZIO[R, TestFailure[E], TestSuccess] - )(implicit trace: ZTraceElement): ZIO[R, TestFailure[E], TestSuccess] = - TestConfig.repeats.flatMap { n => - test *> test.tap(_ => Annotations.annotate(TestAnnotation.repeated, 1)).repeatN(n - 1) - } - } - restoreTestEnvironment >>> nonFlaky + val nonFlaky: TestAspect.WithOut[ + Nothing, + ZTestEnv with Has[Annotations] with Has[TestConfig], + Nothing, + Any, + ({ type OutEnv[Env] = Env })#OutEnv, + ({ type OutErr[Err] = Err })#OutErr + ] = { + val nonFlaky: TestAspect.WithOut[Nothing, ZTestEnv with Has[Annotations] with Has[ + TestConfig + ], Nothing, Any, ({ type OutEnv[Env] = Env })#OutEnv, ({ type OutErr[Err] = Err })#OutErr] = + new PerTest[Nothing, ZTestEnv with Has[Annotations] with Has[TestConfig], Nothing, Any] { + def perTest[R <: ZTestEnv with Has[Annotations] with Has[TestConfig], E]( + test: ZIO[R, TestFailure[E], TestSuccess] + )(implicit trace: ZTraceElement): ZIO[R, TestFailure[E], TestSuccess] = + TestConfig.repeats.flatMap { n => + test *> test.tap(_ => Annotations.annotate(TestAnnotation.repeated, 1)).repeatN(n - 1) + } + } + val restore = restoreTestEnvironment >>> nonFlaky + restore } /** * An aspect that repeats the test a specified number of times, ensuring it is * stable ("non-flaky"). Stops at the first failure. */ - def nonFlaky(n: Int): TestAspectAtLeastR[ZTestEnv with Has[Annotations]] = { - val nonFlaky = new PerTest.AtLeastR[ZTestEnv with Has[Annotations]] { - def perTest[R <: ZTestEnv with Has[Annotations], E]( - test: ZIO[R, TestFailure[E], TestSuccess] - )(implicit trace: ZTraceElement): ZIO[R, TestFailure[E], TestSuccess] = - test *> test.tap(_ => Annotations.annotate(TestAnnotation.repeated, 1)).repeatN(n - 1) - } - restoreTestEnvironment >>> nonFlaky + def nonFlaky(n: Int): TestAspect.WithOut[ + Nothing, + ZTestEnv with Has[Annotations], + Nothing, + Any, + ({ type OutEnv[Env] = Env })#OutEnv, + ({ type OutErr[Err] = Err })#OutErr + ] = { + val nonFlaky: TestAspect.WithOut[Nothing, ZTestEnv with Has[ + Annotations + ], Nothing, Any, ({ type OutEnv[Env] = Env })#OutEnv, ({ type OutErr[Err] = Err })#OutErr] = + new PerTest[Nothing, ZTestEnv with Has[Annotations], Nothing, Any] { + def perTest[R <: ZTestEnv with Has[Annotations], E]( + test: ZIO[R, TestFailure[E], TestSuccess] + )(implicit trace: ZTraceElement): ZIO[R, TestFailure[E], TestSuccess] = + test *> test.tap(_ => Annotations.annotate(TestAnnotation.repeated, 1)).repeatN(n - 1) + } + val restore = restoreTestEnvironment >>> nonFlaky + restore } /** * Constructs an aspect that requires a test to not terminate within the * specified time. */ - def nonTermination(duration: Duration): TestAspectAtLeastR[Has[Live]] = - timeout(duration) >>> - failing { + def nonTermination(duration: Duration): TestAspect.WithOut[ + Nothing, + Has[Live], + Nothing, + Any, + ({ type OutEnv[Env] = Env })#OutEnv, + ({ type OutErr[Err] = Err })#OutErr + ] = { + val nonTermination = timeout(duration) >>> + failing[Any] { case TestFailure.Assertion(_) => false case TestFailure.Runtime(cause) => cause.dieOption match { @@ -566,12 +924,21 @@ object TestAspect extends TimeoutVariants { case None => false } } + nonTermination + } /** * Sets the seed of the `TestRandom` instance in the environment to a random * value before each test. */ - val nondeterministic: TestAspectAtLeastR[Has[Live] with Has[TestRandom]] = + val nondeterministic: TestAspect.WithOut[ + Nothing, + Has[Live] with Has[TestRandom], + Nothing, + Any, + ({ type OutEnv[Env] = Env })#OutEnv, + ({ type OutErr[Err] = Err })#OutErr + ] = before( Live .live(Clock.nanoTime(ZTraceElement.empty))(ZTraceElement.empty) @@ -581,23 +948,200 @@ object TestAspect extends TimeoutVariants { /** * An aspect that executes the members of a suite in parallel. */ - val parallel: TestAspectPoly = + val parallel: TestAspect.WithOut[ + Nothing, + Any, + Nothing, + Any, + ({ type OutEnv[Env] = Env })#OutEnv, + ({ type OutErr[Err] = Err })#OutErr + ] = executionStrategy(ExecutionStrategy.Parallel) /** * An aspect that executes the members of a suite in parallel, up to the * specified number of concurrent fibers. */ - def parallelN(n: Int): TestAspectPoly = + def parallelN(n: Int): TestAspect.WithOut[ + Nothing, + Any, + Nothing, + Any, + ({ type OutEnv[Env] = Env })#OutEnv, + ({ type OutErr[Err] = Err })#OutErr + ] = executionStrategy(ExecutionStrategy.ParallelN(n)) + /** + * An aspect that provides each test in the spec with its required + * environment. + */ + final def provide[R0](r: R0): TestAspect.WithOut[ + R0, + Any, + Nothing, + Any, + ({ type OutEnv[Env] = Any })#OutEnv, + ({ type OutErr[Err] = Err })#OutErr + ] = + new TestAspect[R0, Any, Nothing, Any] { + type OutEnv[Env] = Any + type OutErr[Err] = Err + def apply[R >: R0, E](spec: ZSpec[R, E])(implicit trace: ZTraceElement): ZSpec[Any, E] = + spec.provide(r) + } + + /** + * Provides each test with the part of the environment that is not part of the + * `TestEnvironment`, leaving a spec that only depends on the + * `TestEnvironment`. + * + * {{{ + * val loggingLayer: ZLayer[Any, Nothing, Logging] = ??? + * + * val spec: ZSpec[TestEnvironment with Logging, Nothing] = ??? + * + * val spec2 = spec.provideCustomLayer(loggingLayer) + * }}} + */ + def provideCustomLayer[E, R](layer: ZLayer[TestEnvironment, TestFailure[E], R])(implicit + ev2: Has.Union[TestEnvironment, R], + tagged: Tag[R], + trace: ZTraceElement + ): TestAspect.WithOut[ + TestEnvironment with R, + Any, + E, + Any, + ({ type OutEnv[Env] = TestEnvironment })#OutEnv, + ({ type OutErr[Err] = Err })#OutErr + ] = + provideSomeLayer[TestEnvironment][E, R](layer) + + /** + * Provides each test with the part of the environment that is not part of the + * `TestEnvironment`, leaving a spec that only depends on the + * `TestEnvironment`. + * + * {{{ + * val loggingLayer: ZLayer[Any, Nothing, Logging] = ??? + * + * val spec: ZSpec[TestEnvironment with Logging, Nothing] = ??? + * + * val spec2 = spec.provideCustomLayer(loggingLayer) + * }}} + */ + def provideCustomLayerShared[E, R](layer: ZLayer[TestEnvironment, TestFailure[E], R])(implicit + ev2: Has.Union[TestEnvironment, R], + tagged: Tag[R], + trace: ZTraceElement + ): TestAspect.WithOut[ + TestEnvironment with R, + Any, + E, + Any, + ({ type OutEnv[Env] = TestEnvironment })#OutEnv, + ({ type OutErr[Err] = Err })#OutErr + ] = + provideSomeLayerShared[TestEnvironment][E, R](layer) + + /** + * An aspect that provides a layer to the spec, translating it up a level. + */ + final def provideLayer[R0, E1, R1]( + layer: ZLayer[R0, TestFailure[E1], R1] + ): TestAspect.WithOut[R1, Any, E1, Any, ({ type OutEnv[Env] = R0 })#OutEnv, ({ type OutErr[Err] = Err })#OutErr] = + new TestAspect[R1, Any, E1, Any] { + type OutEnv[Env] = R0 + type OutErr[Err] = Err + def apply[R >: R1, E >: E1](spec: ZSpec[R, E])(implicit trace: ZTraceElement): ZSpec[R0, E] = + spec.provideLayer(layer) + } + + /** + * An aspect that provides a layer to the spec, translating it up a level. + */ + final def provideLayerShared[R0, E1, R1]( + layer: ZLayer[R0, TestFailure[E1], R1] + ): TestAspect.WithOut[R1, Any, E1, Any, ({ type OutEnv[Env] = R0 })#OutEnv, ({ type OutErr[Err] = Err })#OutErr] = + new TestAspect[R1, Any, E1, Any] { + type OutEnv[Env] = R0 + type OutErr[Err] = Err + def apply[R >: R1, E >: E1](spec: ZSpec[R, E])(implicit trace: ZTraceElement): ZSpec[R0, E] = + spec.provideLayerShared(layer) + } + + /** + * Uses the specified function to provide each test in this spec with part of + * its required environment. + */ + final def provideSome[R0, R1](f: R0 => R1): TestAspect.WithOut[ + R1, + Any, + Nothing, + Any, + ({ type OutEnv[Env] = R0 })#OutEnv, + ({ type OutErr[Err] = Err })#OutErr + ] = + new TestAspect[R1, Any, Nothing, Any] { + type OutEnv[Env] = R0 + type OutErr[Err] = Err + def apply[R >: R1, E](spec: ZSpec[R, E])(implicit trace: ZTraceElement): ZSpec[R0, E] = + spec.provideSome(f) + } + + /** + * Splits the environment into two parts, providing each test with one part + * using the specified layer and leaving the remainder `R0`. + * + * {{{ + * val clockLayer: ZLayer[Any, Nothing, Has[Clock]] = ??? + * + * val spec: ZSpec[Has[Clock] with Has[Random], Nothing] = ??? + * + * val spec2 = spec @@ provideSomeLayer[Has[Random]](clockLayer) + * }}} + */ + final def provideSomeLayer[R0]: TestAspect.ProvideSomeLayer[R0] = + new TestAspect.ProvideSomeLayer[R0] + + /** + * Splits the environment into two parts, providing all tests with a shared + * version of one part using the specified layer and leaving the remainder + * `R0`. + * + * {{{ + * val clockLayer: ZLayer[Any, Nothing, Has[Clock]] = ??? + * + * val spec: ZSpec[Has[Clock] with Has[Random], Nothing] = ??? + * + * val spec2 = spec.provideSomeLayerShared[Has[Random]](clockLayer) + * }}} + */ + final def provideSomeLayerShared[R0]: TestAspect.ProvideSomeLayerShared[R0] = + new TestAspect.ProvideSomeLayerShared[R0] + /** * An aspect that repeats successful tests according to a schedule. */ def repeat[R0 <: ZTestEnv with Has[Annotations] with Has[Live]]( schedule: Schedule[R0, TestSuccess, Any] - ): TestAspectAtLeastR[R0] = { - val repeat = new PerTest.AtLeastR[R0] { + ): TestAspect.WithOut[ + Nothing, + R0, + Nothing, + Any, + ({ type OutEnv[Env] = Env })#OutEnv, + ({ type OutErr[Err] = Err })#OutErr + ] = { + val repeat: TestAspect.WithOut[ + Nothing, + R0, + Nothing, + Any, + ({ type OutEnv[Env] = Env })#OutEnv, + ({ type OutErr[Err] = Err })#OutErr + ] = new PerTest[Nothing, R0, Nothing, Any] { def perTest[R <: R0, E]( test: ZIO[R, TestFailure[E], TestSuccess] )(implicit trace: ZTraceElement): ZIO[R, TestFailure[E], TestSuccess] = @@ -610,15 +1154,23 @@ object TestAspect extends TimeoutVariants { Live.live(test.provide(r).repeat(repeatSchedule)) } } - restoreTestEnvironment >>> repeat + val restore = restoreTestEnvironment >>> repeat + restore } /** * An aspect that runs each test with the number of times to repeat tests to * ensure they are stable set to the specified value. */ - def repeats(n: Int): TestAspectAtLeastR[Has[TestConfig]] = - new PerTest.AtLeastR[Has[TestConfig]] { + def repeats(n: Int): TestAspect.WithOut[ + Nothing, + Has[TestConfig], + Nothing, + Any, + ({ type OutEnv[Env] = Env })#OutEnv, + ({ type OutErr[Err] = Err })#OutErr + ] = + new PerTest[Nothing, Has[TestConfig], Nothing, Any] { def perTest[R <: Has[TestConfig], E]( test: ZIO[R, TestFailure[E], TestSuccess] )(implicit trace: ZTraceElement): ZIO[R, TestFailure[E], TestSuccess] = @@ -637,7 +1189,14 @@ object TestAspect extends TimeoutVariants { * to its starting state after the test is run. Note that this is only useful * when repeating tests. */ - def restore[R0](service: R0 => Restorable): TestAspectAtLeastR[R0] = + def restore[R0](service: R0 => Restorable): TestAspect.WithOut[ + Nothing, + R0, + Nothing, + Any, + ({ type OutEnv[Env] = Env })#OutEnv, + ({ type OutErr[Err] = Err })#OutErr + ] = aroundWith(ZIO.accessZIO[R0](r => service(r).save(ZTraceElement.empty))(ZTraceElement.empty))(restore => restore) /** @@ -645,7 +1204,14 @@ object TestAspect extends TimeoutVariants { * starting state after the test is run. Note that this is only useful when * repeating tests. */ - def restoreTestClock: TestAspectAtLeastR[Has[TestClock]] = + def restoreTestClock: TestAspect.WithOut[ + Nothing, + Has[TestClock], + Nothing, + Any, + ({ type OutEnv[Env] = Env })#OutEnv, + ({ type OutErr[Err] = Err })#OutErr + ] = restore[Has[TestClock]](_.get) /** @@ -653,7 +1219,14 @@ object TestAspect extends TimeoutVariants { * its starting state after the test is run. Note that this is only useful * when repeating tests. */ - def restoreTestConsole: TestAspectAtLeastR[Has[TestConsole]] = + def restoreTestConsole: TestAspect.WithOut[ + Nothing, + Has[TestConsole], + Nothing, + Any, + ({ type OutEnv[Env] = Env })#OutEnv, + ({ type OutErr[Err] = Err })#OutErr + ] = restore[Has[TestConsole]](_.get) /** @@ -661,7 +1234,14 @@ object TestAspect extends TimeoutVariants { * its starting state after the test is run. Note that this is only useful * when repeating tests. */ - def restoreTestRandom: TestAspectAtLeastR[Has[TestRandom]] = + def restoreTestRandom: TestAspect.WithOut[ + Nothing, + Has[TestRandom], + Nothing, + Any, + ({ type OutEnv[Env] = Env })#OutEnv, + ({ type OutErr[Err] = Err })#OutErr + ] = restore[Has[TestRandom]](_.get) /** @@ -669,7 +1249,14 @@ object TestAspect extends TimeoutVariants { * its starting state after the test is run. Note that this is only useful * when repeating tests. */ - def restoreTestSystem: TestAspectAtLeastR[ZTestEnv] = + def restoreTestSystem: TestAspect.WithOut[ + Nothing, + Has[TestSystem], + Nothing, + Any, + ({ type OutEnv[Env] = Env })#OutEnv, + ({ type OutErr[Err] = Err })#OutErr + ] = restore[Has[TestSystem]](_.get) /** @@ -679,15 +1266,31 @@ object TestAspect extends TimeoutVariants { * and [[zio.test.TestSystem TestSystem]]) to their starting state after the * test is run. Note that this is only useful when repeating tests. */ - def restoreTestEnvironment: TestAspectAtLeastR[ZTestEnv] = - restoreTestClock >>> restoreTestConsole >>> restoreTestRandom >>> restoreTestSystem + def restoreTestEnvironment: TestAspect.WithOut[ + Nothing, + ZTestEnv, + Nothing, + Any, + ({ type OutEnv[Env] = Env })#OutEnv, + ({ type OutErr[Err] = Err })#OutErr + ] = { + val restoreTestEnvironment = restoreTestClock >>> restoreTestConsole >>> restoreTestRandom >>> restoreTestSystem + restoreTestEnvironment + } /** * An aspect that runs each test with the number of times to retry flaky tests * set to the specified value. */ - def retries(n: Int): TestAspectAtLeastR[Has[TestConfig]] = - new PerTest.AtLeastR[Has[TestConfig]] { + def retries(n: Int): TestAspect.WithOut[ + Nothing, + Has[TestConfig], + Nothing, + Any, + ({ type OutEnv[Env] = Env })#OutEnv, + ({ type OutErr[Err] = Err })#OutErr + ] = + new PerTest[Nothing, Has[TestConfig], Nothing, Any] { def perTest[R <: Has[TestConfig], E]( test: ZIO[R, TestFailure[E], TestSuccess] )(implicit trace: ZTraceElement): ZIO[R, TestFailure[E], TestSuccess] = @@ -706,27 +1309,50 @@ object TestAspect extends TimeoutVariants { */ def retry[R0 <: ZTestEnv with Has[Annotations] with Has[Live], E0]( schedule: Schedule[R0, TestFailure[E0], Any] - ): TestAspect[Nothing, R0, Nothing, E0] = { - val retry = new TestAspect.PerTest[Nothing, R0, Nothing, E0] { - def perTest[R <: R0, E <: E0]( - test: ZIO[R, TestFailure[E], TestSuccess] - )(implicit trace: ZTraceElement): ZIO[R, TestFailure[E], TestSuccess] = - ZIO.accessZIO[R] { r => - val retrySchedule: Schedule[Any, TestFailure[E0], Any] = - schedule - .tapOutput(_ => Annotations.annotate(TestAnnotation.retried, 1)) - .provide(r) - Live.live(test.provide(r).retry(retrySchedule)) - } - } - restoreTestEnvironment >>> retry + ): TestAspect.WithOut[ + Nothing, + R0, + Nothing, + E0, + ({ type OutEnv[Env] = Env })#OutEnv, + ({ type OutErr[Err] = Err })#OutErr + ] = { + val retry: TestAspect.WithOut[ + Nothing, + R0, + Nothing, + E0, + ({ type OutEnv[Env] = Env })#OutEnv, + ({ type OutErr[Err] = Err })#OutErr + ] = + new TestAspect.PerTest[Nothing, R0, Nothing, E0] { + def perTest[R <: R0, E <: E0]( + test: ZIO[R, TestFailure[E], TestSuccess] + )(implicit trace: ZTraceElement): ZIO[R, TestFailure[E], TestSuccess] = + ZIO.accessZIO[R] { r => + val retrySchedule: Schedule[Any, TestFailure[E0], Any] = + schedule + .tapOutput(_ => Annotations.annotate(TestAnnotation.retried, 1)) + .provide(r) + Live.live(test.provide(r).retry(retrySchedule)) + } + } + val restore = restoreTestEnvironment >>> retry + restore } /** * As aspect that runs each test with the specified `RuntimeConfigAspect`. */ - def runtimeConfig(runtimeConfigAspect: RuntimeConfigAspect): TestAspectPoly = - new PerTest.Poly { + def runtimeConfig(runtimeConfigAspect: RuntimeConfigAspect): TestAspect.WithOut[ + Nothing, + Any, + Nothing, + Any, + ({ type OutEnv[Env] = Env })#OutEnv, + ({ type OutErr[Err] = Err })#OutErr + ] = + new PerTest[Nothing, Any, Nothing, Any] { def perTest[R, E](test: ZIO[R, TestFailure[E], TestSuccess])(implicit trace: ZTraceElement ): ZIO[R, TestFailure[E], TestSuccess] = @@ -737,8 +1363,15 @@ object TestAspect extends TimeoutVariants { * An aspect that runs each test with the number of sufficient samples to * check for a random variable set to the specified value. */ - def samples(n: Int): TestAspectAtLeastR[Has[TestConfig]] = - new PerTest.AtLeastR[Has[TestConfig]] { + def samples(n: Int): TestAspect.WithOut[ + Nothing, + Has[TestConfig], + Nothing, + Any, + ({ type OutEnv[Env] = Env })#OutEnv, + ({ type OutErr[Err] = Err })#OutErr + ] = + new PerTest[Nothing, Has[TestConfig], Nothing, Any] { def perTest[R <: Has[TestConfig], E]( test: ZIO[R, TestFailure[E], TestSuccess] )(implicit trace: ZTraceElement): ZIO[R, TestFailure[E], TestSuccess] = @@ -755,78 +1388,183 @@ object TestAspect extends TimeoutVariants { /** * An aspect that executes the members of a suite sequentially. */ - val sequential: TestAspectPoly = + val sequential: TestAspect.WithOut[ + Nothing, + Any, + Nothing, + Any, + ({ type OutEnv[Env] = Env })#OutEnv, + ({ type OutErr[Err] = Err })#OutErr + ] = executionStrategy(ExecutionStrategy.Sequential) /** * An aspect that applies the specified aspect on Scala 2. */ def scala2[LowerR, UpperR, LowerE, UpperE]( - that: TestAspect[LowerR, UpperR, LowerE, UpperE] - ): TestAspect[LowerR, UpperR, LowerE, UpperE] = + that: TestAspect.WithOut[ + LowerR, + UpperR, + LowerE, + UpperE, + ({ type OutEnv[Env] = Env })#OutEnv, + ({ type OutErr[Err] = Err })#OutErr + ] + ): TestAspect.WithOut[ + LowerR, + UpperR, + LowerE, + UpperE, + ({ type OutEnv[Env] = Env })#OutEnv, + ({ type OutErr[Err] = Err })#OutErr + ] = if (TestVersion.isScala2) that else identity /** * An aspect that applies the specified aspect on Scala 2.11. */ def scala211[LowerR, UpperR, LowerE, UpperE]( - that: TestAspect[LowerR, UpperR, LowerE, UpperE] - ): TestAspect[LowerR, UpperR, LowerE, UpperE] = + that: TestAspect.WithOut[ + LowerR, + UpperR, + LowerE, + UpperE, + ({ type OutEnv[Env] = Env })#OutEnv, + ({ type OutErr[Err] = Err })#OutErr + ] + ): TestAspect.WithOut[ + LowerR, + UpperR, + LowerE, + UpperE, + ({ type OutEnv[Env] = Env })#OutEnv, + ({ type OutErr[Err] = Err })#OutErr + ] = if (TestVersion.isScala211) that else identity /** * An aspect that applies the specified aspect on Scala 2.12. */ def scala212[LowerR, UpperR, LowerE, UpperE]( - that: TestAspect[LowerR, UpperR, LowerE, UpperE] - ): TestAspect[LowerR, UpperR, LowerE, UpperE] = + that: TestAspect.WithOut[ + LowerR, + UpperR, + LowerE, + UpperE, + ({ type OutEnv[Env] = Env })#OutEnv, + ({ type OutErr[Err] = Err })#OutErr + ] + ): TestAspect.WithOut[ + LowerR, + UpperR, + LowerE, + UpperE, + ({ type OutEnv[Env] = Env })#OutEnv, + ({ type OutErr[Err] = Err })#OutErr + ] = if (TestVersion.isScala212) that else identity /** * An aspect that applies the specified aspect on Scala 2.13. */ def scala213[LowerR, UpperR, LowerE, UpperE]( - that: TestAspect[LowerR, UpperR, LowerE, UpperE] - ): TestAspect[LowerR, UpperR, LowerE, UpperE] = + that: TestAspect.WithOut[ + LowerR, + UpperR, + LowerE, + UpperE, + ({ type OutEnv[Env] = Env })#OutEnv, + ({ type OutErr[Err] = Err })#OutErr + ] + ): TestAspect.WithOut[ + LowerR, + UpperR, + LowerE, + UpperE, + ({ type OutEnv[Env] = Env })#OutEnv, + ({ type OutErr[Err] = Err })#OutErr + ] = if (TestVersion.isScala213) that else identity /** * An aspect that only runs tests on Scala 2. */ - val scala2Only: TestAspectAtLeastR[Has[Annotations]] = + val scala2Only: TestAspect.WithOut[ + Nothing, + Has[Annotations], + Nothing, + Any, + ({ type OutEnv[Env] = Env })#OutEnv, + ({ type OutErr[Err] = Err })#OutErr + ] = if (TestVersion.isScala2) identity else ignore /** * An aspect that only runs tests on Scala 2.11. */ - val scala211Only: TestAspectAtLeastR[Has[Annotations]] = + val scala211Only: TestAspect.WithOut[ + Nothing, + Has[Annotations], + Nothing, + Any, + ({ type OutEnv[Env] = Env })#OutEnv, + ({ type OutErr[Err] = Err })#OutErr + ] = if (TestVersion.isScala211) identity else ignore /** * An aspect that only runs tests on Scala 2.12. */ - val scala212Only: TestAspectAtLeastR[Has[Annotations]] = + val scala212Only: TestAspect.WithOut[ + Nothing, + Has[Annotations], + Nothing, + Any, + ({ type OutEnv[Env] = Env })#OutEnv, + ({ type OutErr[Err] = Err })#OutErr + ] = if (TestVersion.isScala212) identity else ignore /** * An aspect that only runs tests on Scala 2.13. */ - val scala213Only: TestAspectAtLeastR[Has[Annotations]] = + val scala213Only: TestAspect.WithOut[ + Nothing, + Has[Annotations], + Nothing, + Any, + ({ type OutEnv[Env] = Env })#OutEnv, + ({ type OutErr[Err] = Err })#OutErr + ] = if (TestVersion.isScala213) identity else ignore /** * Sets the seed of the `TestRandom` instance in the environment to the * specified value before each test. */ - def setSeed(seed: => Long): TestAspectAtLeastR[Has[TestRandom]] = + def setSeed(seed: => Long): TestAspect.WithOut[ + Nothing, + Has[TestRandom], + Nothing, + Any, + ({ type OutEnv[Env] = Env })#OutEnv, + ({ type OutErr[Err] = Err })#OutErr + ] = before(TestRandom.setSeed(seed)(ZTraceElement.empty)) /** * An aspect that runs each test with the maximum number of shrinkings to * minimize large failures set to the specified value. */ - def shrinks(n: Int): TestAspectAtLeastR[Has[TestConfig]] = - new PerTest.AtLeastR[Has[TestConfig]] { + def shrinks(n: Int): TestAspect.WithOut[ + Nothing, + Has[TestConfig], + Nothing, + Any, + ({ type OutEnv[Env] = Env })#OutEnv, + ({ type OutErr[Err] = Err })#OutErr + ] = + new PerTest[Nothing, Has[TestConfig], Nothing, Any] { def perTest[R <: Has[TestConfig], E]( test: ZIO[R, TestFailure[E], TestSuccess] )(implicit trace: ZTraceElement): ZIO[R, TestFailure[E], TestSuccess] = @@ -845,8 +1583,15 @@ object TestAspect extends TimeoutVariants { * instance in the environment set to silent mode so that console output is * only written to the output buffer and not rendered to standard output. */ - val silent: TestAspectAtLeastR[Has[TestConsole]] = - new PerTest.AtLeastR[Has[TestConsole]] { + val silent: TestAspect.WithOut[ + Nothing, + Has[TestConsole], + Nothing, + Any, + ({ type OutEnv[Env] = Env })#OutEnv, + ({ type OutErr[Err] = Err })#OutErr + ] = + new PerTest[Nothing, Has[TestConsole], Nothing, Any] { def perTest[R <: Has[TestConsole], E]( test: ZIO[R, TestFailure[E], TestSuccess] )(implicit trace: ZTraceElement): ZIO[R, TestFailure[E], TestSuccess] = @@ -856,8 +1601,15 @@ object TestAspect extends TimeoutVariants { /** * An aspect that runs each test with the size set to the specified value. */ - def sized(n: Int): TestAspectAtLeastR[Has[Sized]] = - new PerTest.AtLeastR[Has[Sized]] { + def sized(n: Int): TestAspect.WithOut[ + Nothing, + Has[Sized], + Nothing, + Any, + ({ type OutEnv[Env] = Env })#OutEnv, + ({ type OutErr[Err] = Err })#OutErr + ] = + new PerTest[Nothing, Has[Sized], Nothing, Any] { def perTest[R <: Has[Sized], E](test: ZIO[R, TestFailure[E], TestSuccess])(implicit trace: ZTraceElement ): ZIO[R, TestFailure[E], TestSuccess] = @@ -867,8 +1619,15 @@ object TestAspect extends TimeoutVariants { /** * An aspect that converts ignored tests into test failures. */ - val success: TestAspectPoly = - new PerTest.Poly { + val success: TestAspect.WithOut[ + Nothing, + Any, + Nothing, + Any, + ({ type OutEnv[Env] = Env })#OutEnv, + ({ type OutErr[Err] = Err })#OutErr + ] = + new PerTest[Nothing, Any, Nothing, Any] { def perTest[R, E]( test: ZIO[R, TestFailure[E], TestSuccess] )(implicit trace: ZTraceElement): ZIO[R, TestFailure[E], TestSuccess] = @@ -882,14 +1641,28 @@ object TestAspect extends TimeoutVariants { /** * Annotates tests with string tags. */ - def tag(tag: String, tags: String*): TestAspectPoly = + def tag(tag: String, tags: String*): TestAspect.WithOut[ + Nothing, + Any, + Nothing, + Any, + ({ type OutEnv[Env] = Env })#OutEnv, + ({ type OutErr[Err] = Err })#OutErr + ] = annotate(TestAnnotation.tagged, Set(tag) union tags.toSet) /** * Annotates tests with their execution times. */ - val timed: TestAspectAtLeastR[Has[Live] with Has[Annotations]] = - new TestAspect.PerTest.AtLeastR[Has[Live] with Has[Annotations]] { + val timed: TestAspect.WithOut[ + Nothing, + Has[Live] with Has[Annotations], + Nothing, + Any, + ({ type OutEnv[Env] = Env })#OutEnv, + ({ type OutErr[Err] = Err })#OutErr + ] = + new TestAspect.PerTest[Nothing, Has[Live] with Has[Annotations], Nothing, Any] { def perTest[R <: Has[Live] with Has[Annotations], E]( test: ZIO[R, TestFailure[E], TestSuccess] )(implicit trace: ZTraceElement): ZIO[R, TestFailure[E], TestSuccess] = @@ -905,8 +1678,15 @@ object TestAspect extends TimeoutVariants { */ def timeout( duration: Duration - ): TestAspectAtLeastR[Has[Live]] = - new PerTest.AtLeastR[Has[Live]] { + ): TestAspect.WithOut[ + Nothing, + Has[Live], + Nothing, + Any, + ({ type OutEnv[Env] = Env })#OutEnv, + ({ type OutErr[Err] = Err })#OutErr + ] = + new PerTest[Nothing, Has[Live], Nothing, Any] { def perTest[R <: Has[Live], E]( test: ZIO[R, TestFailure[E], TestSuccess] )(implicit trace: ZTraceElement): ZIO[R, TestFailure[E], TestSuccess] = { @@ -923,7 +1703,14 @@ object TestAspect extends TimeoutVariants { /** * Verifies the specified post-condition after each test is run. */ - def verify[R0, E0](condition: => ZIO[R0, E0, TestResult]): TestAspect[Nothing, R0, E0, Any] = + def verify[R0, E0](condition: => ZIO[R0, E0, TestResult]): TestAspect.WithOut[ + Nothing, + R0, + E0, + Any, + ({ type OutEnv[Env] = Env })#OutEnv, + ({ type OutErr[Err] = Err })#OutErr + ] = new TestAspect.PerTest[Nothing, R0, E0, Any] { def perTest[R <: R0, E >: E0](test: ZIO[R, TestFailure[E], TestSuccess])(implicit trace: ZTraceElement @@ -934,40 +1721,93 @@ object TestAspect extends TimeoutVariants { /** * Runs only on Unix / Linux operating systems. */ - val unix: TestAspectAtLeastR[Has[Annotations]] = os(_.isUnix) + val unix: TestAspect.WithOut[ + Nothing, + Has[Annotations], + Nothing, + Any, + ({ type OutEnv[Env] = Env })#OutEnv, + ({ type OutErr[Err] = Err })#OutErr + ] = + os(_.isUnix) /** * Runs only on Windows operating systems. */ - val windows: TestAspectAtLeastR[Has[Annotations]] = os(_.isWindows) + val windows: TestAspect.WithOut[ + Nothing, + Has[Annotations], + Nothing, + Any, + ({ type OutEnv[Env] = Env })#OutEnv, + ({ type OutErr[Err] = Err })#OutErr + ] = + os(_.isWindows) abstract class PerTest[+LowerR, -UpperR, +LowerE, -UpperE] extends TestAspect[LowerR, UpperR, LowerE, UpperE] { + type OutEnv[Env] = Env + type OutErr[Err] = Err def perTest[R >: LowerR <: UpperR, E >: LowerE <: UpperE]( test: ZIO[R, TestFailure[E], TestSuccess] )(implicit trace: ZTraceElement): ZIO[R, TestFailure[E], TestSuccess] - final def some[R >: LowerR <: UpperR, E >: LowerE <: UpperE]( - spec: ZSpec[R, E] - )(implicit trace: ZTraceElement): ZSpec[R, E] = + final def apply[R >: LowerR <: UpperR, E >: LowerE <: UpperE]( + spec: Spec[R, TestFailure[E], TestSuccess] + )(implicit trace: ZTraceElement): Spec[R, TestFailure[E], TestSuccess] = spec.transform[R, TestFailure[E], TestSuccess] { case Spec.TestCase(test, annotations) => Spec.TestCase(perTest(test), annotations) case c => c } } - object PerTest { - - /** - * A `PerTest.AtLeast[R]` is a `TestAspect.PerTest` that that requires at - * least an `R` in its environment - */ - type AtLeastR[R] = TestAspect.PerTest[Nothing, R, Nothing, Any] - - /** - * A `PerTest.Poly` is a `TestAspect.PerTest` that is completely - * polymorphic, having no requirements ZRTestEnv on error or environment. - */ - type Poly = TestAspect.PerTest[Nothing, Any, Nothing, Any] + + final class ProvideSomeLayer[R0](private val dummy: Boolean = true) extends AnyVal { + def apply[E1, R1]( + layer: ZLayer[R0, TestFailure[E1], R1] + )(implicit + ev: Has.Union[R0, R1], + tagged: Tag[R1], + trace: ZTraceElement + ): TestAspect.WithOut[ + R0 with R1, + Any, + E1, + Any, + ({ type OutEnv[Env] = R0 })#OutEnv, + ({ type OutErr[Err] = Err })#OutErr + ] = + new TestAspect[R0 with R1, Any, E1, Any] { + type OutEnv[Env] = R0 + type OutErr[Err] = Err + def apply[R >: R0 with R1, E >: E1]( + spec: Spec[R, TestFailure[E], TestSuccess] + )(implicit trace: ZTraceElement): Spec[R0, TestFailure[E], TestSuccess] = + spec.provideLayer[TestFailure[E], R0, R0 with R1](ZLayer.environment[R0] ++ layer) + } } + final class ProvideSomeLayerShared[R0](private val dummy: Boolean = true) extends AnyVal { + def apply[E1, R1]( + layer: ZLayer[R0, TestFailure[E1], R1] + )(implicit + ev2: Has.Union[R0, R1], + tagged: Tag[R1], + trace: ZTraceElement + ): TestAspect.WithOut[ + R0 with R1, + Any, + E1, + Any, + ({ type OutEnv[Env] = R0 })#OutEnv, + ({ type OutErr[Err] = Err })#OutErr + ] = + new TestAspect[R0 with R1, Any, E1, Any] { + type OutEnv[Env] = R0 + type OutErr[Err] = Err + def apply[R >: R0 with R1, E >: E1]( + spec: Spec[R, TestFailure[E], TestSuccess] + )(implicit trace: ZTraceElement): Spec[R0, TestFailure[E], TestSuccess] = + spec.provideLayerShared[TestFailure[E], R0, R0 with R1](ZLayer.environment[R0] ++ layer) + } + } } diff --git a/test/shared/src/main/scala/zio/test/TimeoutVariants.scala b/test/shared/src/main/scala/zio/test/TimeoutVariants.scala index d2884c269613..7ff7caf39dd0 100644 --- a/test/shared/src/main/scala/zio/test/TimeoutVariants.scala +++ b/test/shared/src/main/scala/zio/test/TimeoutVariants.scala @@ -26,9 +26,18 @@ trait TimeoutVariants { */ def timeoutWarning( duration: Duration - ): TestAspect[Nothing, Has[Live], Nothing, Any] = + ): TestAspect.WithOut[ + Nothing, + Has[Live], + Nothing, + Any, + ({ type OutEnv[Env] = Env })#OutEnv, + ({ type OutErr[Err] = Err })#OutErr + ] = new TestAspect[Nothing, Has[Live], Nothing, Any] { - def some[R <: Has[Live], E]( + type OutEnv[Env] = Env + type OutErr[Err] = Err + def apply[R <: Has[Live], E]( spec: ZSpec[R, E] )(implicit trace: ZTraceElement): ZSpec[R, E] = { def loop(labels: List[String], spec: ZSpec[R, E]): ZSpec[R with Has[Live], E] = diff --git a/test/shared/src/main/scala/zio/test/ZIOSpecAbstract.scala b/test/shared/src/main/scala/zio/test/ZIOSpecAbstract.scala index 58e9e006b981..d39abd1cf716 100644 --- a/test/shared/src/main/scala/zio/test/ZIOSpecAbstract.scala +++ b/test/shared/src/main/scala/zio/test/ZIOSpecAbstract.scala @@ -27,7 +27,14 @@ abstract class ZIOSpecAbstract extends ZIOApp { self => def spec: ZSpec[Environment with TestEnvironment with Has[ZIOAppArgs], Any] - def aspects: Chunk[TestAspect[Nothing, Environment with TestEnvironment with Has[ZIOAppArgs], Nothing, Any]] = + def aspects: Chunk[TestAspect.WithOut[ + Nothing, + Environment with TestEnvironment with Has[ZIOAppArgs], + Nothing, + Any, + ({ type OutEnv[Env] = Env })#OutEnv, + ({ type OutErr[Err] = Err })#OutErr + ]] = Chunk.empty final def run: ZIO[ZEnv with Has[ZIOAppArgs], Any, Any] = { diff --git a/test/shared/src/main/scala/zio/test/package.scala b/test/shared/src/main/scala/zio/test/package.scala index ef490e002014..915e5d70e087 100644 --- a/test/shared/src/main/scala/zio/test/package.scala +++ b/test/shared/src/main/scala/zio/test/package.scala @@ -112,18 +112,6 @@ package object test extends CompileVariants { )(f: IO[E, A] => ZIO[ZEnv, E1, B])(implicit trace: ZTraceElement): ZIO[R with Has[Live], E1, B] = Live.withLive(zio)(f) - /** - * A `TestAspectAtLeast[R]` is a `TestAspect` that requires at least an `R` in - * its environment. - */ - type TestAspectAtLeastR[R] = TestAspect[Nothing, R, Nothing, Any] - - /** - * A `TestAspectPoly` is a `TestAspect` that is completely polymorphic, having - * no requirements on error or environment. - */ - type TestAspectPoly = TestAspect[Nothing, Any, Nothing, Any] - type TestResult = BoolAlgebra[AssertionResult] object TestResult {