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

org.specs2.matcher.ValueCheck.scala Maven / Gradle / Ivy

There is a newer version: 5.5.8
Show newest version
package org.specs2
package matcher

import execute.*
import org.specs2.execute.AsResult
import describe.*
import text.Quote.*
import Expectations.*
import control.*
import ResultLogicalCombinators.{given, *}

/** Common interface for checks of a value of type T:
  *
  *   - a expected single value of type T
  *   - a Matcher[T]
  *   - a function returning a type R having an AsResult instance
  */
trait ValueCheck[T]:
  outer =>

  def check: T => Result
  def checkNot: T => Result

  def negate: ValueCheck[T] =
    new ValueCheck[T]:
      def check: T => Result = outer.checkNot
      def checkNot: T => Result = outer.check

object ValueCheck:

  given typedValueCheck[T: Diffable]: Conversion[T, BeEqualTypedValueCheck[T]] with
    def apply(expected: T): BeEqualTypedValueCheck[T] =
      new BeEqualTypedValueCheck[T](expected)

  def alwaysOk[T]: ValueCheck[T] =
    new ValueCheck[T]:
      def check: T => Result = (t: T) => StandardResults.success
      def checkNot: T => Result = (t: T) => StandardResults.failure

  def toOptionCheck[T](valueCheck: ValueCheck[T]): ValueCheck[Option[T]] =
    new ValueCheck[Option[T]]:
      def check = (t: Option[T]) => t.map(valueCheck.check).getOrElse(Failure("Expected a value, got None"))

      def checkNot = (t: Option[T]) => check(t).not

/** implicit conversions used to create ValueChecks
  */
trait ValueChecks extends ValueChecksBase:

  /** a partial function returning an object having an AsResult instance can check a value */
  given partialfunctionIsValueCheck[T, R: AsResult]: Conversion[PartialFunction[T, R], ValueCheck[T]] with
    def apply(f: PartialFunction[T, R]): ValueCheck[T] =
      new ValueCheck[T]:
        def check = (t: T) => {
          if f.isDefinedAt(t) then functionResult(AsResult.safely(f(t)), t)
          else Failure("undefined function for " + q(t))
        }

        def checkNot = (t: T) => Results.negate(check(t))

  /** a check of type T can be downcasted implicitly to a check of type S >: T */
  given downcastBeEqualTypedValueCheck[T, S >: T]: Conversion[BeEqualTypedValueCheck[T], ValueCheck[S]] with
    def apply(check: BeEqualTypedValueCheck[T]): ValueCheck[S] =
      check.downcast[S]

trait ValueChecksBase extends ValueChecksLowImplicits:

  /** a Matcher[T] can check a value */
  given matcherIsValueCheck[T]: Conversion[Matcher[T], ValueCheck[T]] with
    def apply(m: Matcher[T]): ValueCheck[T] =
      new ValueCheck[T]:
        def check = (t: T) => AsResult.safely(m(createExpectable(t)))
        def checkNot = (t: T) => AsResult.safely(m.not(createExpectable(t)))

  /** an expected value can be used to check another value */
  def valueIsTypedValueCheck[T](expected: T)(using di: Diffable[T]): BeEqualTypedValueCheck[T] =
    expected

trait ValueChecksLowImplicits:
  /** a function returning an object having an AsResult instance can check a value */
  given functionIsValueCheck[T, R: AsResult]: Conversion[T => R, ValueCheck[T]] with
    def apply(f: T => R): ValueCheck[T] =
      new ValueCheck[T]:
        def check = (t: T) => functionResult(AsResult.safely(f(t)), t)
        def checkNot = (t: T) => Results.negate(check(t))

  private[matcher] def functionResult[T](result: Result, t: T) =
    if Seq("true", "false").contains(result.message) then
      result.updateMessage(m => s"the function returns ${q(m)} on ${q(t)}")
    else result

object ValueChecks extends ValueChecks

/** ValueCheck for a typed expected value. It uses the BeEqualTo matcher */
case class BeEqualTypedValueCheck[T: Diffable](expected: T) extends ValueCheck[T]:
  private lazy val matcher = new EqualityMatcher(expected)
  def check = (t: T) => AsResult.safely(matcher(createExpectable(t)))
  def checkNot = (t: T) => AsResult.safely(matcher.not(createExpectable(t)))

  def downcast[S] = new BeEqualValueCheck[S](expected)

/** ValueCheck for an untyped expected value. It uses the BeEqualTo matcher */
case class BeEqualValueCheck[T](expected: Any) extends ValueCheck[T]:
  private lazy val matcher = new BeEqualTo(expected)
  def check = (t: T) => AsResult.safely(matcher(createExpectable(t)))
  def checkNot = (t: T) => AsResult.safely(matcher.not(createExpectable(t)))




© 2015 - 2024 Weber Informatics LLC | Privacy Policy