scalatest / scalatestplus-scalacheck

ScalaTest + ScalaCheck provides integration support between ScalaTest and ScalaCheck.
Apache License 2.0
57 stars 24 forks source link

Support scalatest assertions in Checkers #50

Open brandon-leapyear opened 3 years ago

brandon-leapyear commented 3 years ago

As a follow up to https://github.com/scalatest/scalatest/issues/251, ScalaCheckDrivenPropertyChecks isn't good for nested forAlls and is also missing features like forAllNoShrink.

It seems like Checkers is what I want anyway, to explicitly build up a Prop, then check it. But it currently doesn't work with normal scalatest assertions like

check {
  forAll { a: Int =>
    foo(a) shouldBe 42
  }
}

This currently throws a compile-time error:

No implicit view available from org.scalatest.Assertion => org.scalacheck.Prop.

It would be nice to augment Checkers or provide a separate class to include support for normal scalatest assertions.

brandon-leapyear commented 3 years ago

:sparkles: This is an old work account. Please reference @brandonchinn178 for all future communication :sparkles:


Currently working around by writing my own Checkers trait with an implicit function to convert an Assertion into a Prop

import org.scalacheck.Prop
import org.scalacheck.Prop._
import org.scalatest.Assertion
import org.scalatest.exceptions.DiscardedEvaluationException
import org.scalatestplus.scalacheck

// https://github.com/scalatest/scalatestplus-scalacheck/issues/50
trait Checkers extends scalacheck.Checkers {
  implicit def assertionToProp(test: Assertion)
    (implicit
      asserting: scalacheck.CheckerAsserting[Assertion]
    ): Prop = {
      val (unmetCondition, succeeded, exception) =
        try {
          val (succeeded, cause) = asserting.succeed(test)
          (false, succeeded, cause)
        }
        catch {
          case e: DiscardedEvaluationException => (true, false, None)
          case e: Throwable => (false, false, Some(e))
        }
      !unmetCondition ==> (
        if (exception.isEmpty) {
          if (succeeded)
            Prop.passed
          else
            Prop.falsified
        }
        else
          Prop.exception(exception.get)
      )
    }
}