org.scalautils.Prettifier.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.scalautils
import scala.collection._
import mutable.WrappedArray
import scala.util.Success
/**
* A function that given any object will produce a “pretty” string representation of that object,
* where “pretty” is in the eye of the implementer.
*
*
* Scala's Any
type declares a toString
that will convert any object to a String
* representation. This String
representation is primarily intended for programmers, and is usually sufficient.
* However, sometimes it can be helpful to provide an alternative implementation of toString
for certain types.
* For example, the toString
implementation on String
prints out the value of the String
:
*
*
*
* scala> "1".toString
* res0: String = 1
*
*
*
* If the error message that resulted from comparing Int
1 with String
"1"
* in a ScalaTest assertion used toString
, therefore, the error message would be:
*
*
*
* 1 did not equal 1
*
*
*
* To make it quicker to figure out why the assertion failed, ScalaTest prettifies the objects involved in
* the error message. The default Prettifier
will place double quotes on either side of a String
s
* toString
result:
*
*
*
* scala> import org.scalautils._
* import org.scalautils._
*
* scala> Prettifier.default("1")
* res1: String = "1"
*
*
*
* Thus the error message resulting from comparing Int
1 with String
"1"
,
* in a ScalaTest assertion is:
*
*
*
* 1 did not equal "1"
*
*
*
* If you wish to prettify an object in production code, for example, to issue a profoundly clear debug message, you can use
* PrettyMethods
and invoke pretty
. Here's an example:
*
*
*
* scala> import PrettyMethods._
* import PrettyMethods._
*
* scala> 1.pretty
* res2: String = 1
*
* scala> "1".pretty
* res3: String = "1"
*
*
*
* For example, the default Prettifier
, Prettifier.default
, transforms:
*
*
*
* Null
to: null
* Unit
to: <() the Unit value>
* String
to: "string"
(the toString
result surrounded by double quotes)
* Char
to: 'c'
(the toString
result surrounded by single quotes)
* Array
to: Array("1", "2", "3")
* scala.Some
to: Some("3")
* scala.util.Left
to: Left("3")
* scala.util.Right
to: Right("3")
* scala.util.Success
to: Success("3")
* org.scalautils.Good
to: Good("3")
* org.scalautils.Bad
to: Bad("3")
* org.scalautils.One
to: One("3")
* org.scalautils.Many
to: Many("1", "2", "3")
* scala.collection.GenTraversable
to: List("1", "2", "3")
* java.util.Collection
to: ["1", "2", "3"]
* java.util.Map
to: {1="one", 2="two", 3="three"}
*
*
*
* For anything else, the default Prettifier
returns the result of invoking toString
.
*
*
*
* Note: Prettifier
is not parameterized (i.e., Prettifier[T]
, where T
is the type
* to prettify) because assertions (including matcher expressions) in ScalaTest would then need to look up Prettifier
s implicitly by type. This would slow
* compilation even though most (let's guess 99.9%) of the time in practice assertions do not fail, and thus 99.9% of the time no error messages need to be generated.
* If no error messages are needed 99.9% of the time, no prettification is needed 99.9% of the time, so the slow down in compile time for the implicit
* look ups is unlikely to be worth the benefit. Only a few types in practice usually need prettification for testing error message purposes, and those will be covered
* by the default Prettifier
. A future version of ScalaTest will provide a simple mechanism to replace the default Prettifier
with a
* custom one when a test actually fails.
*
*/
trait Prettifier extends (Any => String)
/**
* Companion object for Prettifier
that provides a default Prettifier
implementation.
*/
object Prettifier {
/**
* A default Prettifier
.
*
*
* This default Prettifier
is used in ScalaTest to clarify error messages.
*
*
*
* It transforms:
*
*
*
* Null
to: null
* Unit
to: <() the Unit value>
* String
to: "string"
(the toString
result surrounded by double quotes)
* Char
to: 'c'
(the toString
result surrounded by single quotes)
* Array
to: Array("1", "2", "3")
* scala.Some
to: Some("3")
* scala.util.Left
to: Left("3")
* scala.util.Right
to: Right("3")
* scala.util.Success
to: Success("3")
* org.scalautils.Good
to: Good("3")
* org.scalautils.Bad
to: Bad("3")
* org.scalautils.One
to: One("3")
* org.scalautils.Many
to: Many("1", "2", "3")
* scala.collection.GenTraversable
to: List("1", "2", "3")
* java.util.Collection
to: ["1", "2", "3"]
* java.util.Map
to: {1="one", 2="two", 3="three"}
*
*
*
*
* For anything else, it returns the result of invoking toString
.
*
*/
val default: Prettifier =
new Prettifier {
def apply(o: Any): String =
o match {
case null => "null"
case aUnit: Unit => "<(), the Unit value>"
case aString: String => "\"" + aString + "\""
case aChar: Char => "\'" + aChar + "\'"
case Some(e) => "Some(" + apply(e) + ")"
case Success(e) => "Success(" + apply(e) + ")"
case Left(e) => "Left(" + apply(e) + ")"
case Right(e) => "Right(" + apply(e) + ")"
case Good(e) => "Good(" + apply(e) + ")"
case Bad(e) => "Bad(" + apply(e) + ")"
case One(e) => "One(" + apply(e) + ")"
case many: Many[_] => "Many(" + many.toIterator.map(apply(_)).mkString(", ") + ")"
case anArray: Array[_] => "Array(" + (anArray map apply).mkString(", ") + ")"
case aWrappedArray: WrappedArray[_] => "Array(" + (aWrappedArray map apply).mkString(", ") + ")"
case aGenMap: GenMap[_, _] =>
val defaultToString = aGenMap.toString
val typeName = defaultToString.takeWhile(_ != '(')
typeName + "(" +
(aGenMap.toIterator.map { case (key, value) => // toIterator is needed for consistent ordering
apply(key) + " -> " + apply(value)
}).mkString(", ") + ")"
case aGenTraversable: GenTraversable[_] =>
val defaultToString = aGenTraversable.toString
val typeName = defaultToString.takeWhile(_ != '(')
typeName + "(" + aGenTraversable.toIterator.map(apply(_)).mkString(", ") + ")" // toIterator is needed for consistent ordering
case javaCol: java.util.Collection[_] =>
// By default java collection follows http://download.java.net/jdk7/archive/b123/docs/api/java/util/AbstractCollection.html#toString()
// let's do our best to prettify its element when it is not overriden
import scala.collection.JavaConverters._
val theToString = javaCol.toString
if (theToString.startsWith("[") && theToString.endsWith("]"))
"[" + javaCol.iterator().asScala.map(apply(_)).mkString(", ") + "]"
else
theToString
case javaMap: java.util.Map[_, _] =>
// By default java map follows http://download.java.net/jdk7/archive/b123/docs/api/java/util/AbstractMap.html#toString()
// let's do our best to prettify its element when it is not overriden
import scala.collection.JavaConverters._
val theToString = javaMap.toString
if (theToString.startsWith("{") && theToString.endsWith("}"))
"{" + javaMap.entrySet.iterator.asScala.map { entry =>
apply(entry.getKey) + "=" + apply(entry.getValue)
}.mkString(", ") + "}"
else
theToString
case anythingElse => anythingElse.toString
}
}
/**
* A basic Prettifier
.
*
*
* This was the default Prettifier
used in ScalaTest 2.0 release.
*
*
*
* It transforms:
*
*
*
* Null
to: null
* Unit
to: <() the Unit value>
* String
to: "string"
(the toString
result surrounded by double quotes)
* Char
to: 'c'
(the toString
result surrounded by single quotes)
* Array
to: Array("1", "2", "3")
* scala.util.Some
to: Some("3")
*
*
*
* For anything else, it returns the result of invoking toString
.
*
*/
val basic = new BasicPrettifier
}
private[scalautils] class BasicPrettifier extends Prettifier {
def apply(o: Any): String =
o match {
case null => "null"
case aUnit: Unit => "<(), the Unit value>"
case aString: String => "\"" + aString + "\""
case aChar: Char => "\'" + aChar + "\'"
case anArray: Array[_] => prettifyArrays(anArray)
case aWrappedArray: WrappedArray[_] => prettifyArrays(aWrappedArray)
case anythingElse => anythingElse.toString
}
private def prettifyArrays(o: Any): String =
o match {
case arr: Array[_] => "Array(" + (arr map (a => prettifyArrays(a))).mkString(", ") + ")"
case wrappedArr: WrappedArray[_] => "Array(" + (wrappedArr map (a => prettifyArrays(a))).mkString(", ") + ")"
case _ => if (o != null) o.toString else "null"
}
}