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

dev.tauri.choam.laws.TestInstances.scala Maven / Gradle / Ivy

The newest version!
/*
 * SPDX-License-Identifier: Apache-2.0
 * Copyright 2016-2024 Daniel Urban and contributors listed in NOTICE.txt
 *
 * 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 dev.tauri.choam
package laws

import cats.Eq
import cats.data.Ior

import org.scalacheck.{ Gen, Arbitrary, Cogen }

import internal.mcas.Mcas

trait TestInstances extends TestInstancesLowPrio0 { self =>

  def mcasImpl: Mcas

  implicit def arbRef[A](implicit arbA: Arbitrary[A]): Arbitrary[Ref[A]] = Arbitrary {
    import refs.Ref2
    arbA.arbitrary.flatMap { a =>
      Gen.oneOf(
        Gen.oneOf(
          Gen.delay(Ref.unsafeUnpadded(a)),
          Gen.delay(Ref.unsafePadded(a)),
        ),
        Gen.oneOf(
          Gen.delay(Ref2.unsafeP1P1[A, String](a, "foo")._1),
          Gen.delay(Ref2.unsafeP1P1[String, A]("foo", a)._2),
          Gen.delay(Ref2.unsafeP2[A, String](a, "foo")._1),
          Gen.delay(Ref2.unsafeP2[String, A]("foo", a)._2),
        ),
        Gen.choose(1, 8).flatMap { s =>
          Arbitrary.arbBool.arbitrary.flatMap { sparse =>
            Arbitrary.arbBool.arbitrary.flatMap { flat =>
              val str = Ref.Array.AllocationStrategy(sparse = sparse, flat = flat, padded = false)
              Gen.delay { Ref.unsafeArray[A](size = s, initial = a, strategy = str) }.flatMap { arr =>
                Gen.oneOf(Gen.const(0), Gen.choose(0, s - 1)).flatMap { idx =>
                  Gen.delay { arr.unsafeGet(idx) }
                }
              }
            }
          }
        }
      )
    }
  }

  implicit def cogenRef[A]: Cogen[Ref[A]] = {
    Cogen.cogenLong.contramap[Ref[A]] { ref =>
      ref.loc.id
    }
  }

  implicit def arbAxn[B](
    implicit
    arbB: Arbitrary[B],
  ): Arbitrary[Axn[B]] = {
    implicit val arbAny: Arbitrary[Any] = Arbitrary(
      Gen.oneOf(
        Gen.const(()),
        Gen.const(null),
        Gen.alphaNumStr,
        Gen.long,
      )
    )
    implicit val cogAny: Cogen[Any] = Cogen.cogenInt.contramap[Any](_.##)
    Arbitrary { self.arbRxn[Any, B].arbitrary }
  }

  implicit def arbIor[A, B](implicit arbA: Arbitrary[A], arbB: Arbitrary[B]): Arbitrary[Ior[A, B]] = Arbitrary {
    Gen.oneOf(
      arbA.arbitrary.map(Ior.left),
      arbB.arbitrary.map(Ior.right),
      arbA.arbitrary.flatMap { a => arbB.arbitrary.map { b => Ior.both(a, b) } },
    )
  }

  implicit def cogenIor[A, B](implicit cogA: Cogen[A], cogB: Cogen[B]): Cogen[Ior[A, B]] = {
    Cogen { (seed, ior) =>
      ior.fold(
        a => cogA.perturb(seed.next, a),
        b => cogB.perturb(seed.next.next, b),
        (a, b) => cogB.perturb(cogA.perturb(seed.next.next.next, a), b)
      )
    }
  }

  implicit def testingEqAxn[A](implicit equA: Eq[A]): Eq[Axn[A]] = new Eq[Axn[A]] {
    override def eqv(x: Axn[A], y: Axn[A]): Boolean = {
      val rx = self.unsafePerformForTest(x, ())
      val ry = self.unsafePerformForTest(y, ())
      equA.eqv(rx, ry)
    }
  }

  private[choam] final def unsafePerformForTest[A, B](rxn: A =#> B, a: A): B = {
    rxn.unsafePerform(a, self.mcasImpl)
  }
}

private[choam] sealed trait TestInstancesLowPrio0 extends TestInstancesLowPrio1 { self: TestInstances =>

  implicit def arbRxn[A, B](
    implicit
    arbA: Arbitrary[A],
    arbB: Arbitrary[B],
    arbAB: Arbitrary[A => B],
    arbAA: Arbitrary[A => A]
  ): Arbitrary[Rxn[A, B]] = Arbitrary {
    arbResetRxn[A, B].arbitrary.map(_.toRxn)
  }

  private def arbResetRxn[A, B](
    implicit
    arbA: Arbitrary[A],
    arbB: Arbitrary[B],
    arbAB: Arbitrary[A => B],
    arbAA: Arbitrary[A => A]
  ): Arbitrary[ResetRxn[A, B]] = Arbitrary {
    Gen.oneOf(
      arbAB.arbitrary.map(ab => ResetRxn(Rxn.lift[A, B](ab))),
      arbB.arbitrary.map(b => ResetRxn(Rxn.ret(b))),
      Gen.lzy {
        arbResetRxn[A, B].arbitrary.map { rxn =>
          ResetRxn(Rxn.identity[A]) >>> rxn
        }
      },
      Gen.lzy {
        for {
          one <- arbResetRxn[A, B].arbitrary
          two <- arbResetRxn[A, B].arbitrary
        } yield one + two
      },
      Gen.lzy {
        for {
          one <- arbResetRxn[A, A].arbitrary
          two <- arbResetRxn[A, B].arbitrary
        } yield one >>> two
      },
      Gen.lzy {
        for {
          flag <- Arbitrary.arbBool.arbitrary
          one <- arbResetRxn[A, B].arbitrary
          two <- arbResetRxn[A, B].arbitrary
        } yield (one * two).map { bb => if (flag) bb._1 else bb._2 }
      },
      arbB.arbitrary.flatMap { b =>
        Gen.delay {
          val ref = Ref.unsafe(b)
          ResetRxn(ref.unsafeDirectRead, Set(ResetRef(ref, b)))
        }
      },
      for {
        ab <- arbAB.arbitrary
        a0 <- arbA.arbitrary
        ref <- Gen.delay { Ref.unsafe(a0) }
      } yield {
        val rxn = ref.upd[A, B] { (aOld, aInput) => (aInput, ab(aOld)) }
        ResetRxn(rxn, Set(ResetRef(ref, a0)))
      },
      // TODO: this generates `r: Rxn[A, B]` so that `r * r` can never commit
      // for {
      //   aa <- arbAA.arbitrary
      //   ab <- arbAB.arbitrary
      //   a0 <- arbA.arbitrary
      //   ref <- Gen.delay { Ref.unsafe(a0) }
      // } yield {
      //   val rxn = ref.unsafeDirectRead.flatMap { oldA =>
      //     val newA = aa(oldA)
      //     ref.unsafeCas(oldA, newA).as(ab(newA))
      //   }
      //   ResetRxn(rxn, Set(ResetRef(ref, a0)))
      // },
      Gen.lzy {
        for {
          r <- arbResetRxn[A, B].arbitrary
          b <- arbB.arbitrary
          b2 <- arbB.arbitrary
          ref <- Gen.delay { Ref.unsafe[B](b) }
        } yield {
          ResetRxn(
            r.rxn.postCommit(ref.upd[B, Unit] { case (_, _) => (b2, ()) }),
            r.refs + ResetRef(ref, b)
          )
        }
      },
      Gen.lzy {
        arbResetRxn[A, B].arbitrary.map { rxn =>
          ResetRxn(Rxn.unsafe.retry[A, B]) + rxn
        }
      },
      Gen.lzy {
        Arbitrary.arbString.arbitrary.flatMap { s =>
          arbResetRxn[A, B].arbitrary.map { rr =>
            ResetRxn(
              rr.rxn.first[String].contramap[A](a => (a, s)).map(_._1),
              rr.refs
            )
          }
        }
      },
    )
  }

  implicit def testingEqRxn[A, B](implicit arbA: Arbitrary[A], equB: Eq[B]): Eq[Rxn[A, B]] = new Eq[Rxn[A, B]] {
    override def eqv(x: Rxn[A, B], y: Rxn[A, B]): Boolean = {
      (1 to 32).forall { _ =>
        val a = arbA.arbitrary.sample.getOrElse {
          throw new IllegalStateException("no sample")
        }
        val rx = self.unsafePerformForTest(x, a)
        val ry = self.unsafePerformForTest(y, a)
        equB.eqv(rx, ry)
      }
    }
  }
}

private[choam] sealed trait TestInstancesLowPrio1 { self: TestInstances =>
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy