zio.prelude.laws.Gens.scala Maven / Gradle / Ivy
The newest version!
/*
* Copyright 2020-2023 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.prelude.laws
import zio.Trace
import zio.prelude._
import zio.prelude.fx.Cause
import zio.prelude.newtypes.Natural
import zio.test._
/**
* Provides generators for data types from _ZIO Prelude_.
*/
object Gens {
/**
* A generator of natural numbers. Shrinks toward '0'.
*/
val anyNatural: Gen[Any, Natural] =
natural(Natural.zero, Natural.unsafeMake(Int.MaxValue))
/**
* A generator of natural numbers inside the specified range: [start, end].
* The shrinker will shrink toward the lower end of the range ("smallest").
*/
def natural(min: Natural, max: Natural)(implicit trace: Trace): Gen[Any, Natural] =
Gen.int(min, max).map(Natural.unsafeMake)
def parSeq[R <: Sized, Z <: Unit, A](z: Gen[R, Z], a: Gen[R, A]): Gen[R, ParSeq[Z, A]] = {
val failure = a.map(Cause.single)
val empty = z.map(_ => Cause.empty.asInstanceOf[ParSeq[Nothing, Nothing]])
def sequential(n: Int) = Gen.suspend {
for {
i <- Gen.int(1, n - 1)
l <- parSeqN(i)
r <- parSeqN(n - i)
} yield Cause.Then(l, r)
}
def parallel(n: Int) = Gen.suspend {
for {
i <- Gen.int(1, n - 1)
l <- parSeqN(i)
r <- parSeqN(n - i)
} yield Cause.Both(l, r)
}
def parSeqN(n: Int): Gen[R, ParSeq[Z, A]] = Gen.suspend {
if (n == 1) Gen.oneOf(empty, failure)
else Gen.oneOf(sequential(n), parallel(n))
}
Gen.small(parSeqN, 1)
}
/**
* A generator of `NonEmptyList` values.
*/
def nonEmptyListOf[R <: Sized, A](a: Gen[R, A]): Gen[R, NonEmptyList[A]] =
Gen.listOf1(a).map(NonEmptyList.fromCons)
/**
* A generator of `NonEmptyMultiSet` values.
*/
def nonEmptyMultiSetOf[R <: Sized, A](a: Gen[R, A]): Gen[R, NonEmptyMultiSet[A]] =
Gen.mapOf1(a, Gen.size.map(Natural.unsafeMake)).map(NonEmptyMultiSet.fromMapOption(_).get)
/**
* A generator of `NonEmptySet` values.
*/
def nonEmptySetOf[R <: Sized, A](a: Gen[R, A]): Gen[R, NonEmptySet[A]] =
Gen.setOf1(a).map(NonEmptySet.fromSetOption(_).get)
/**
* A generator of state transition functions.
*/
def state[R, S, A](s: Gen[R, S], a: Gen[R, A]): Gen[R, State[S, A]] =
Gen.function[R, S, (A, S)](a <*> s).map(State.modify)
/**
* A generator of `These` values.
*/
def these[R <: Sized, A, B](a: Gen[R, A], b: Gen[R, B]): Gen[R, These[A, B]] =
Gen.oneOf(a.map(These.left), b.map(These.right), a.zipWith(b)(These.both))
/**
* A generator of `Validation` values.
*/
def validation[R <: Sized, W, E, A](
w: Gen[R, W],
e: Gen[R, E],
a: Gen[R, A]
): Gen[R, ZValidation[W, E, A]] =
Gen.chunkOf(w).flatMap { w =>
Gen.either(Gen.chunkOf1(e), a).map {
case Left(e) => Validation.Failure(w, e)
case Right(a) => Validation.Success(w, a)
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy