org.scalatest.words.ContainWord.scala Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of scalatest_2.9.1 Show documentation
Show all versions of scalatest_2.9.1 Show documentation
ScalaTest is a free, open-source testing toolkit for Scala and Java
programmers.
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.scalatest.words
import org.scalatest.matchers._
import scala.collection.GenTraversable
import org.scalautils._
import org.scalatest.FailureMessages
import org.scalatest.UnquotedString
import org.scalautils.Equality
import org.scalatest.enablers.Containing
import org.scalatest.enablers.Aggregating
/**
* This class is part of the ScalaTest matchers DSL. Please see the documentation for Matchers for an overview of
* the matchers DSL.
*
* @author Bill Venners
*/
final class ContainWord {
/**
* This method enables the following syntax:
*
*
* Array(1, 2) should (contain (2) and contain (1))
* ^
*
*/
def apply(expectedElement: Any): MatcherFactory1[Any, Containing] =
new MatcherFactory1[Any, Containing] {
def matcher[U <: Any : Containing]: Matcher[U] =
new Matcher[U] {
def apply(left: U): MatchResult = {
val containing = implicitly[Containing[U]]
MatchResult(
containing.contains(left, expectedElement),
FailureMessages("didNotContainExpectedElement", left, expectedElement),
FailureMessages("containedExpectedElement", left, expectedElement)
)
}
}
}
//
// This key method is called when "contain" is used in a logical expression, such as:
// map should { contain key 1 and equal (Map(1 -> "Howdy")) }. It results in a matcher
// that remembers the key value. By making the value type Any, it causes overloaded shoulds
// to work, because for example a Matcher[GenMap[Int, Any]] is a subtype of Matcher[GenMap[Int, String]],
// given Map is covariant in its V (the value type stored in the map) parameter and Matcher is
// contravariant in its lone type parameter. Thus, the type of the Matcher resulting from contain key 1
// is a subtype of the map type that has a known value type parameter because its that of the map
// to the left of should. This means the should method that takes a map will be selected by Scala's
// method overloading rules.
//
/**
* This method enables the following syntax:
*
*
* map should (contain key ("fifty five") or contain key ("twenty two"))
* ^
*
*
* The map's value type parameter cannot be inferred because only a key type is provided in
* an expression like (contain key ("fifty five")). The matcher returned
* by this method matches scala.collection.Maps with the inferred key type and value type Any. Given
* Map is covariant in its value type, and Matcher is contravariant in
* its type parameter, a Matcher[Map[Int, Any]], for example, is a subtype of Matcher[Map[Int, String]].
* This will enable the matcher returned by this method to be used against any Map that has
* the inferred key type.
*/
def key[K](expectedKey: K): Matcher[scala.collection.GenMap[K, Any]] =
new Matcher[scala.collection.GenMap[K, Any]] {
def apply(left: scala.collection.GenMap[K, Any]): MatchResult =
MatchResult(
left.exists(_._1 == expectedKey),
FailureMessages("didNotContainKey", left, expectedKey),
FailureMessages("containedKey", left, expectedKey)
)
}
// Holy smokes I'm starting to scare myself. I fixed the problem of the compiler not being
// able to infer the value type in contain value 1 and ... like expressions, because the
// value type is there, with an existential type. Since I don't know what K is, I decided to
// try just saying that with an existential type, and it compiled and ran. Pretty darned
// amazing compiler. The problem could not be fixed like I fixed the key method above, because
// Maps are nonvariant in their key type parameter, whereas they are covariant in their value
// type parameter, so the same trick wouldn't work. But this existential type trick seems to
// work like a charm.
/**
* This method enables the following syntax:
*
*
* Map("one" -> 1, "two" -> 2) should (not contain value (5) and not contain value (3))
* ^
*
*
* The map's key type parameter cannot be inferred because only a value type is provided in
* an expression like (contain value (5)). The matcher returned
* by this method matches scala.collection.Maps with the inferred value type and the existential key
* type [K] forSome { type K }. Even though Matcher is contravariant in its type parameter, because
* Map is nonvariant in its key type,
* a Matcher[Map[Any, Int]], for example, is not a subtype of Matcher[Map[String, Int]],
* so the key type parameter of the Map returned by this method cannot be Any. By making it
* an existential type, the Scala compiler will not infer it to anything more specific.
* This will enable the matcher returned by this method to be used against any Map that has
* the inferred value type.
*
*/
def value[V](expectedValue: V): Matcher[scala.collection.GenMap[K, V] forSome { type K }] =
new Matcher[scala.collection.GenMap[K, V] forSome { type K }] {
def apply(left: scala.collection.GenMap[K, V] forSome { type K }): MatchResult =
MatchResult(
// left.values.contains(expectedValue), CHANGING FOR 2.8.0 RC1
left.exists(expectedValue == _._2),
FailureMessages("didNotContainValue", left, expectedValue),
FailureMessages("containedValue", left, expectedValue)
)
}
/**
* This method enables the following syntax, where positiveNumber and validNumber are, for example, of type AMatcher:
*
*
* Array(1, 2, 3) should (contain a positiveNumber and contain a validNumber)
* ^
*
*/
def a[T](aMatcher: AMatcher[T]): Matcher[GenTraversable[T]] =
new Matcher[GenTraversable[T]] {
def apply(left: GenTraversable[T]): MatchResult = {
val matched = left.find(aMatcher(_).matches)
MatchResult(
matched.isDefined,
FailureMessages("didNotContainA", left, UnquotedString(aMatcher.nounName)),
FailureMessages("containedA", left, UnquotedString(aMatcher.nounName), UnquotedString(if (matched.isDefined) aMatcher(matched.get).negatedFailureMessage else "-"))
)
}
}
/**
* This method enables the following syntax, where oddNumber and invalidNumber are, for example, of type AnMatcher:
*
*
* Array(1, 2, 3) should (contain an oddNumber and contain an invalidNumber)
* ^
*
*/
def an[T](anMatcher: AnMatcher[T]): Matcher[GenTraversable[T]] =
new Matcher[GenTraversable[T]] {
def apply(left: GenTraversable[T]): MatchResult = {
val matched = left.find(anMatcher(_).matches)
MatchResult(
matched.isDefined,
FailureMessages("didNotContainAn", left, UnquotedString(anMatcher.nounName)),
FailureMessages("containedAn", left, UnquotedString(anMatcher.nounName), UnquotedString(if (matched.isDefined) anMatcher(matched.get).negatedFailureMessage else "-"))
)
}
}
def oneOf(right: Any*): MatcherFactory1[Any, Containing] = {
new MatcherFactory1[Any, Containing] {
def matcher[T](implicit containing: Containing[T]): Matcher[T] = {
new Matcher[T] {
def apply(left: T): MatchResult = {
MatchResult(
containing.containsOneOf(left, right),
FailureMessages("didNotContainOneOfElements", left, UnquotedString(right.map(FailureMessages.decorateToStringValue).mkString(", "))),
FailureMessages("containedOneOfElements", left, UnquotedString(right.map(FailureMessages.decorateToStringValue).mkString(", ")))
)
}
}
}
}
}
def atLeastOneOf(right: Any*): MatcherFactory1[Any, Aggregating] = {
new MatcherFactory1[Any, Aggregating] {
def matcher[T](implicit aggregating: Aggregating[T]): Matcher[T] = {
new Matcher[T] {
def apply(left: T): MatchResult = {
MatchResult(
aggregating.containsAtLeastOneOf(left, right),
FailureMessages("didNotContainAtLeastOneOf", left, UnquotedString(right.map(FailureMessages.decorateToStringValue).mkString(", "))),
FailureMessages("containedAtLeastOneOf", left, UnquotedString(right.map(FailureMessages.decorateToStringValue).mkString(", ")))
)
}
}
}
}
}
def noneOf(right: Any*): MatcherFactory1[Any, Containing] = {
new MatcherFactory1[Any, Containing] {
def matcher[T](implicit containing: Containing[T]): Matcher[T] = {
new Matcher[T] {
def apply(left: T): MatchResult = {
MatchResult(
containing.containsNoneOf(left, right),
FailureMessages("containedOneOfElements", left, UnquotedString(right.map(FailureMessages.decorateToStringValue).mkString(", "))),
FailureMessages("didNotContainOneOfElements", left, UnquotedString(right.map(FailureMessages.decorateToStringValue).mkString(", ")))
)
}
}
}
}
}
def theSameElementsAs(right: GenTraversable[Any]): MatcherFactory1[Any, Aggregating] = {
new MatcherFactory1[Any, Aggregating] {
def matcher[T](implicit aggregating: Aggregating[T]): Matcher[T] = {
new Matcher[T] {
def apply(left: T): MatchResult = {
MatchResult(
aggregating.containsTheSameElementsAs(left, right),
FailureMessages("didNotContainSameElements", left, right),
FailureMessages("containedSameElements", left, right)
)
}
}
}
}
}
def theSameElementsInOrderAs(right: GenTraversable[Any]): MatcherFactory1[Any, Aggregating] = {
new MatcherFactory1[Any, Aggregating] {
def matcher[T](implicit aggregating: Aggregating[T]): Matcher[T] = {
new Matcher[T] {
def apply(left: T): MatchResult = {
MatchResult(
aggregating.containsTheSameElementsInOrderAs(left, right),
FailureMessages("didNotContainSameElementsInOrder", left, right),
FailureMessages("containedSameElementsInOrder", left, right)
)
}
}
}
}
}
def only(right: Any*): MatcherFactory1[Any, Aggregating] = {
new MatcherFactory1[Any, Aggregating] {
def matcher[T](implicit aggregating: Aggregating[T]): Matcher[T] = {
new Matcher[T] {
def apply(left: T): MatchResult = {
MatchResult(
aggregating.containsOnly(left, right),
FailureMessages("didNotContainOnlyElements", left, UnquotedString(right.map(FailureMessages.decorateToStringValue).mkString(", "))),
FailureMessages("containedOnlyElements", left, UnquotedString(right.map(FailureMessages.decorateToStringValue).mkString(", ")))
)
}
}
}
}
}
def inOrderOnly(right: Any*): MatcherFactory1[Any, Aggregating] = {
new MatcherFactory1[Any, Aggregating] {
def matcher[T](implicit aggregating: Aggregating[T]): Matcher[T] = {
new Matcher[T] {
def apply(left: T): MatchResult = {
MatchResult(
aggregating.containsInOrderOnly(left, right),
FailureMessages("didNotContainInOrderOnlyElements", left, UnquotedString(right.map(FailureMessages.decorateToStringValue).mkString(", "))),
FailureMessages("containedInOrderOnlyElements", left, UnquotedString(right.map(FailureMessages.decorateToStringValue).mkString(", ")))
)
}
}
}
}
}
def allOf(right: Any*): MatcherFactory1[Any, Aggregating] = {
new MatcherFactory1[Any, Aggregating] {
def matcher[T](implicit aggregating: Aggregating[T]): Matcher[T] = {
new Matcher[T] {
def apply(left: T): MatchResult = {
MatchResult(
aggregating.containsAllOf(left, right),
FailureMessages("didNotContainAllOfElements", left, UnquotedString(right.map(FailureMessages.decorateToStringValue).mkString(", "))),
FailureMessages("containedAllOfElements", left, UnquotedString(right.map(FailureMessages.decorateToStringValue).mkString(", ")))
)
}
}
}
}
}
def inOrder(right: Any*): MatcherFactory1[Any, Aggregating] = {
new MatcherFactory1[Any, Aggregating] {
def matcher[T](implicit aggregating: Aggregating[T]): Matcher[T] = {
new Matcher[T] {
def apply(left: T): MatchResult = {
MatchResult(
aggregating.containsInOrder(left, right),
FailureMessages("didNotContainAllOfElementsInOrder", left, UnquotedString(right.map(FailureMessages.decorateToStringValue).mkString(", "))),
FailureMessages("containedAllOfElementsInOrder", left, UnquotedString(right.map(FailureMessages.decorateToStringValue).mkString(", ")))
)
}
}
}
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy