org.scalatest.EitherValues.scala Maven / Gradle / Ivy
Show all versions of scalatest_2.8.1 Show documentation
/*
* Copyright 2001-2011 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
/**
* Trait that provides an implicit conversion that adds left.value and right.value methods
* to Either, which will return the selected value of the Either if defined,
* or throw TestFailedException if not.
*
*
* This construct allows you to express in one statement that an Either should be left or right
* and that its value should meet some expectation. Here's are some examples:
*
*
*
* either1.right.value should be > 9
* either2.left.value should be ("Muchas problemas")
*
*
*
* Or, using assertions instead of matcher expressions:
*
*
*
* assert(either1.right.value > 9)
* assert(either2.left.value === "Muchas problemas")
*
*
*
* Were you to simply invoke right.get or left.get on the Either,
* if the Either wasn't defined as expected (e.g., it was a Left when you expected a Right), it
* would throw a NoSuchElementException:
*
*
*
* val either: Either[String, Int] = Left("Muchas problemas")
*
* either.right.get should be > 9 // either.right.get throws NoSuchElementException
*
*
*
* The NoSuchElementException would cause the test to fail, but without providing a stack depth pointing
* to the failing line of test code. This stack depth, provided by TestFailedException (and a
* few other ScalaTest exceptions), makes it quicker for
* users to navigate to the cause of the failure. Without EitherValues, to get
* a stack depth exception you would need to make two statements, like this:
*
*
*
* val either: Either[String, Int] = Left("Muchas problemas")
*
* either should be ('right) // throws TestFailedException
* either.right.get should be > 9
*
*
*
* The EitherValues trait allows you to state that more concisely:
*
*
*
* val either: Either[String, Int] = Left("Muchas problemas")
*
* either.right.value should be > 9 // either.right.value throws TestFailedException
*
*/
trait EitherValues {
/**
* Implicit conversion that adds a value method to LeftProjection.
*
* @param either the LeftProjection on which to add the value method
*/
implicit def convertLeftProjectionToValuable[L, R](leftProj: Either.LeftProjection[L, R]) = new LeftValuable(leftProj)
/**
* Implicit conversion that adds a value method to RightProjection.
*
* @param either the RightProjection on which to add the value method
*/
implicit def convertRightProjectionToValuable[L, R](rightProj: Either.RightProjection[L, R]) = new RightValuable(rightProj)
/**
* Wrapper class that adds a value method to LeftProjection, allowing
* you to make statements like:
*
*
* either.left.value should be > 9
*
*
* @param leftProj A LeftProjection to convert to LeftValuable, which provides the
* value method.
*/
class LeftValuable[L, R](leftProj: Either.LeftProjection[L, R]) {
/**
* Returns the Left value contained in the wrapped LeftProjection, if defined as a Left, else throws TestFailedException with
* a detail message indicating the Either was defined as a Right, not a Left.
*/
def value: L = {
try {
leftProj.get
}
catch {
case cause: NoSuchElementException =>
throw new TestFailedException(sde => Some(Resources("eitherLeftValueNotDefined")), Some(cause), getStackDepthFun("EitherValues.scala", "value"))
}
}
}
/**
* Wrapper class that adds a value method to RightProjection, allowing
* you to make statements like:
*
*
* either.right.value should be > 9
*
*
* @param rightProj A RightProjection to convert to RightValuable, which provides the
* value method.
*/
class RightValuable[L, R](rightProj: Either.RightProjection[L, R]) {
/**
* Returns the Right value contained in the wrapped RightProjection, if defined as a Right, else throws TestFailedException with
* a detail message indicating the Either was defined as a Right, not a Left.
*/
def value: R = {
try {
rightProj.get
}
catch {
case cause: NoSuchElementException =>
throw new TestFailedException(sde => Some(Resources("eitherRightValueNotDefined")), Some(cause), getStackDepthFun("EitherValues.scala", "value"))
}
}
}
}
/**
* Companion object that facilitates the importing of ValueEither members as
* an alternative to mixing it in. One use case is to import EitherValues's members so you can use
* left.value and right.value on Either in the Scala interpreter:
*
*
* $ scala -cp scalatest-1.7.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 EitherValues._
* import EitherValues._
*
* scala> val e: Either[String, Int] = Left("Muchas problemas")
* e: Either[String,Int] = Left(Muchas problemas)
*
* scala> e.left.value should be ("Muchas problemas")
*
* scala> e.right.value should be < 9
* org.scalatest.TestFailedException: The Either on which rightValue was invoked was not defined.
* at org.scalatest.EitherValues$RightValuable.value(EitherValues.scala:148)
* at .<init>(<console>:18)
* ...
*
*/
object EitherValues extends EitherValues