org.scalatestplus.scalacheck.CheckerAsserting.scala Maven / Gradle / Ivy
The newest version!
/*
* Copyright 2001-2013 Artima, Inc.
*
* 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 org.scalatestplus.scalacheck
import org.scalactic.{Resources => _, FailureMessages => _, UnquotedString => _, _}
import NameUtil.getSimpleNameOfAnObjectsClass
import org.scalacheck.Prop
import org.scalacheck.Prop.Arg
import org.scalacheck.Test
import org.scalacheck.util.Pretty
import org.scalatest.Assertion
//import org.scalatest.Expectation
import org.scalatest.Fact
import org.scalatest.Succeeded
import org.scalatest.exceptions.StackDepthException
import org.scalatestplus.scalacheck.FailureMessages.decorateToStringValue
import org.scalatest.exceptions.GeneratorDrivenPropertyCheckFailedException
import org.scalatest.exceptions.StackDepth
/**
* Supertrait for CheckerAsserting
typeclasses, which are used to implement and determine the result
* type of [[org.scalatest.prop.GeneratorDrivenPropertyChecks GeneratorDrivenPropertyChecks]]'s apply
and forAll
method.
*
*
* Currently, an [[org.scalatest.prop.GeneratorDrivenPropertyChecks GeneratorDrivenPropertyChecks]] expression will have result type Assertion
, if the function passed has result type Assertion
,
* else it will have result type Unit
.
*
*/
trait CheckerAsserting[T] {
/**
* The result type of the check
method.
*/
type Result
def succeed(result: T): (Boolean, Option[Throwable])
/**
* Perform the property check using the given Prop
and Test.Parameters
.
*
* @param p the Prop
to be used to check
* @param prms the Test.Parameters
to be used to check
* @param prettifier the Prettifier
to be used to prettify error message
* @param pos the Position
of the caller site
* @param argNames the list of argument names
* @return the Result
of the property check.
*/
def check(p: Prop, prms: Test.Parameters, prettifier: Prettifier, pos: source.Position, argNames: Option[List[String]] = None): Result
}
/**
* Class holding lowest priority CheckerAsserting
implicit, which enables [[org.scalatest.prop.GeneratorDrivenPropertyChecks GeneratorDrivenPropertyChecks]] expressions that have result type Unit
.
*/
abstract class UnitCheckerAsserting {
/**
* Abstract subclass of CheckerAsserting
that provides the bulk of the implementations of CheckerAsserting
* check
method.
*/
/* protected[scalatest]*/ abstract class CheckerAssertingImpl[T] extends CheckerAsserting[T] {
import CheckerAsserting._
/**
* Check the given Prop
and Test.Parameters
by calling [[http://www.scalacheck.org ScalaCheck]]'s Test.check
.
* If the check succeeds, call indicateSuccess
, else call indicateFailure
.
*
*
* @param p the Prop
to be used to check
* @param prms the Test.Parameters
to be used to check
* @param prettifier the Prettifier
to be used to prettify error message
* @param pos the Position
of the caller site
* @param argNames the list of argument names
* @return the Result
of the property check.
*/
def check(p: Prop, prms: Test.Parameters, prettifier: Prettifier, pos: source.Position, argNames: Option[List[String]] = None): Result = {
val result = Test.check(prms, p)
if (!result.passed) {
val (args, labels) = argsAndLabels(result)
(result.status: @unchecked) match {
case Test.Exhausted =>
val failureMsg =
if (result.succeeded == 1)
FailureMessages.propCheckExhaustedAfterOne(prettifier, result.discarded)
else
FailureMessages.propCheckExhausted(prettifier, result.succeeded, result.discarded)
indicateFailure(
sde => failureMsg,
failureMsg,
args,
labels,
None,
pos
)
case Test.Failed(scalaCheckArgs, scalaCheckLabels) =>
val stackDepth = 1
indicateFailure(
sde => FailureMessages.propertyException(prettifier, UnquotedString(sde.getClass.getSimpleName)) + "\n" +
( sde.failedCodeFileNameAndLineNumberString match { case Some(s) => " (" + s + ")"; case None => "" }) + "\n" +
" " + FailureMessages.propertyFailed(prettifier, result.succeeded) + "\n" +
(
sde match {
case sd: StackDepth if sd.failedCodeFileNameAndLineNumberString.isDefined =>
" " + FailureMessages.thrownExceptionsLocation(prettifier, UnquotedString(sd.failedCodeFileNameAndLineNumberString.get)) + "\n"
case _ => ""
}
) +
" " + FailureMessages.occurredOnValues + "\n" +
prettyArgs(getArgsWithSpecifiedNames(argNames, scalaCheckArgs), prettifier) + "\n" +
" )" +
getLabelDisplay(scalaCheckLabels),
FailureMessages.propertyFailed(prettifier, result.succeeded),
scalaCheckArgs,
scalaCheckLabels.toList,
None,
pos
)
case Test.PropException(scalaCheckArgs, e, scalaCheckLabels) =>
indicateFailure(
sde => FailureMessages.propertyException(prettifier, UnquotedString(e.getClass.getSimpleName)) + "\n" +
" " + FailureMessages.thrownExceptionsMessage(prettifier, if (e.getMessage == null) "None" else UnquotedString(e.getMessage)) + "\n" +
(
e match {
case sd: StackDepth if sd.failedCodeFileNameAndLineNumberString.isDefined =>
" " + FailureMessages.thrownExceptionsLocation(prettifier, UnquotedString(sd.failedCodeFileNameAndLineNumberString.get)) + "\n"
case _ => ""
}
) +
" " + FailureMessages.occurredOnValues + "\n" +
prettyArgs(getArgsWithSpecifiedNames(argNames, scalaCheckArgs), prettifier) + "\n" +
" )" +
getLabelDisplay(scalaCheckLabels),
FailureMessages.propertyException(prettifier, UnquotedString(e.getClass.getName)),
scalaCheckArgs,
scalaCheckLabels.toList,
Some(e),
pos
)
}
} else indicateSuccess(FailureMessages.propertyCheckSucceeded)
}
private[scalacheck] def indicateSuccess(message: => String): Result
private[scalacheck] def indicateFailure(messageFun: StackDepthException => String, undecoratedMessage: => String, scalaCheckArgs: List[Any], scalaCheckLabels: List[String], optionalCause: Option[Throwable], pos: source.Position): Result
}
/**
* Provides support of [[org.scalatest.enablers.CheckerAsserting CheckerAsserting]] for Unit. Do nothing when the check succeeds,
* but throw [[org.scalatest.exceptions.GeneratorDrivenPropertyCheckFailedException GeneratorDrivenPropertyCheckFailedException]]
* when check fails.
*/
implicit def assertingNatureOfT[T]: CheckerAsserting[T] { type Result = Unit } =
new CheckerAssertingImpl[T] {
type Result = Unit
def succeed(result: T) = (true, None)
private[scalacheck] def indicateSuccess(message: => String): Unit = ()
private[scalacheck] def indicateFailure(messageFun: StackDepthException => String, undecoratedMessage: => String, scalaCheckArgs: List[Any], scalaCheckLabels: List[String], optionalCause: Option[Throwable], pos: source.Position): Unit = {
throw new GeneratorDrivenPropertyCheckFailedException(
messageFun,
optionalCause,
pos,
None,
undecoratedMessage,
scalaCheckArgs,
None,
scalaCheckLabels.toList
)
}
}
}
/**
* Abstract class that in the future will hold an intermediate priority CheckerAsserting
implicit, which will enable inspector expressions
* that have result type Expectation
, a more composable form of assertion that returns a result instead of throwing an exception when it fails.
*/
abstract class ExpectationCheckerAsserting extends UnitCheckerAsserting {
/*implicit def assertingNatureOfExpectation(implicit prettifier: Prettifier): CheckerAsserting[Expectation] { type Result = Expectation } = {
new CheckerAssertingImpl[Expectation] {
type Result = Expectation
def succeed(result: Expectation) = (result.isYes, result.cause)
private[scalacheck] def indicateSuccess(message: => String): Expectation = Fact.Yes(message)(prettifier)
private[scalacheck] def indicateFailure(messageFun: StackDepthException => String, undecoratedMessage: => String, scalaCheckArgs: List[Any], scalaCheckLabels: List[String], optionalCause: Option[Throwable], pos: source.Position): Expectation = {
val gdpcfe =
new GeneratorDrivenPropertyCheckFailedException(
messageFun,
optionalCause,
pos,
None,
undecoratedMessage,
scalaCheckArgs,
None,
scalaCheckLabels.toList
)
val message: String = gdpcfe.getMessage
Fact.No(message)(prettifier)
}
}
}*/
}
/**
* Companion object to CheckerAsserting
that provides two implicit providers, a higher priority one for passed functions that have result
* type Assertion
, which also yields result type Assertion
, and one for any other type, which yields result type Unit
.
*/
object CheckerAsserting extends ExpectationCheckerAsserting {
/**
* Provides support of [[org.scalatest.enablers.CheckerAsserting CheckerAsserting]] for Assertion. Returns [[org.scalatest.Succeeded Succeeded]] when the check succeeds,
* but throw [[org.scalatest.exceptions.GeneratorDrivenPropertyCheckFailedException GeneratorDrivenPropertyCheckFailedException]]
* when check fails.
*/
implicit def assertingNatureOfAssertion: CheckerAsserting[Assertion] { type Result = Assertion } = {
new CheckerAssertingImpl[Assertion] {
type Result = Assertion
def succeed(result: Assertion) = (true, None)
private[scalacheck] def indicateSuccess(message: => String): Assertion = Succeeded
private[scalacheck] def indicateFailure(messageFun: StackDepthException => String, undecoratedMessage: => String, scalaCheckArgs: List[Any], scalaCheckLabels: List[String], optionalCause: Option[Throwable], pos: source.Position): Assertion = {
throw new GeneratorDrivenPropertyCheckFailedException(
messageFun,
optionalCause,
pos,
None,
undecoratedMessage,
scalaCheckArgs,
None,
scalaCheckLabels.toList
)
}
}
}
private[scalacheck] def getArgsWithSpecifiedNames(argNames: Option[List[String]], scalaCheckArgs: List[Arg[Any]]) = {
if (argNames.isDefined) {
// length of scalaCheckArgs should equal length of argNames
val zipped = argNames.get zip scalaCheckArgs
zipped map { case (argName, arg) => arg.copy(label = argName) }
}
else
scalaCheckArgs
}
private[scalacheck] def getLabelDisplay(labels: Set[String]): String =
if (labels.size > 0)
"\n " + (if (labels.size == 1) Resources.propCheckLabel else Resources.propCheckLabels) + "\n" + labels.map(" " + _).mkString("\n")
else
""
private[scalacheck] def argsAndLabels(result: Test.Result): (List[Any], List[String]) = {
val (scalaCheckArgs, scalaCheckLabels) =
result.status match {
case Test.Proved(args) => (args.toList, List())
case Test.Failed(args, labels) => (args.toList, labels.toList)
case Test.PropException(args, _, labels) => (args.toList, labels.toList)
case _ => (List(), List())
}
val args: List[Any] = for (scalaCheckArg <- scalaCheckArgs.toList) yield scalaCheckArg.arg
// scalaCheckLabels is a Set[String], I think
val labels: List[String] = for (scalaCheckLabel <- scalaCheckLabels.iterator.toList) yield scalaCheckLabel
(args, labels)
}
// TODO: Internationalize these, and make them consistent with FailureMessages stuff (only strings get quotes around them, etc.)
private[scalacheck] def prettyTestStats(result: Test.Result, prettifier: Prettifier) = result.status match {
case Test.Proved(args) =>
"OK, proved property: \n" + prettyArgs(args, prettifier)
case Test.Passed =>
"OK, passed " + result.succeeded + " tests."
case Test.Failed(args, labels) =>
"Falsified after " + result.succeeded + " passed tests:\n" + prettyLabels(labels) + prettyArgs(args, prettifier)
case Test.Exhausted =>
"Gave up after only " + result.succeeded + " passed tests. " +
result.discarded + " tests were discarded."
case Test.PropException(args, e, labels) =>
FailureMessages.propertyException(prettifier, UnquotedString(e.getClass.getSimpleName)) + "\n" + prettyLabels(labels) + prettyArgs(args, prettifier)
}
private[scalacheck] def prettyLabels(labels: Set[String]) = {
if (labels.isEmpty) ""
else if (labels.size == 1) "Label of failing property: " + labels.iterator.next + "\n"
else "Labels of failing property: " + labels.mkString("\n") + "\n"
}
//
// If scalacheck arg contains a type that
// decorateToStringValue processes, then let
// decorateToStringValue handle it. Otherwise use its
// prettyArg method to generate the display string.
//
// Passes 0 as verbosity value to prettyArg function.
//
private[scalacheck] def decorateArgToStringValue(arg: Arg[_], prettifier: Prettifier): String =
arg.arg match {
case null => decorateToStringValue(prettifier, arg.arg)
case _: Unit => decorateToStringValue(prettifier, arg.arg)
case _: String => decorateToStringValue(prettifier, arg.arg)
case _: Char => decorateToStringValue(prettifier, arg.arg)
case _: Array[_] => decorateToStringValue(prettifier, arg.arg)
case _ => arg.prettyArg(new Pretty.Params(0))
}
private[scalacheck] def prettyArgs(args: List[Arg[_]], prettifier: Prettifier) = {
val strs = for((a, i) <- args.zipWithIndex) yield (
" " +
(if (a.label == "") "arg" + i else a.label) +
" = " + decorateArgToStringValue(a, prettifier) + (if (i < args.length - 1) "," else "") +
(if (a.shrinks > 0) " // " + a.shrinks + (if (a.shrinks == 1) " shrink" else " shrinks") else "")
)
strs.mkString("\n")
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy