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

commonMain.io.kotest.property.arrow.optics.OptionalLaws.kt Maven / Gradle / Ivy

@file:Suppress("MemberVisibilityCanBePrivate", "unused")

package io.kotest.property.arrow.optics

import arrow.core.compose
import arrow.core.identity
import arrow.optics.Optional
import io.kotest.property.Arb
import io.kotest.property.PropertyContext
import io.kotest.property.arbitrary.constant
import io.kotest.property.arrow.laws.Law
import io.kotest.property.arrow.laws.equalUnderTheLaw
import io.kotest.property.checkAll

public object OptionalLaws {

  public fun  laws(
    optionalGen: Arb>,
    aGen: Arb,
    bGen: Arb,
    funcGen: Arb<(B) -> B>,
    eqa: (A, A) -> Boolean = { a, b -> a == b },
    eqb: (B?, B?) -> Boolean = { a, b -> a == b }
  ): List = listOf(
    Law("Optional Law: set what you get") { getOptionSet(optionalGen, aGen, eqa) },
    Law("Optional Law: set what you get") { setGetOption(optionalGen, aGen, bGen, eqb) },
    Law("Optional Law: set is idempotent") { setIdempotent(optionalGen, aGen, bGen, eqa) },
    Law("Optional Law: modify identity = identity") { modifyIdentity(optionalGen, aGen, eqa) },
    Law("Optional Law: compose modify") { composeModify(optionalGen, aGen, funcGen, eqa) },
    Law("Optional Law: consistent set with modify") { consistentSetModify(optionalGen, aGen, bGen, eqa) }
  )

  /**
   * Warning: Use only when a `Gen.constant()` applies
   */
  public fun  laws(
    optional: Optional,
    aGen: Arb,
    bGen: Arb,
    funcGen: Arb<(B) -> B>,
    eqa: (A, A) -> Boolean = { a, b -> a == b },
    eqb: (B?, B?) -> Boolean = { a, b -> a == b }
  ): List = laws(Arb.constant(optional), aGen, bGen, funcGen, eqa, eqb)

  public suspend fun  getOptionSet(
    optionalGen: Arb>,
    aGen: Arb,
    eq: (A, A) -> Boolean
  ): PropertyContext =
    checkAll(optionalGen, aGen) { optional, a ->
      optional.run {
        getOrModify(a).fold(::identity) { set(a, it) }
          .equalUnderTheLaw(a, eq)
      }
    }

  public suspend fun  setGetOption(
    optionalGen: Arb>,
    aGen: Arb,
    bGen: Arb,
    eq: (B?, B?) -> Boolean
  ): PropertyContext =
    checkAll(optionalGen, aGen, bGen) { optional, a, b ->
      optional.run {
        getOrNull(set(a, b)).equalUnderTheLaw(getOrNull(a)?.let { b }) { a, b -> eq(a, b) }
      }
    }

  public suspend fun  setIdempotent(
    optionalGen: Arb>,
    aGen: Arb,
    bGen: Arb,
    eq: (A, A) -> Boolean
  ): PropertyContext =
    checkAll(optionalGen, aGen, bGen) { optional, a, b ->
      optional.run {
        set(set(a, b), b).equalUnderTheLaw(set(a, b), eq)
      }
    }

  public suspend fun  modifyIdentity(
    optionalGen: Arb>,
    aGen: Arb,
    eq: (A, A) -> Boolean
  ): PropertyContext =
    checkAll(optionalGen, aGen) { optional, a ->
      optional.run {
        modify(a, ::identity).equalUnderTheLaw(a, eq)
      }
    }

  public suspend fun  composeModify(
    optionalGen: Arb>,
    aGen: Arb,
    funcGen: Arb<(B) -> B>,
    eq: (A, A) -> Boolean
  ): PropertyContext =
    checkAll(optionalGen, aGen, funcGen, funcGen) { optional, a, f, g ->
      optional.run {
        modify(modify(a, f), g).equalUnderTheLaw(modify(a, g compose f), eq)
      }
    }

  public suspend fun  consistentSetModify(
    optionalGen: Arb>,
    aGen: Arb,
    bGen: Arb,
    eq: (A, A) -> Boolean
  ): PropertyContext =
    checkAll(optionalGen, aGen, bGen) { optional, a, b ->
      optional.run {
        set(a, b).equalUnderTheLaw(modify(a) { b }, eq)
      }
    }
}