org.scalatest.FactInspectors.scala Maven / Gradle / Ivy
/*
* 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.scalatest
/**
* Provides nestable inspector methods (or just inspectors) that enable assertions to be made about collections.
*
*
* For example, the forAll
method enables you to state that something should be true about all elements of a collection, such
* as that all elements should be positive:
*
*
*
* scala> import org.scalatest._
* import org.scalatest._
*
* scala> import Assertions._
* import Assertions._
*
* scala> import Inspectors._
* import Inspectors._
*
* scala> val xs = List(1, 2, 3, 4, 5)
* xs: List[Int] = List(1, 2, 3, 4, 5)
*
* scala> forAll (xs) { x => assert(x > 0) }
*
*
*
* Or, with matchers:
*
*
*
* scala> import Matchers._
* import Matchers._
*
* scala> forAll (xs) { x => x should be > 0 }
*
*
*
* To make assertions about nested collections, you can nest the inspector method invocations.
* For example, given the following list of lists of Int
:
*
*
*
* scala> val yss =
* | List(
* | List(1, 2, 3),
* | List(1, 2, 3),
* | List(1, 2, 3)
* | )
* yss: List[List[Int]] = List(List(1, 2, 3), List(1, 2, 3), List(1, 2, 3))
*
*
*
* You can assert that all Int
elements in all nested lists are positive by nesting two forAll
method invocations, like this:
*
*
*
* scala> forAll (yss) { ys =>
* | forAll (ys) { y => y should be > 0 }
* | }
*
*
*
* The full list of inspector methods are:
*
*
*
* forAll
- succeeds if the assertion holds true for every element
* forAtLeast
- succeeds if the assertion holds true for at least the specified number of elements
* forAtMost
- succeeds if the assertion holds true for at most the specified number of elements
* forBetween
- succeeds if the assertion holds true for between the specified minimum and maximum number of elements, inclusive
* forEvery
- same as forAll
, but lists all failing elements if it fails (whereas forAll
just reports the first failing element)
* forExactly
- succeeds if the assertion holds true for exactly the specified number of elements
*
*
*
* The error messages produced by inspector methods are designed to make sense no matter how deeply you nest the method invocations.
* Here's an example of a nested inspection that fails and the resulting error message:
*
*
*
* scala> forAll (yss) { ys =>
* | forAll (ys) { y => y should be < 2 }
* | }
* org.scalatest.exceptions.TestFailedException: forAll failed, because:
* at index 0, forAll failed, because:
* at index 1, 2 was not less than 2 (<console>:20)
* in List(1, 2, 3) (<console>:20)
* in List(List(1, 2, 3), List(1, 2, 3), List(1, 2, 3))
* at org.scalatest.InspectorsHelper$.doForAll(Inspectors.scala:146)
* ...
*
*
*
* One way the error message is designed to help you understand the error is by using indentation that mimics the indentation of the
* source code (optimistically assuming the source will be nicely indented). The error message above indicates the outer forAll
failed
* because its initial List
(i.e., at index 0) failed
* the assertion, which was that all elements of that initial List[Int]
at index 0 should be less than 2. This assertion failed because index 1 of
* that inner list contained the value 2, which was indeed “not less than 2.” The error message for the inner list is an indented line inside the error message
* for the outer list. The actual contents of each list are displayed at the end in inspector error messages, also indented appropriately. The actual contents
* are placed at the end so that for very large collections, the contents will not drown out and make it difficult to find the messages that describe
* actual causes of the failure.
*
*
*
* The forAll
and forEvery
methods are similar in that both succeed only if the assertion holds for all elements of the collection.
* They differ in that forAll
will only report the first element encountered that failed the assertion, but forEvery
will report all
* elements that fail the assertion. The tradeoff is that while forEvery
gives more information, it may take longer to run because it must inspect every element
* of the collection. The forAll
method can simply stop inspecting once it encounters the first failing element. Here's an example that
* shows the difference in the forAll
and forEvery
error messages:
*
*
*
* scala> forAll (xs) { x => x should be < 3 }
* org.scalatest.exceptions.TestFailedException: forAll failed, because:
* at index 2, 3 was not less than 3 (<console>:18)
* in List(1, 2, 3, 4, 5)
* at org.scalatest.InspectorsHelper$.doForAll(Inspectors.scala:146)
* ...
*
* scala> forEvery (xs) { x => x should be < 3 }
* org.scalatest.exceptions.TestFailedException: forEvery failed, because:
* at index 2, 3 was not less than 3 (<console>:18),
* at index 3, 4 was not less than 3 (<console>:18),
* at index 4, 5 was not less than 3 (<console>:18)
* in List(1, 2, 3, 4, 5)
* at org.scalatest.InspectorsHelper$.doForEvery(Inspectors.scala:226)
* ...
*
*
*
* Note that if you're using matchers, you can alternatively use inspector shorthands for writing non-nested
* inspections. Here's an example:
*
*
*
* scala> all (xs) should be > 3
* org.scalatest.exceptions.TestFailedException: 'all' inspection failed, because:
* at index 0, 1 was not greater than 3
* in List(1, 2, 3, 4, 5)
* at org.scalatest.InspectorsHelper$.doForAll(Inspectors.scala:146)
*
*
*
* You can use Inspectors
on any scala.collection.GenTraversable
, java.util.Collection
,
* java.util.Map
(with Entry
), Array
, or String
.
* Here are some examples:
*
*
*
* scala> import org.scalatest._
* import org.scalatest._
*
* scala> import Inspectors._
* import Inspectors._
*
* scala> import Matchers._
* import Matchers._
*
* scala> forAll (Array(1, 2, 3)) { e => e should be < 5 }
*
* scala> import collection.JavaConverters._
* import collection.JavaConverters._
*
* scala> val js = List(1, 2, 3).asJava
* js: java.util.List[Int] = [1, 2, 3]
*
* scala> forAll (js) { j => j should be < 5 }
*
* scala> val jmap = Map("a" -> 1, "b" -> 2).asJava
* jmap: java.util.Map[String,Int] = {a=1, b=2}
*
* scala> forAtLeast(1, jmap) { e => e shouldBe Entry("b", 2) }
*
* scala> forAtLeast(2, "hello, world!") { c => c shouldBe 'o' }
*
*/
/*
Commenting this out entirely now that we're going the Asserting route. Will
leave it checked in commented out until we get Inspectors working with Fact,
which should be a couple days I "expect".
private[scalatest] trait FactInspectors {
import FactInspectorsHelper._
// SKIP-SCALATESTJS-START
val stackDepthAdjustment = 0
// SKIP-SCALATESTJS-END
//SCALATESTJS-ONLY val stackDepthAdjustment = 1
/**
* Ensure that all elements in a given collection pass the given inspection function, where "pass" means returning normally from the function (i.e.,
* without throwing an exception).
*
*
* The difference between forAll
and forEvery
is that
* forAll
will stop on the first failure, while forEvery
will continue to inspect all elements after the
* first failure (and report all failures).
*
*
* @param xs the collection of elements
* @param fun the inspection function
* @param collecting the implicit Collecting
that can transform xs
into a scala.collection.GenTraversable
* @tparam E the type of element in the collection
* @tparam C the type of collection
*
*/
def forAll[E, C[_]](xs: C[E])(fun: E => Expectation)(implicit collecting: Collecting[E, C[E]]): Expectation = {
doForAll(collecting.genTraversableFrom(xs), xs, false, "Inspectors.scala", "forAll", stackDepthAdjustment)(fun)
}
// SKIP-SCALATESTJS-START
/**
* Ensure that all elements in a given java.util.Map
pass the given inspection function, where "pass" means returning normally from the function (i.e.,
* without throwing an exception).
*
*
* The difference between forAll
and forEvery
is that
* forAll
will stop on the first failure, while forEvery
will continue to inspect all java.util.Map
elements after the
* first failure (and report all failures).
*
*
* @param xs the java.util.Map
* @param fun the inspection function
* @param collecting the implicit Collecting
that can transform xs
into a scala.collection.GenTraversable
* @tparam K the type of key in the Java Map
* @tparam V the type of value in the Java Map
* @tparam JMAP subtype of java.util.Map
*
*/
def forAll[K, V, JMAP[k, v] <: java.util.Map[k, v]](xs: JMAP[K, V])(fun: org.scalatest.Entry[K, V] => Expectation)(implicit collecting: Collecting[org.scalatest.Entry[K, V], JMAP[K, V]]): Expectation = {
doForAll(collecting.genTraversableFrom(xs), xs, false, "Inspectors.scala", "forAll", stackDepthAdjustment)(fun)
}
// SKIP-SCALATESTJS-END
/**
* Ensure that all characters in a given String
pass the given inspection function, where "pass" means returning normally from the function (i.e.,
* without throwing an exception).
*
*
* The difference between forAll
and forEvery
is that
* forAll
will stop on the first failure, while forEvery
will continue to inspect all characters in the String
after the
* first failure (and report all failures).
*
*
* @param xs the String
* @param fun the inspection function
* @param collecting the implicit Collecting
that can transform xs
into a scala.collection.GenTraversable
*
*/
def forAll(xs: String)(fun: Char => Expectation)(implicit collecting: Collecting[Char, String]): Expectation = {
doForAll(collecting.genTraversableFrom(xs), xs, false, "Inspectors.scala", "forAll", stackDepthAdjustment)(fun)
}
/**
* Ensure that at least min
number of elements of a given collection pass the given inspection function.
*
* @param min the minimum number of elements that must pass the inspection function
* @param xs the collection of elements
* @param fun the inspection function
* @param collecting the implicit Collecting
that can transform xs
into a scala.collection.GenTraversable
* @tparam E the type of element in the collection
* @tparam C the type of collection
*
*/
def forAtLeast[E, C[_]](min: Int, xs: C[E])(fun: E => Expectation)(implicit collecting: Collecting[E, C[E]]): Expectation = {
doForAtLeast(min, collecting.genTraversableFrom(xs), xs, false, "Inspectors.scala", "forAtLeast", stackDepthAdjustment)(fun)
}
// SKIP-SCALATESTJS-START
/**
* Ensure that at least min
number of elements in a given java.util.Map
pass the given inspection function.
*
* @param min the minimum number of elements that must pass the inspection function
* @param xs the java.util.Map
* @param fun the inspection function
* @param collecting the implicit Collecting
that can transform xs
into a scala.collection.GenTraversable
* @tparam K the type of key in the java.util.Map
* @tparam V the type of value in the java.util.Map
* @tparam JMAP subtype of java.util.Map
*
*/
def forAtLeast[K, V, JMAP[k, v] <: java.util.Map[k, v]](min: Int, xs: JMAP[K, V])(fun: org.scalatest.Entry[K, V] => Expectation)(implicit collecting: Collecting[org.scalatest.Entry[K, V],JMAP[K, V]]): Expectation = {
doForAtLeast(min, collecting.genTraversableFrom(xs), xs, false, "Inspectors.scala", "forAtLeast", stackDepthAdjustment)(fun)
}
// SKIP-SCALATESTJS-END
/**
* Ensure that at least min
number of characters in a given String
pass the given inspection function.
*
* @param min the minimum number of characters in String
that must pass the inspection function
* @param xs the String
* @param fun the inspection function
* @param collecting the implicit Collecting
that can transform xs
into a scala.collection.GenTraversable
*
*/
def forAtLeast(min: Int, xs: String)(fun: Char => Expectation)(implicit collecting: Collecting[Char, String]): Expectation = {
doForAtLeast(min, collecting.genTraversableFrom(xs), xs, false, "Inspectors.scala", "forAtLeast", stackDepthAdjustment)(fun)
}
private def shouldIncludeIndex[T, R](xs: GenTraversable[T]) = xs.isInstanceOf[GenSeq[T]]
/**
* Ensure that at most max
number of elements of a given collection pass the given inspection function.
*
* @param max the maximum number of elements that must pass the inspection function
* @param xs the collection of elements
* @param fun the inspection function
* @param collecting the implicit Collecting
that can transform xs
into a scala.collection.GenTraversable
* @tparam E the type of element in the collection
* @tparam C the type of collection
*/
def forAtMost[E, C[_]](max: Int, xs: C[E])(fun: E => Expectation)(implicit collecting: Collecting[E, C[E]]): Expectation = {
doForAtMost(max, collecting.genTraversableFrom(xs), xs, false, "Inspectors.scala", "forAtMost", stackDepthAdjustment)(fun)
}
// SKIP-SCALATESTJS-START
/**
* Ensure that at most max
number of elements in a given java.util.Map
pass the given inspection function.
*
* @param max the maximum number of elements in the java.util.Map
that must pass the inspection function
* @param xs the java.util.Map
* @param fun the inspection function
* @param collecting the implicit Collecting
that can transform xs
into a scala.collection.GenTraversable
* @tparam K the type of key in the java.util.Map
* @tparam V the type of value in the java.util.Map
* @tparam JMAP subtype of java.util.Map
*/
def forAtMost[K, V, JMAP[k, v] <: java.util.Map[k, v]](max: Int, xs: JMAP[K, V])(fun: org.scalatest.Entry[K, V] => Expectation)(implicit collecting: Collecting[org.scalatest.Entry[K, V], JMAP[K, V]]): Expectation = {
doForAtMost(max, collecting.genTraversableFrom(xs), xs, false, "Inspectors.scala", "forAtMost", stackDepthAdjustment)(fun)
}
// SKIP-SCALATESTJS-END
/**
* Ensure that at most max
number of characters in a given String
pass the given inspection function.
*
* @param max the maximum number of characters in String
that must pass the inspection function
* @param xs the String
* @param fun the inspection function
* @param collecting the implicit Collecting
that can transform xs
into a scala.collection.GenTraversable
*/
def forAtMost(max: Int, xs: String)(fun: Char => Expectation)(implicit collecting: Collecting[Char, String]): Expectation = {
doForAtMost(max, collecting.genTraversableFrom(xs), xs, false, "Inspectors.scala", "forAtMost", stackDepthAdjustment)(fun)
}
/**
* Ensure that exactly succeededCount
number of elements of a given collection pass the given inspection function.
*
* @param succeededCount the number of elements that must pass the inspection function
* @param xs the collection of elements
* @param fun the inspection function
* @param collecting the implicit Collecting
that can transform xs
into a scala.collection.GenTraversable
* @tparam E the type of element in the collection
* @tparam C the type of collection
*/
def forExactly[E, C[_]](succeededCount: Int, xs: C[E])(fun: E => Expectation)(implicit collecting: Collecting[E, C[E]]): Expectation = {
doForExactly(succeededCount, collecting.genTraversableFrom(xs), xs, false, "Inspectors.scala", "forExactly", stackDepthAdjustment)(fun)
}
// SKIP-SCALATESTJS-START
/**
* Ensure that exactly succeededCount
number of elements in a given java.util.Map
pass the given inspection function.
*
* @param succeededCount the number of elements in the java.util.Map
that must pass the inspection function
* @param xs the java.util.Map
* @param fun the inspection function
* @param collecting the implicit Collecting
that can transform xs
into a scala.collection.GenTraversable
* @tparam K the type of key in the java.util.Map
* @tparam V the type of value in the java.util.Map
* @tparam JMAP subtype of java.util.Map
*/
def forExactly[K, V, JMAP[k, v] <: java.util.Map[k, v]](succeededCount: Int, xs: JMAP[K, V])(fun: org.scalatest.Entry[K, V] => Expectation)(implicit collecting: Collecting[org.scalatest.Entry[K, V], JMAP[K, V]]): Expectation = {
doForExactly(succeededCount, collecting.genTraversableFrom(xs), xs, false, "Inspectors.scala", "forExactly", stackDepthAdjustment)(fun)
}
// SKIP-SCALATESTJS-END
/**
* Ensure that exactly succeededCount
number of characters in a given String
pass the given inspection function.
*
* @param succeededCount the number of characters in the String
that must pass the inspection function
* @param xs the String
* @param fun the inspection function
* @param collecting the implicit Collecting
that can transform xs
into a scala.collection.GenTraversable
*/
def forExactly(succeededCount: Int, xs: String)(fun: Char => Expectation)(implicit collecting: Collecting[Char, String]): Expectation = {
doForExactly(succeededCount, collecting.genTraversableFrom(xs), xs, false, "Inspectors.scala", "forExactly", stackDepthAdjustment)(fun)
}
private[scalatest] def forNo[E, C[_]](xs: C[E])(fun: E => Expectation)(implicit collecting: Collecting[E, C[E]]): Expectation = {
doForNo(collecting.genTraversableFrom(xs), xs, false, "Inspectors.scala", "forNo", stackDepthAdjustment)(fun)
}
// SKIP-SCALATESTJS-START
private[scalatest] def forNo[K, V, JMAP[k, v] <: java.util.Map[k, v]](xs: JMAP[K, V])(fun: org.scalatest.Entry[K, V] => Expectation)(implicit collecting: Collecting[org.scalatest.Entry[K, V], JMAP[K, V]]): Expectation = {
doForNo(collecting.genTraversableFrom(xs), xs, false, "Inspectors.scala", "forNo", stackDepthAdjustment)(fun)
}
// SKIP-SCALATESTJS-END
private[scalatest] def forNo(xs: String)(fun: Char => Expectation)(implicit collecting: Collecting[Char, String]): Expectation = {
doForNo(collecting.genTraversableFrom(xs), xs, false, "Inspectors.scala", "forNo", stackDepthAdjustment)(fun)
}
/**
* Ensure the number of elements of a given collection that pass the given inspection function is between from
and upTo
.
*
* @param from the minimum number of elements that must pass the inspection number
* @param upTo the maximum number of elements that must pass the inspection number
* @param xs the collection of elements
* @param fun the inspection function
* @param collecting the implicit Collecting
that can transform xs
into a scala.collection.GenTraversable
* @tparam E the type of element in the collection
* @tparam C the type of collection
*/
def forBetween[E, C[_]](from: Int, upTo: Int, xs: C[E])(fun: E => Expectation)(implicit collecting: Collecting[E, C[E]]): Expectation = {
doForBetween(from, upTo, collecting.genTraversableFrom(xs), xs, false, "Inspectors.scala", "forBetween", stackDepthAdjustment)(fun)
}
// SKIP-SCALATESTJS-START
/**
* Ensure the number of elements in a given java.util.Map
that pass the given inspection function is between from
and upTo
.
*
* @param from the minimum number of elements in the java.util.Map
that must pass the inspection number
* @param upTo the maximum number of elements in the java.util.Map
that must pass the inspection number
* @param xs the java.util.Map
* @param fun the inspection function
* @param collecting the implicit Collecting
that can transform xs
into a scala.collection.GenTraversable
* @tparam K the type of key in the java.util.Map
* @tparam V the type of value in the java.util.Map
* @tparam JMAP subtype of java.util.Map
*/
def forBetween[K, V, JMAP[k, v] <: java.util.Map[k, v]](from: Int, upTo: Int, xs: JMAP[K, V])(fun: org.scalatest.Entry[K, V] => Expectation)(implicit collecting: Collecting[org.scalatest.Entry[K, V], JMAP[K, V]]): Expectation = {
doForBetween(from, upTo, collecting.genTraversableFrom(xs), xs, false, "Inspectors.scala", "forBetween", stackDepthAdjustment)(fun)
}
// SKIP-SCALATESTJS-END
/**
* Ensure the number of characters of a given String
that pass the given inspection function is between from
and upTo
.
*
* @param from the minimum number of characters in the String
that must pass the inspection number
* @param upTo the maximum number of characters in the String
that must pass the inspection number
* @param xs the String
* @param fun the inspection function
* @param collecting the implicit Collecting
that can transform xs
into a scala.collection.GenTraversable
*/
def forBetween(from: Int, upTo: Int, xs: String)(fun: Char => Expectation)(implicit collecting: Collecting[Char, String]): Expectation = {
doForBetween(from, upTo, collecting.genTraversableFrom(xs), xs, false, "Inspectors.scala", "forBetween", stackDepthAdjustment)(fun)
}
/**
* Ensure that every element in a given collection passes the given inspection function, where "pass" means returning normally from the function (i.e.,
* without throwing an exception).
*
*
* The difference between forEvery
and forAll
is that
* forEvery
will continue to inspect all elements after first failure, and report all failures,
* whereas forAll
will stop on (and only report) the first failure.
*
*
* @param xs the collection of elements
* @param fun the inspection function
* @param collecting the implicit Collecting
that can transform xs
into a scala.collection.GenTraversable
* @tparam E the type of element in the collection
* @tparam C the type of collection
*/
def forEvery[E, C[_]](xs: C[E])(fun: E => Expectation)(implicit collecting: Collecting[E, C[E]]): Expectation = {
doForEvery(collecting.genTraversableFrom(xs), xs, false, "Inspectors.scala", "forEvery", stackDepthAdjustment)(fun)
}
// SKIP-SCALATESTJS-START
/**
* Ensure that every element in a given java.util.Map
passes the given inspection function, where "pass" means returning normally
* from the function (i.e., without throwing an exception).
*
*
* The difference between forEvery
and forAll
is that
* forEvery
will continue to inspect all elements in the java.util.Map
after first failure, and report all failures,
* whereas forAll
will stop on (and only report) the first failure.
*
*
* @param xs the java.util.Map
* @param fun the inspection function
* @param collecting the implicit Collecting
that can transform xs
into a scala.collection.GenTraversable
* @tparam K the type of key in the java.util.Map
* @tparam V the type of value in the java.util.Map
* @tparam JMAP subtype of java.util.Map
*/
def forEvery[K, V, JMAP[k, v] <: java.util.Map[k, v]](xs: JMAP[K, V])(fun: org.scalatest.Entry[K, V] => Expectation)(implicit collecting: Collecting[org.scalatest.Entry[K, V], JMAP[K, V]]): Expectation = {
doForEvery(collecting.genTraversableFrom(xs), xs, false, "Inspectors.scala", "forEvery", stackDepthAdjustment)(fun)
}
// SKIP-SCALATESTJS-END
/**
* Ensure that every character in a given String
passes the given inspection function, where "pass" means returning normally from the function (i.e.,
* without throwing an exception).
*
*
* The difference between forEvery
and forAll
is that
* forEvery
will continue to inspect all characters in the String
after first failure, and report all failures,
* whereas forAll
will stop on (and only report) the first failure.
*
*
* @param xs the String
* @param fun the inspection function
* @param collecting the implicit Collecting
that can transform xs
into a scala.collection.GenTraversable
*/
def forEvery(xs: String)(fun: Char => Expectation)(implicit collecting: Collecting[Char, String]): Expectation = {
doForEvery(collecting.genTraversableFrom(xs), xs, false, "Inspectors.scala", "forEvery", stackDepthAdjustment)(fun)
}
}
/**
* Companion object that facilitates the importing of Inspectors
members as
* an alternative to mixing it in. One use case is to import Inspectors
's members so you can use
* them in the Scala interpreter.
*/
private[scalatest] object FactInspectors extends FactInspectors
private[scalatest] object FactInspectorsHelper {
def indentErrorMessages(messages: IndexedSeq[String]) = indentLines(1, messages)
def isMap(xs: Any): Boolean =
xs match {
case _: collection.GenMap[_, _] => true
// SKIP-SCALATESTJS-START
case _: java.util.Map[_, _] => true
// SKIP-SCALATESTJS-END
case _ => false
}
def shouldPropagate(throwable: Throwable): Boolean =
throwable match {
case _: exceptions.TestPendingException |
_: exceptions.TestCanceledException => true
case _ if Suite.anExceptionThatShouldCauseAnAbort(throwable) => true
case _ => false
}
def createMessage(messageKey: String, t: Throwable, xsIsMap: Boolean): String =
t match {
case sde: exceptions.StackDepthException =>
sde.failedCodeFileNameAndLineNumberString match {
case Some(failedCodeFileNameAndLineNumber) =>
if (xsIsMap)
Resources.forAssertionsGenMapMessageWithStackDepth(messageKey, sde.getMessage, failedCodeFileNameAndLineNumber)
else
Resources.forAssertionsGenTraversableMessageWithStackDepth(messageKey, sde.getMessage, failedCodeFileNameAndLineNumber)
case None =>
if (xsIsMap)
Resources.forAssertionsGenMapMessageWithoutStackDepth(messageKey, sde.getMessage)
else
Resources.forAssertionsGenTraversableMessageWithoutStackDepth(messageKey, sde.getMessage)
}
case _ =>
if (xsIsMap)
Resources.forAssertionsGenMapMessageWithoutStackDepth(messageKey, if (t.getMessage != null) t.getMessage else "null")
else
Resources.forAssertionsGenTraversableMessageWithoutStackDepth(messageKey, if (t.getMessage != null) t.getMessage else "null")
}
def elementLabel(count: Int): String =
if (count > 1) Resources.forAssertionsElements(count.toString) else Resources.forAssertionsElement(count.toString)
case class ForResult[T](passedCount: Int = 0, messageAcc: IndexedSeq[String] = IndexedSeq.empty,
passedElements: IndexedSeq[(Int, T)] = IndexedSeq.empty, failedElements: IndexedSeq[(Int, T, Throwable)] = IndexedSeq.empty)
@tailrec
def runFor[T](itr: Iterator[T], xsIsMap: Boolean, index:Int, result: ForResult[T], fun: T => Expectation, stopFun: ForResult[_] => Boolean): ForResult[T] = {
if (itr.hasNext) {
val head = itr.next
val newResult =
try {
val fact = fun(head)
if (fact.isYes) // TODO: Write a test for VacuousYes, and if get it, throw TCE here.
result.copy(passedCount = result.passedCount + 1, passedElements = result.passedElements :+ (index, head))
else {
val messageKey = head match {
case tuple: Tuple2[_, _] if xsIsMap => tuple._1.toString
case entry: Entry[_, _] if xsIsMap => entry.getKey.toString
case _ => index.toString
}
result.copy(messageAcc = result.messageAcc :+ fact.factMessage, failedElements = result.failedElements :+ (index, head, new Exception("place holder")))
}
}
catch {
case e if !shouldPropagate(e) =>
val messageKey = head match {
case tuple: Tuple2[_, _] if xsIsMap => tuple._1.toString
case entry: Entry[_, _] if xsIsMap => entry.getKey.toString
case _ => index.toString
}
result.copy(messageAcc = result.messageAcc :+ createMessage(messageKey, e, xsIsMap), failedElements = result.failedElements :+ (index, head, e))
}
if (stopFun(newResult))
newResult
else
runFor(itr, xsIsMap, index + 1, newResult, fun, stopFun)
}
else
result
}
def keyOrIndexLabel(xs: Any, passedElements: IndexedSeq[(Int, _)]): String = {
def makeAndLabel(indexes: IndexedSeq[Int]): String =
if (indexes.length > 1)
indexes.dropRight(1).mkString(", ") + " and " + indexes.last
else
indexes.mkString(", ")
val (xsIsMap, elements) = xs match {
// SKIP-SCALATESTJS-START
case _: collection.GenMap[_, _] | _: java.util.Map[_, _] =>
// SKIP-SCALATESTJS-END
//SCALATESTJS-ONLY case _: collection.GenMap[_, _] =>
val elements = passedElements.map{ case (index, e) =>
e match {
case tuple2: Tuple2[_, _] => tuple2._1
// SKIP-SCALATESTJS-START
case entry: java.util.Map.Entry[_, _] => entry.getKey
// SKIP-SCALATESTJS-END
case _ => index
}
}
(true, elements)
case _ =>
(false, passedElements.map(_._1))
}
if (elements.length > 1)
if (xsIsMap)
Resources.forAssertionsKeyAndLabel(elements.dropRight(1).mkString(", "), elements.last.toString)
else
Resources.forAssertionsIndexAndLabel(elements.dropRight(1).mkString(", "), elements.last.toString)
else
if (xsIsMap)
Resources.forAssertionsKeyLabel(elements.mkString(", "))
else
Resources.forAssertionsIndexLabel(elements.mkString(", "))
}
def doForAll[E](xs: GenTraversable[E], original: Any, shorthand: Boolean, sourceFileName: String, methodName: String, stackDepthAdjustment: Int)(fun: E => Expectation): Expectation = {
val xsIsMap = isMap(original)
val result =
runFor(xs.toIterator, xsIsMap, 0, new ForResult[E], fun, _.failedElements.length > 0)
if (result.failedElements.length > 0)
throw new exceptions.TestFailedException(
sde =>
Some(
if (shorthand)
Resources.allShorthandFailed(indentErrorMessages(result.messageAcc).mkString(", \n"), decorateToStringValue(original))
else
Resources.forAllFailed(indentErrorMessages(result.messageAcc).mkString(", \n"), decorateToStringValue(original))
),
Some(result.failedElements(0)._3),
getStackDepthFun(sourceFileName, methodName, stackDepthAdjustment)
)
else Yes("forAll inspection succeeded")
}
def doForAtLeast[T](min: Int, xs: GenTraversable[T], original: Any, shorthand: Boolean, sourceFileName: String, methodName: String, stackDepthAdjustment: Int)(fun: T => Expectation): Expectation = {
@tailrec
def forAtLeastAcc(itr: Iterator[T], includeIndex: Boolean, index: Int, passedCount: Int, messageAcc: IndexedSeq[String]): (Int, IndexedSeq[String]) = {
if (itr.hasNext) {
val head = itr.next
val (newPassedCount, newMessageAcc) =
try {
fun(head)
(passedCount + 1, messageAcc)
}
catch {
case e if !shouldPropagate(e) =>
val xsIsMap = isMap(original)
val messageKey = head match {
case tuple: Tuple2[_, _] if xsIsMap => tuple._1.toString
case entry: Entry[_, _] if xsIsMap => entry.getKey.toString
case _ => index.toString
}
(passedCount, messageAcc :+ createMessage(messageKey, e, xsIsMap))
}
if (newPassedCount < min)
forAtLeastAcc(itr, includeIndex, index + 1, newPassedCount, newMessageAcc)
else
(newPassedCount, newMessageAcc)
}
else
(passedCount, messageAcc)
}
if (min <= 0)
throw new IllegalArgumentException(Resources.forAssertionsMoreThanZero("'min'"))
val (passedCount, messageAcc) = forAtLeastAcc(xs.toIterator, xs.isInstanceOf[Seq[T]], 0, 0, IndexedSeq.empty)
if (passedCount < min)
throw new exceptions.TestFailedException(
sde =>
Some(
if (shorthand)
if (passedCount > 0)
Resources.atLeastShorthandFailed(min.toString, elementLabel(passedCount), indentErrorMessages(messageAcc).mkString(", \n"), decorateToStringValue(original))
else
Resources.atLeastShorthandFailedNoElement(min.toString, indentErrorMessages(messageAcc).mkString(", \n"), decorateToStringValue(original))
else
if (passedCount > 0)
Resources.forAtLeastFailed(min.toString, elementLabel(passedCount), indentErrorMessages(messageAcc).mkString(", \n"), decorateToStringValue(original))
else
Resources.forAtLeastFailedNoElement(min.toString, indentErrorMessages(messageAcc).mkString(", \n"), decorateToStringValue(original))
),
None,
getStackDepthFun(sourceFileName, methodName, stackDepthAdjustment)
)
else Yes("forAtLeast inspection succeeded")
}
def doForEvery[T](xs: GenTraversable[T], original: Any, shorthand: Boolean, sourceFileName: String, methodName: String, stackDepthAdjustment: Int)(fun: T => Expectation): Expectation = {
@tailrec
def runAndCollectErrorMessage[T](itr: Iterator[T], messageList: IndexedSeq[String], index: Int)(fun: T => Expectation): IndexedSeq[String] = {
if (itr.hasNext) {
val head = itr.next
val newMessageList =
try {
fun(head)
messageList
}
catch {
case e if !shouldPropagate(e) =>
val xsIsMap = isMap(original)
val messageKey = head match {
case tuple: Tuple2[_, _] if xsIsMap => tuple._1.toString
case entry: Entry[_, _] if xsIsMap => entry.getKey.toString
case _ => index.toString
}
messageList :+ createMessage(messageKey, e, xsIsMap)
}
runAndCollectErrorMessage(itr, newMessageList, index + 1)(fun)
}
else
messageList
}
val messageList = runAndCollectErrorMessage(xs.toIterator, IndexedSeq.empty, 0)(fun)
if (messageList.size > 0)
throw new exceptions.TestFailedException(
sde =>
Some(
if (shorthand)
Resources.everyShorthandFailed(indentErrorMessages(messageList).mkString(", \n"), decorateToStringValue(original))
else
Resources.forEveryFailed(indentErrorMessages(messageList).mkString(", \n"), decorateToStringValue(original))
),
None,
getStackDepthFun(sourceFileName, methodName, stackDepthAdjustment)
)
else Yes("forEvery inspection succeeded")
}
def doForExactly[T](succeededCount: Int, xs: GenTraversable[T], original: Any, shorthand: Boolean, sourceFileName: String, methodName: String, stackDepthAdjustment: Int)(fun: T => Expectation): Expectation = {
if (succeededCount <= 0)
throw new IllegalArgumentException(Resources.forAssertionsMoreThanZero("'succeededCount'"))
val xsIsMap = isMap(original)
val result =
runFor(xs.toIterator, xsIsMap, 0, new ForResult[T], fun, _.passedCount > succeededCount)
if (result.passedCount != succeededCount)
throw new exceptions.TestFailedException(
sde =>
Some(
if (shorthand)
if (result.passedCount == 0)
Resources.exactlyShorthandFailedNoElement(succeededCount.toString, indentErrorMessages(result.messageAcc).mkString(", \n"), decorateToStringValue(original))
else {
if (result.passedCount < succeededCount)
Resources.exactlyShorthandFailedLess(succeededCount.toString, elementLabel(result.passedCount), keyOrIndexLabel(original, result.passedElements), indentErrorMessages(result.messageAcc).mkString(", \n"), decorateToStringValue(original))
else
Resources.exactlyShorthandFailedMore(succeededCount.toString, elementLabel(result.passedCount), keyOrIndexLabel(original, result.passedElements), decorateToStringValue(original))
}
else
if (result.passedCount == 0)
Resources.forExactlyFailedNoElement(succeededCount.toString, indentErrorMessages(result.messageAcc).mkString(", \n"), decorateToStringValue(original))
else {
if (result.passedCount < succeededCount)
Resources.forExactlyFailedLess(succeededCount.toString, elementLabel(result.passedCount), keyOrIndexLabel(original, result.passedElements), indentErrorMessages(result.messageAcc).mkString(", \n"), decorateToStringValue(original))
else
Resources.forExactlyFailedMore(succeededCount.toString, elementLabel(result.passedCount), keyOrIndexLabel(original, result.passedElements), decorateToStringValue(original))
}
),
None,
getStackDepthFun(sourceFileName, methodName, stackDepthAdjustment)
)
else Yes("forExactly inspection succeeded")
}
def doForNo[T](xs: GenTraversable[T], original: Any, shorthand: Boolean, sourceFileName: String, methodName: String, stackDepthAdjustment: Int)(fun: T => Expectation): Expectation = {
val xsIsMap = isMap(original)
val result =
runFor(xs.toIterator, xsIsMap, 0, new ForResult[T], fun, _.passedCount != 0)
if (result.passedCount != 0)
throw new exceptions.TestFailedException(
sde =>
Some(
if (shorthand)
Resources.noShorthandFailed(keyOrIndexLabel(original, result.passedElements), decorateToStringValue(original))
else
Resources.forNoFailed(keyOrIndexLabel(original, result.passedElements), decorateToStringValue(original))
),
None,
getStackDepthFun(sourceFileName, methodName, stackDepthAdjustment)
)
else Yes("forNo inspection succeeded")
}
def doForBetween[T](from: Int, upTo: Int, xs: GenTraversable[T], original: Any, shorthand: Boolean, sourceFileName: String, methodName: String, stackDepthAdjustment: Int)(fun: T => Expectation): Expectation = {
if (from < 0)
throw new IllegalArgumentException(Resources.forAssertionsMoreThanEqualZero("'from'"))
if (upTo <= 0)
throw new IllegalArgumentException(Resources.forAssertionsMoreThanZero("'upTo'"))
if (upTo <= from)
throw new IllegalArgumentException(Resources.forAssertionsMoreThan("'upTo'", "'from'"))
val xsIsMap = isMap(original)
val result =
runFor(xs.toIterator, xsIsMap, 0, new ForResult[T], fun, _.passedCount > upTo)
if (result.passedCount < from || result.passedCount > upTo)
throw new exceptions.TestFailedException(
sde =>
Some(
if (shorthand)
if (result.passedCount == 0)
Resources.betweenShorthandFailedNoElement(from.toString, upTo.toString, indentErrorMessages(result.messageAcc).mkString(", \n"), decorateToStringValue(original))
else {
if (result.passedCount < from)
Resources.betweenShorthandFailedLess(from.toString, upTo.toString, elementLabel(result.passedCount), keyOrIndexLabel(original, result.passedElements), indentErrorMessages(result.messageAcc).mkString(", \n"), decorateToStringValue(original))
else
Resources.betweenShorthandFailedMore(from.toString, upTo.toString, elementLabel(result.passedCount), keyOrIndexLabel(original, result.passedElements), decorateToStringValue(original))
}
else
if (result.passedCount == 0)
Resources.forBetweenFailedNoElement(from.toString, upTo.toString, indentErrorMessages(result.messageAcc).mkString(", \n"), decorateToStringValue(original))
else {
if (result.passedCount < from)
Resources.forBetweenFailedLess(from.toString, upTo.toString, elementLabel(result.passedCount), keyOrIndexLabel(original, result.passedElements), indentErrorMessages(result.messageAcc).mkString(", \n"), decorateToStringValue(original))
else
Resources.forBetweenFailedMore(from.toString, upTo.toString, elementLabel(result.passedCount), keyOrIndexLabel(original, result.passedElements), decorateToStringValue(original))
}
),
None,
getStackDepthFun(sourceFileName, methodName, stackDepthAdjustment)
)
else Yes("forBetween inspection succeeded")
}
def doForAtMost[T](max: Int, xs: GenTraversable[T], original: Any, shorthand: Boolean, sourceFileName: String, methodName: String, stackDepthAdjustment: Int)(fun: T => Expectation): Expectation = {
if (max <= 0)
throw new IllegalArgumentException(Resources.forAssertionsMoreThanZero("'max'"))
val xsIsMap = isMap(original)
val result =
runFor(xs.toIterator, xsIsMap, 0, new ForResult[T], fun, _.passedCount > max)
if (result.passedCount > max)
throw new exceptions.TestFailedException(
sde =>
Some(
if (shorthand)
Resources.atMostShorthandFailed(max.toString, result.passedCount.toString, keyOrIndexLabel(original, result.passedElements), decorateToStringValue(original))
else
Resources.forAtMostFailed(max.toString, result.passedCount.toString, keyOrIndexLabel(original, result.passedElements), decorateToStringValue(original))
),
None,
getStackDepthFun(sourceFileName, methodName, stackDepthAdjustment)
)
else Yes("forAtMost inspection succeeded")
}
}
*/