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

org.scalatest.EitherValues.scala Maven / Gradle / Ivy

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

import org.scalactic.{Resources => _, _}
import org.scalatest.exceptions.StackDepthException
import org.scalatest.exceptions.TestFailedException

/**
 * Trait that provides an implicit conversion that adds value (when you expect a Right)
 * and left.value (when you expect a Left) 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.value should be > 9
 * either2.left.value should be ("Muchos problemas")
 * 
* *

* Or, using assertions instead of matcher expressions: *

* *
 * assert(either1.value > 9)
 * assert(either2.left.value === "Muchos problemas")
 * 
* *

* Were you to simply invoke left.get on the Either, * if the Either wasn't defined as expected (e.g., it was a Right when you expected a Left), it * would throw a NoSuchElementException: *

* *
 * val either: Either[String, Int] = Right(9)
 *
 * either.left.get should be > "Muchos problemas" // 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] = Right(9)
 *
 * either should be ('left) // throws TestFailedException
 * either.left.get should be > "Muchos problemas"
 * 
* *

* The EitherValues trait allows you to state that more concisely: *

* *
 * val either: Either[String, Int] = Left("Muchas problemas")
 *
 * either.left.value should be > 9 // either.left.value throws TestFailedException
 * 
*/ trait EitherValues extends Serializable { import scala.language.implicitConversions /** * Implicit conversion that adds a value method to LeftProjection. * * @param leftProj the LeftProjection on which to add the value method */ implicit def convertLeftProjectionToValuable[L, R](leftProj: Either.LeftProjection[L, R])(implicit pos: source.Position): LeftValuable[L, R] = new LeftValuable(leftProj, pos) /** * Implicit conversion that adds a value method to RightProjection. * * @param rightProj the RightProjection on which to add the value method */ @deprecated("The .right.value syntax on Either has been deprecated and will be removed in a future version of ScalaTest. Please use .value instead.") implicit def convertRightProjectionToValuable[L, R](rightProj: Either.RightProjection[L, R])(implicit pos: source.Position): RightValuable[L, R] = new RightValuable(rightProj, pos) /** * Implicit conversion that adds a value method to Either. * This method is right biased and is the equivalent of calling either.right.value. * * @param either the Either on which to add the value method */ implicit def convertEitherToValuable[L, R](either: Either[L, R])(implicit pos: source.Position): EitherValuable[L, R] = new EitherValuable(either, pos) /** * 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], pos: source.Position) extends Serializable { /** * 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 => val e = leftProj.e val p = pos throw new TestFailedException((_: StackDepthException) => Some(Resources.eitherLeftValueNotDefined(e)), Some(cause), p) } } } /** * 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], pos: source.Position) extends Serializable { /** * 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 => val e = rightProj.e val p = pos throw new TestFailedException((_: StackDepthException) => Some(Resources.eitherRightValueNotDefined(e)), Some(cause), p) } } } /** * Wrapper class that adds a value method to Either, allowing * you to make statements to inspect the value if a Right, like: * *
 * either.value should be > 9
 * 
* * @param either An Either to convert to EitherValuable, which provides the * value method. */ class EitherValuable[L, R](either: Either[L, R], pos: source.Position) extends Serializable { /** * 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 = { either match { case Right(r) => r case _ => val e = either val p = pos throw new TestFailedException((_: StackDepthException) => Some(Resources.eitherValueNotDefined(e)), None, p) } } } } /** * 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.Matchers._
 * import matchers.Matchers._
 * 
 * scala> import EitherValues._
 * import EitherValues._
 * 
 * scala> val e: Either[String, Int] = Left("Muchas problemas")
 * e: Either[String,Int] = Left(Muchos problemas)
 * 
 * scala> e.left.value should be ("Muchos problemas")
 * 
 * scala> e.value should be < 9
 * org.scalatest.TestFailedException: The Either on which value was invoked was not defined.
 *   at org.scalatest.EitherValues$RightValuable.value(EitherValues.scala:148)
 *   at .<init>(<console>:18)
 *   ...
 * 
*/ object EitherValues extends EitherValues




© 2015 - 2024 Weber Informatics LLC | Privacy Policy