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

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,NATIVE-START val stackDepthAdjustment = 0 // SKIP-SCALATESTJS,NATIVE-END //SCALATESTJS,NATIVE-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,NATIVE-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,NATIVE-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,NATIVE-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,NATIVE-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,NATIVE-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,NATIVE-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,NATIVE-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,NATIVE-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,NATIVE-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,NATIVE-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,NATIVE-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,NATIVE-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,NATIVE-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,NATIVE-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,NATIVE-START case _: java.util.Map[_, _] => true // SKIP-SCALATESTJS,NATIVE-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,NATIVE-START case _: collection.GenMap[_, _] | _: java.util.Map[_, _] => // SKIP-SCALATESTJS,NATIVE-END //SCALATESTJS,NATIVE-ONLY case _: collection.GenMap[_, _] => val elements = passedElements.map{ case (index, e) => e match { case tuple2: Tuple2[_, _] => tuple2._1 // SKIP-SCALATESTJS,NATIVE-START case entry: java.util.Map.Entry[_, _] => entry.getKey // SKIP-SCALATESTJS,NATIVE-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") } } */




© 2015 - 2024 Weber Informatics LLC | Privacy Policy