org.scalatest.Inside.scala Maven / Gradle / Ivy
Show all versions of scalatest_2.11.0-RC2 Show documentation
/*
* 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
import org.scalatest.exceptions.StackDepthExceptionHelper.getStackDepthFun
import scala.annotation.tailrec
/**
* Trait containing the inside
construct, which allows you to make statements about nested object graphs using pattern matching.
*
*
* For example, given the following case classes:
*
*
* case class Address(street: String, city: String, state: String, zip: String)
* case class Name(first: String, middle: String, last: String)
* case class Record(name: Name, address: Address, age: Int)
*
*
* You could write:
*
*
* inside (rec) { case Record(name, address, age) =>
* inside (name) { case Name(first, middle, last) =>
* first should be ("Sally")
* middle should be ("Ann")
* last should be ("Jones")
* }
* inside (address) { case Address(street, city, state, zip) =>
* street should startWith ("25")
* city should endWith ("Angeles")
* state should equal ("CA")
* zip should be ("12345")
* }
* age should be < 99
* }
*
*
*
* If an assertion fails, the error message will include the toString
of each value passed
* to inside
clauses enclosing the failed assertion. For example, if rec
in
* the previous expression was defined like this:
*
*
*
* val rec = Record(
* Name("Sally", "Anna", "Jones"),
* Address("25 Main St", "Los Angeles", "CA", "12345"),
* 38
* )
*
*
*
* The error message will read:
*
*
*
* "Ann[a]" was not equal to "Ann[]", inside Name(Sally,Anna,Jones),
* inside Record(Name(Sally,Anna,Jones),Address(25 Main St,Los Angeles,CA,12345),38)
*
*
*/
trait Inside {
/**
* Inspects inside the passed value using the passed partial function.
*
*
* The inside
method checks to see whether the partial function passed as the second curried
* parameter is defined at the value passed as the first parameter, and if so, passes that value to the
* partial function.
*
*
*
* If the partial function is not defined at the passed value, inside
will throw a
* TestFailedException
with a detail message describing the problem. Otherwise, if the
* partial function returns normally, inside
will return normally. If the partial function
* completes abruptly with an exception that mixes in ModifiableMessage
(such as
* TestFailedException
), inside
will append the value's toString
of
* to the exception's detail message, and rethrow it. If the exception thrown by the partial function does not mix
* in ModifiableMessage
, inside
completes abruptly with that same exception.
*
*
* @param value the value inside of which to inspect
* @param pf the partial function to use to inspect inside the passed value
* @throws TestFailedException if the passed partial function is not defined at the passed value
*/
def inside[T](value: T)(pf: PartialFunction[T, Unit]) {
def appendInsideMessage(currentMessage: Option[String]) = {
val st = Thread.currentThread.getStackTrace
val levelCount =
st.count { elem =>
elem.getClassName == "org.scalatest.Inside$class" && elem.getMethodName == "inside"
}
val indentation = " " * (levelCount - 1)
currentMessage match {
case Some(msg) => Some(Resources("insidePartialFunctionAppendSomeMsg", msg.trim, indentation, value.toString()))
case None => Some(Resources("insidePartialFunctionAppendNone", indentation, value.toString()))
}
}
if (pf.isDefinedAt(value)) {
try {
pf(value)
}
catch {
case e: org.scalatest.exceptions.ModifiableMessage[_] =>
throw e.modifyMessage(appendInsideMessage)
}
}
else
throw new TestFailedException(sde => Some(Resources("insidePartialFunctionNotDefined", value.toString())), None, getStackDepthFun("Inside.scala", "inside"))
//throw new TestFailedException(Resources("insidePartialFunctionNotDefined", value.toString()), 2)
}
}
/**
* Companion object that facilitates the importing of the inside
construct as
* an alternative to mixing it in. One use case is to import the inside
construct so you can use
* it in the Scala interpreter:
*
*
* $ scala -cp scalatest-1.8.jar
* Welcome to Scala version 2.9.1.final (Java HotSpot(TM) 64-Bit Server VM, Java 1.6.0_29).
* Type in expressions to have them evaluated.
* Type :help for more information.
*
* scala> import org.scalatest._
* import org.scalatest._
*
* scala> import matchers.ShouldMatchers._
* import matchers.ShouldMatchers._
*
* scala> import Inside._
* import Inside._
*
* scala> inside (List(1, 2, 3)) { case List(x, y, z) =>
* | y should equal (2)
* | }
*
* scala> inside (List(1, 2, 3)) { case List(x, y, z) =>
* | x should equal (2)
* | }
* org.scalatest.TestFailedException: 1 did not equal 2, inside List(1, 2, 3)
* at org.scalatest.matchers.Matchers$class.newTestFailedException(Matchers.scala:150)
* at org.scalatest.matchers.ShouldMatchers$.newTestFailedException(ShouldMatchers.scala:2331)
* at org.scalatest.matchers.ShouldMatchers$ShouldMethodHelper$.shouldMatcher(ShouldMatchers.scala:873)
* ...
*
*/
object Inside extends Inside