@@ -7,6 +7,8 @@ import scala.util.control.NoStackTrace
77import org .scalacheck .rng .Seed
88import org .scalacheck .{ Arbitrary , Gen }
99import cats .data .Validated
10+ import cats .effect .Concurrent
11+ import cats .MonadThrow
1012
1113trait Checkers {
1214 self : EffectSuiteAux =>
@@ -20,7 +22,7 @@ trait Checkers {
2022 f andThen (b => Prop [F , B ].lift(b))
2123 }
2224
23- // Configuration for property-based tests
25+ /** Configuration for all property-based tests in this suite. */
2426 def checkConfig : CheckConfig = CheckConfig .default
2527
2628 class PartiallyAppliedForall (config : CheckConfig ) {
@@ -43,9 +45,6 @@ trait Checkers {
4345 B : PropF ](
4446 f : (A1 , A2 , A3 ) => B )(
4547 implicit loc : SourceLocation ): F [Expectations ] = {
46- implicit val tuple3Show : Show [(A1 , A2 , A3 )] = {
47- case (a1, a2, a3) => s " ( ${a1.show}, ${a2.show}, ${a3.show}) "
48- }
4948 forall(implicitly[Arbitrary [(A1 , A2 , A3 )]].arbitrary)(liftProp(
5049 f.tupled))
5150 }
@@ -58,10 +57,6 @@ trait Checkers {
5857 B : PropF
5958 ](f : (A1 , A2 , A3 , A4 ) => B )(
6059 implicit loc : SourceLocation ): F [Expectations ] = {
61- implicit val tuple3Show : Show [(A1 , A2 , A3 , A4 )] = {
62- case (a1, a2, a3, a4) =>
63- s " ( ${a1.show}, ${a2.show}, ${a3.show}, ${a4.show}) "
64- }
6560 forall(implicitly[Arbitrary [(A1 , A2 , A3 , A4 )]].arbitrary)(
6661 liftProp(f.tupled))
6762 }
@@ -75,10 +70,6 @@ trait Checkers {
7570 B : PropF
7671 ](f : (A1 , A2 , A3 , A4 , A5 ) => B )(
7772 implicit loc : SourceLocation ): F [Expectations ] = {
78- implicit val tuple3Show : Show [(A1 , A2 , A3 , A4 , A5 )] = {
79- case (a1, a2, a3, a4, a5) =>
80- s " ( ${a1.show}, ${a2.show}, ${a3.show}, ${a4.show}, ${a5.show}) "
81- }
8273 forall(implicitly[Arbitrary [(A1 , A2 , A3 , A4 , A5 )]].arbitrary)(
8374 liftProp(f.tupled))
8475 }
@@ -93,10 +84,6 @@ trait Checkers {
9384 B : PropF
9485 ](f : (A1 , A2 , A3 , A4 , A5 , A6 ) => B )(
9586 implicit loc : SourceLocation ): F [Expectations ] = {
96- implicit val tuple3Show : Show [(A1 , A2 , A3 , A4 , A5 , A6 )] = {
97- case (a1, a2, a3, a4, a5, a6) =>
98- s " ( ${a1.show}, ${a2.show}, ${a3.show}, ${a4.show}, ${a5.show}, ${a6.show}) "
99- }
10087 forall(implicitly[Arbitrary [(A1 , A2 , A3 , A4 , A5 , A6 )]].arbitrary)(
10188 liftProp(f.tupled))
10289 }
@@ -106,6 +93,59 @@ trait Checkers {
10693 forall_(gen, liftProp(f))
10794
10895 private def forall_ [A : Show ](gen : Gen [A ], f : A => F [Expectations ])(
96+ implicit loc : SourceLocation ): F [Expectations ] =
97+ Helpers .forall(config, gen, f)
98+ }
99+
100+ object forall extends PartiallyAppliedForall (checkConfig) {
101+
102+ /** Configuration for this specific property assertion. */
103+ def withConfig (config : CheckConfig ) = new PartiallyAppliedForall (config)
104+ }
105+ }
106+
107+ object Checkers {
108+ // These allow us to define functions that go from F[Expectations]
109+ trait Prop [F [_], A ] {
110+ def lift (a : A ): F [Expectations ]
111+ }
112+
113+ object Prop {
114+ def apply [F [_], B ](implicit ev : Prop [F , B ]): Prop [F , B ] = ev
115+
116+ implicit def wrap [F [_]: Applicative ]: Prop [F , Expectations ] =
117+ new Prop [F , Expectations ] {
118+ def lift (a : Expectations ): F [Expectations ] = Applicative [F ].pure(a)
119+ }
120+
121+ implicit def unwrapped [F [_], FE ](
122+ implicit ev : FE <:< F [Expectations ]): Prop [F , FE ] =
123+ new Prop [F , FE ] {
124+ def lift (a : FE ): F [Expectations ] = ev(a)
125+ }
126+ }
127+
128+ private def failureMessage (ith : Int , seed : Seed , input : String ): String =
129+ s """ Property test failed on try $ith with seed ${seed} and input $input.
130+ |You can reproduce this by adding the following override to your suite:
131+ |
132+ |override def checkConfig = super.checkConfig.withInitialSeed( $seed.toOption) """ .stripMargin
133+
134+ private [scalacheck] class PropertyTestError (
135+ ith : Int ,
136+ seed : Seed ,
137+ input : String ,
138+ cause : Throwable )
139+ extends RuntimeException (failureMessage(ith, seed, input), cause)
140+ with NoStackTrace
141+
142+ object Helpers {
143+
144+ /** Runs assertions in a property test concurrently. */
145+ def forall [F [_]: Defer : Concurrent , A : Show ](
146+ config : CheckConfig ,
147+ gen : Gen [A ],
148+ f : A => F [Expectations ])(
109149 implicit loc : SourceLocation ): F [Expectations ] = {
110150 val params = Gen .Parameters .default.withNoInitialSeed.withSize(
111151 config.maximumGeneratorSize)
@@ -130,37 +170,33 @@ trait Checkers {
130170 .map { status => status.endResult(config) }
131171 }
132172
133- private def seedStream (initial : Seed ): fs2.Stream [F , Seed ] =
134- fs2.Stream .iterate[F , Seed ](initial)(_.slide)
135- }
136-
137- object forall extends PartiallyAppliedForall (checkConfig) {
138- def withConfig (config : CheckConfig ) = new PartiallyAppliedForall (config)
139- }
140-
141- private def testOne [T : Show ](
142- gen : Gen [T ],
143- f : T => F [Expectations ])(
144- params : Gen .Parameters ,
145- seed : Seed ): F [TestResult ] = {
146- Defer [F ](self.effect).defer {
147- gen(params, seed)
148- .traverse(x => f(x).attempt.map(x -> _))
149- .map { (x : Option [(T , Either [Throwable , Expectations ])]) =>
150- x match {
151- case Some ((_, Right (ex))) if ex.run.isValid => TestResult .Success
152- case Some ((t, Right (ex))) => TestResult .Failure (t.show, ex)
153- case Some ((t, Left (exception : ExpectationFailed ))) =>
154- TestResult .Failure (t.show,
155- Expectations (Validated .invalidNel(exception)))
156- case Some ((t, Left (other))) => TestResult .Exception (t.show, other)
157- case None => TestResult .Discard
173+ private def testOne [F [_]: Defer : MonadThrow , T : Show ](
174+ gen : Gen [T ],
175+ f : T => F [Expectations ])(
176+ params : Gen .Parameters ,
177+ seed : Seed ): F [TestResult ] = {
178+ Defer [F ].defer {
179+ gen(params, seed)
180+ .traverse(x => f(x).attempt.map(x -> _))
181+ .map { (x : Option [(T , Either [Throwable , Expectations ])]) =>
182+ x match {
183+ case Some ((_, Right (ex))) if ex.run.isValid => TestResult .Success
184+ case Some ((t, Right (ex))) => TestResult .Failure (t.show, ex)
185+ case Some ((t, Left (exception : ExpectationFailed ))) =>
186+ TestResult .Failure (
187+ t.show,
188+ Expectations (Validated .invalidNel(exception)))
189+ case Some ((t, Left (other))) => TestResult .Exception (t.show, other)
190+ case None => TestResult .Discard
191+ }
158192 }
159- }
193+ }
160194 }
161- }
162195
163- private [scalacheck] case class Status [T ](
196+ private def seedStream [F [_]](initial : Seed ): fs2.Stream [F , Seed ] =
197+ fs2.Stream .iterate[F , Seed ](initial)(_.slide)
198+ }
199+ private case class Status [T ](
164200 succeeded : Int ,
165201 discarded : Int ,
166202 failure : Option [Expectations ]
@@ -198,28 +234,6 @@ trait Checkers {
198234 def start [T ] = Status [T ](0 , 0 , None )
199235 }
200236
201- }
202-
203- object Checkers {
204- trait Prop [F [_], A ] {
205- def lift (a : A ): F [Expectations ]
206- }
207-
208- object Prop {
209- def apply [F [_], B ](implicit ev : Prop [F , B ]): Prop [F , B ] = ev
210-
211- implicit def wrap [F [_]: Applicative ]: Prop [F , Expectations ] =
212- new Prop [F , Expectations ] {
213- def lift (a : Expectations ): F [Expectations ] = Applicative [F ].pure(a)
214- }
215-
216- implicit def unwrapped [F [_], FE ](
217- implicit ev : FE <:< F [Expectations ]): Prop [F , FE ] =
218- new Prop [F , FE ] {
219- def lift (a : FE ): F [Expectations ] = ev(a)
220- }
221- }
222-
223237 private sealed trait TestResult
224238 private object TestResult {
225239 case object Success extends TestResult
@@ -229,17 +243,4 @@ object Checkers {
229243 case class Exception (input : String , error : Throwable ) extends TestResult
230244 }
231245
232- private def failureMessage (ith : Int , seed : Seed , input : String ): String =
233- s """ Property test failed on try $ith with seed ${seed} and input $input.
234- |You can reproduce this by adding the following override to your suite:
235- |
236- |override def checkConfig = super.checkConfig.withInitialSeed( $seed.toOption) """ .stripMargin
237-
238- private class PropertyTestError (
239- ith : Int ,
240- seed : Seed ,
241- input : String ,
242- cause : Throwable )
243- extends RuntimeException (failureMessage(ith, seed, input), cause)
244- with NoStackTrace
245246}
0 commit comments