org.scalactic
Members list
Packages
Type members
Classlikes
Convenience base trait for string Uniformity
s.
Convenience base trait for string Uniformity
s.
This trait defines a normalizedCanHandle
method that returns true if the passed Any
is a String
and a normalizedOrSame
method that normalizes any passed String
s via the normalized
method, which is left abstract for subclasses to fill in.
Here's an example in which AbstractStringUniformity
is used to normalize strings by ensuring the first character, if any, is capitalized:
val capitalized: Uniformity[String] = new AbstractStringUniformity { def normalized(s: String): String = if (s.isEmpty) "" else s.charAt(0).toUpper + s.substring(1) }
Here's an example of using the capitalized
Uniformity
with a Matcher
expression:
scala> import org.scalatest._ import org.scalatest._ scala> import Matchers._ import Matchers._ scala> import org.scalactic._ import org.scalactic._ scala> val capitalized: Uniformity[String] = | new AbstractStringUniformity { | def normalized(s: String): String = | if (s.isEmpty) "" else s.charAt(0).toUpper + s.substring(1) | } capitalized: org.scalactic.Uniformity[String] = $anon$1@65601e00 scala> "Hello" should equal ("hello") (after being capitalized)
Attributes
- Source
- AbstractStringUniformity.scala
- Supertypes
Provides mechanisms that enable errors to be accumulated in “accumulating Or
s,” Or
s whose Bad
type is an Every
.
Provides mechanisms that enable errors to be accumulated in “accumulating Or
s,” Or
s whose Bad
type is an Every
.
The mechanisms are:
-
Passing accumulating
Or
s towithGood
methods -
Invoking
combined
on a container of accumulatingOr
s -
Invoking
validatedBy
on a container of any type, passing in a function from that type to an accumulatingOr
-
Invoking
zip
on an accumulatingOr
-
Invoking
when
on an accumulatingOr
For more information and examples, see the Accumulating errors with Or
section of the main documentation for class Or
.
Attributes
- Companion
- object
- Source
- Accumulation.scala
- Supertypes
- Known subtypes
-
object Accumulation.type
Companion object to trait Accumulation
that allows Accumulation
's members to be imported rather than mixed in, and also contains nested traits used by implicit conversions declared in trait Accumulations
.
Companion object to trait Accumulation
that allows Accumulation
's members to be imported rather than mixed in, and also contains nested traits used by implicit conversions declared in trait Accumulations
.
For more information and examples, see the Accumulating errors with Or
section of the main documentation for class Or
.
Attributes
- Companion
- trait
- Source
- Accumulation.scala
- Supertypes
- Self type
-
Accumulation.type
Attributes
- Source
- Accumulation.scala
- Supertypes
-
class Objecttrait Matchableclass Any
- Known subtypes
-
trait Accumulationobject Accumulation.type
Contains a “bad” value.
Contains a “bad” value.
You can decide what “bad” means, but it is expected Bad
will be commonly used to hold descriptions of an error (or several, accumulated errors). Some examples of possible error descriptions are String
error messages, Int
error codes, Throwable
exceptions, or instances of a case class hierarchy designed to describe errors.
Value parameters
- b
-
the “bad” value
Attributes
- Source
- Or.scala
- Supertypes
-
trait Serializabletrait Producttrait Equalsclass Objecttrait Matchableclass AnyShow all
A trait that represent a rich-featured boolean value, which includes the following members:
A trait that represent a rich-featured boolean value, which includes the following members:
-
a boolean value
-
methods useful for failure messages construction
-
logical expression methods that makes
Bool
composable
Bool
is used by code generated from BooleanMacro
(which AssertionsMacro
and RequirementsMacro
uses), it needs to be public so that the generated code can be compiled. It is expected that ScalaTest users would ever need to use Bool
directly.
Attributes
- Companion
- object
- Source
- Bool.scala
- Supertypes
-
class Objecttrait Matchableclass Any
Bool
companion object that provides factory methods to create different sub types of Bool
Bool
companion object that provides factory methods to create different sub types of Bool
Bool
is used by code generated from BooleanMacro
(which AssertionsMacro
and RequirementsMacro
uses), it needs to be public so that the generated code can be compiled. It is expected that ScalaTest users would ever need to use Bool
directly.
Attributes
- Companion
- trait
- Source
- Bool.scala
- Supertypes
-
class Objecttrait Matchableclass Any
- Self type
-
Bool.type
Attributes
- Source
- BooleanMacro.scala
- Supertypes
-
class Objecttrait Matchableclass Any
- Self type
-
BooleanMacro.type
Abstract class used to enforce type constraints for equality checks.
Abstract class used to enforce type constraints for equality checks.
For more information on how this class is used, see the documentation of TripleEqualsSupport
.
Attributes
- Source
- CanEqual.scala
- Supertypes
-
class Objecttrait Matchableclass Any
- Known subtypes
-
Convenience class for extractors that match and return Throwable
s based on a type and Boolean
condition.
Convenience class for extractors that match and return Throwable
s based on a type and Boolean
condition.
Class Catcher
was motivated by the need to catch and handle exceptions based on more than just the exception's type as a strategy for dealing with "flickering" tests—tests that usually pass, but occasionally fail. The best strategy for dealing with flickers is to fix the test such that they stop flickering, but sometimes that is not practical. In such cases allowing the test to continue flickering can distract the team by requiring them to spend time inspecting failures to determine whether or not they are flickers or real failures that need attention. Worse, with enough flickers, team members can stop checking all failures and not notice real ones.
One strategy for dealing with flickers you can't practically fix is to catch exceptions that are causing individual flickers and cancel the test when you detect them. Often this means you will need to insert a catch clause in a particular spot, or a pattern match if in a withFixture
, looking for a particular exception with a particular message or other identifying attribute. If the same problem is causing flickers in many places, it is handy to create an extractor to detect the problem. This Catcher
class provides a factory method that takes a partial function from Throwable
to Boolean
and produces such an extractor. Here's an example:
val InternalServerError = Catcher { case e: DBAccessException => e.getMessage == "500:Internal Server Error" }
Using this Catcher
in a ScalaTest withFixture
method would look like:
override def withFixture(test: NoArgTest) = { super.withFixture(test) match { case Failed(InternalServerError(ex)) => Canceled("Canceled because likely a flicker caused by intermittently flaky DB", ex) case other => other } }
Value parameters
- partial
-
the partial function that is used by this extractor to determine matches
Attributes
- Companion
- object
- Source
- Catcher.scala
- Supertypes
-
class Objecttrait Matchableclass Any
Companion object for Catcher
that provides a factory method for creating Throwable
extractors.
Companion object for Catcher
that provides a factory method for creating Throwable
extractors.
Attributes
- Companion
- class
- Source
- Catcher.scala
- Supertypes
-
class Objecttrait Matchableclass Any
- Self type
-
Catcher.type
Attributes
- Source
- DefaultEquality.scala
- Supertypes
-
class Objecttrait Matchableclass Any
- Self type
-
DefaultEquality.type
Defines a custom way to determine equality for a type when compared with another value of type Any
.
Defines a custom way to determine equality for a type when compared with another value of type Any
.
Equality
enables you to define alternate notions of equality for types that can be used with ScalaUtil's ===
and !==
syntax and ScalaTest's matcher syntax.
For example, say you have a case class that includes a Double
value:
scala> case class Person(name: String, age: Double) defined class Person
Imagine you are calculating the age
values in such as way that occasionally tests are failing because of rounding differences that you actually don't care about. For example, you expect an age of 29.0, but you're sometimes seeing 29.0001:
scala> import org.scalactic._ import org.scalactic._ scala> import TripleEquals._ import TripleEquals._ scala> Person("Joe", 29.0001) === Person("Joe", 29.0) res0: Boolean = false
The ===
operator looks for an implicit Equality[L]
, where L
is the left-hand type: in this case, Person
. Because you didn't specifically provide an implicit Equality[Person]
, ===
will fall back on default equality, which will call Person
's equals
method. That equals
method, provided by the Scala compiler because Person
is a case class, will declare these two objects unequal because 29.001 does not exactly equal 29.0.
To make the equality check more forgiving, you could define an implicit Equality[Person]
that compares the age
Double
s with a tolerance, like this:
scala> import Tolerance._ import Tolerance._ scala> implicit val personEq = | new Equality[Person] { | def areEqual(a: Person, b: Any): Boolean = | b match { | case p: Person => a.name == p.name && a.age === p.age +- 0.0002 | case _ => false | } | } personEq: org.scalactic.Equality[Person] = $anon$1@2b29f6e7
Now the ===
operator will use your more forgiving Equality[Person]
for the equality check instead of default equality:
scala> Person("Joe", 29.0001) === Person("Joe", 29.0) res1: Boolean = true
== Default equality ==
Scalactic defines a default Equality[T]
for all types T
whose areEqual
method works by first calling .deep
on any passed array, then calling ==
on the left-hand object, passing in the right-hand object. You can obtain a default equality via the default
method of the Equality companion object, or from the defaultEquality
method defined in TripleEqualsSupport
.
== About equality and equivalence ==
The Equality
trait represents the Java Platform's native notion of equality, as expressed in the signature and contract of the equals
method of java.lang.Object
. Essentially, trait Equality
enables you to write alternate equals
method implementations for a type outside its defining class.
In an equals
method, the left-hand type is known to be the type of this
, but the right-hand type is Any
. As a result, you would normally perform a runtime type test to determine whether the right-hand object is of an appropriate type for equality, and if so, compare it structurally for equality with the left-hand (this
) object. An an illustration, here's a possible equals
implementation for the Person
case class shown in the earlier example:
override def equals(other: Any): Boolean = other match { case p: Person => name = p.name && age = p.age case _ => false }
The areEquals
method of Equality[T]
is similar. The left-hand type is known to be T
, but the right-hand type is Any
, so normally you'd need to do a runtime type test in your areEqual
implementation. Here's the areEqual
method implementation from the earlier Equality[Person]
example:
def areEqual(a: Person, b: Any): Boolean = b match { case p: Person => a.name == p.name && a.age === p.age +- 0.0002 case _ => false }
Equality
is used by TripleEquals
, which enforces no type constraint between the left and right values, and the equal
, be
, and contain
syntax of ScalaTest Matchers.
By contrast, TypeCheckedTripleEquals
and ConversionCheckedTripleEquals
use an Equivalence
. Equivalence
differs from Equality
in that both the left and right values are of the same type. Equivalence
works for TypeCheckedTripleEquals
because the type constraint enforces that the left type is a subtype or supertype of (or the same type as) the right type, and it widens the subtype to the supertype. So ultimately, both left and right sides are of the supertype type. Similarly, Equivalence
works for ConversionCheckedTripleEquals
because the type constraint enforces that an implicit conversion exists from either the left type to the right type, or the right type to the left type, and it always converts one type to the other using the implicit conversion. (If both types are the same type, the identity implicit conversion from Predef
is used.) Because of the conversion, both left and right sides are ultimately of the converted-to type. Here's an example of how writing an Equivalence
's areEquivalent
method might look:
def areEquivalent(a: Person, b: Person): Boolean = a.name == b.name && a.age === b.age +- 0.0002
Scalactic provides both Equality
and Equivalence
because the Any
in Equality
can sometimes make things painful. For example, in trait TolerantNumerics
, a single generic factory method can produce Equivalence
s for any Numeric
type, but because of the Any
, a separate factory method must be defined to produce an Equality
for each Numeric
type.
If you just want to customize the notion of equality for ===
used in Boolean
expressions, you can work with Equivalence
s instead of Equality
s. If you do chose to write the more general Equality
s, they can be used wherever an Equivalence
is required, because Equality
extends Equivalence
, defining a final implementation of areEquivalent
that invokes areEqual
.
Note: The Equality
type class was inspired in part by the Equal
type class of the scalaz
project.
Type parameters
- A
-
the type whose equality is being customized
Attributes
- Companion
- object
- Source
- Equality.scala
- Supertypes
- Known subtypes
-
class DecidedByEquality[A]trait NormalizingEquality[A]
Companion object for trait Equality
that provides factory methods for producing Equality
instances.
Companion object for trait Equality
that provides factory methods for producing Equality
instances.
Attributes
- Companion
- trait
- Source
- Equality.scala
- Supertypes
-
class Objecttrait Matchableclass Any
- Self type
-
Equality.type
Defines a custom way to determine equality for a type when compared with another value of the same type.
Defines a custom way to determine equality for a type when compared with another value of the same type.
Equivalence
enables you to define alternate notions of equality for types that can be used with ScalaUtil's TypeCheckedTripleEquals
and ConversionCheckedTripleEquals
traits. These traits can be used to perform equality comparisons with type constraints enforced at compile time using ScalaUtil's ===
and !==
syntax and ScalaTest's should
===
syntax of Matchers
trait.
Because Equality
extends Equivalence
, you automatically define an Equivalence[T]
when you define an Equality[T]
. Most often you will usually want to define custom Equality
s, because they will be more generally useful: they are also used by Scalactic's TripleEquals
trait and ScalaTest's equal
, be
, and contain
matcher syntax. However, if you really want just an Equivalence
, and writing an Equality
is inconvenient, you can write an Equivalence
directly for a type.
For example, say you have a case class that includes a Double
value:
scala> case class Person(name: String, age: Double) defined class Person
Imagine you are calculating the age
values in such as way that occasionally tests are failing because of rounding differences that you actually don't care about. For example, you expect an age of 29.0, but you're sometimes seeing 29.0001:
scala> import org.scalactic._ import org.scalactic._ scala> import TypeCheckedTripleEquals._ import TypeCheckedTripleEquals._ scala> Person("Joe", 29.0001) === Person("Joe", 29.0) res0: Boolean = false
The ===
operator of TypeCheckedTripleEquals
looks for an implicit Equivalence[SUPER]
, where SUPER
is either the left-hand or right-hand type, whichever one is a supertype of the other. In this case, both sides are Person
(which is considered a supertype of itself), so the compiler will look for an Equivalence[Person]
. Because you didn't specifically provide an implicit Equivalence[Person]
, ===
will fall back on default equality, because an Equality[Person]
is-an Equivalence[Person]
. The default Equality[Person]
will call Person
's equals
method. That equals
method, provided by the Scala compiler because Person
is a case class, will declare these two objects unequal because 29.001 does not exactly equal 29.0.
To make the equality check more forgiving, you could define an implicit Equivalence[Person]
that compares the age
Double
s with a tolerance, like this:
scala> import Tolerance._ import Tolerance._ scala> implicit val personEq = | new Equivalence[Person] { | def areEquivalent(a: Person, b: Person): Boolean = | a.name == b.name && a.age === b.age +- 0.0002 | } personEq: org.scalactic.Equivalence[Person] = $anon$1@7892bd8
Now the ===
operator will use your more forgiving Equivalence[Person]
for the equality check instead of default equality:
scala> Person("Joe", 29.0001) === Person("Joe", 29.0) res1: Boolean = true
Attributes
- Companion
- object
- Source
- Equivalence.scala
- Supertypes
-
class Objecttrait Matchableclass Any
- Known subtypes
-
trait Equality[A]class DecidedByEquality[A]trait NormalizingEquality[A]class DeterminedByEquivalence[T]trait NormalizingEquivalence[A]
Companion object for trait Equivalence
that provides a factory method for producing default Equivalence
instances.
Companion object for trait Equivalence
that provides a factory method for producing default Equivalence
instances.
Attributes
- Companion
- trait
- Source
- Equivalence.scala
- Supertypes
-
class Objecttrait Matchableclass Any
- Self type
-
Equivalence.type
An ordered, immutable, non-empty collection of elements.
An ordered, immutable, non-empty collection of elements.
Class Every
has two and only two subtypes: One
and Many
. A One
contains exactly one element. A Many
contains two or more elements. Thus no way exists for an Every
to contain zero elements.
== Constructing Every
s ==
You can construct an Every
by passing one or more elements to the Every.apply
factory method:
Every(1) Every(1, 2) Every(1, 2, 3)
Alternatively you can pass one element to the One.apply
factory method, or two or more elements to Many.apply
:
One(1) Many(1, 3) Many(1, 2, 3)
== Working with Every
s ==
Every
does not extend Scala's Seq
or Traversable
traits because these require that implementations may be empty. For example, if you invoke tail
on a Seq
that contains just one element, you'll get an empty Seq
:
scala> List(1).tail res6: List[Int] = List()
On the other hand, many useful methods exist on Seq
that when invoked on a non-empty Seq
are guaranteed to not result in an empty Seq
. For convenience, Every
defines a method corresponding to every such Seq
method. Here are some examples:
Many(1, 2, 3).map(_ + 1) // Result: Many(2, 3, 4) One(1).map(_ + 1) // Result: One(2) Every(1, 2, 3).containsSlice(Every(2, 3)) // Result: true Every(1, 2, 3).containsSlice(Every(3, 4)) // Result: false Every(-1, -2, 3, 4, 5).minBy(_.abs) // Result: -1
Every
does not currently define any methods corresponding to Seq
methods that could result in an empty Seq
. However, an implicit converison from Every
to collection.immutable.IndexedSeq
is defined in the Every
companion object that will be applied if you attempt to call one of the missing methods. As a result, you can invoke filter
on an Every
, even though filter
could result in an empty sequence—but the result type will be collection.immutable.IndexedSeq
instead of Every
:
Every(1, 2, 3).filter(_ < 10) // Result: Vector(1, 2, 3) Every(1, 2, 3).filter(_ > 10) // Result: Vector()
You can use Every
s in for
expressions. The result will be an Every
unless you use a filter (an if
clause). Because filters are desugared to invocations of filter
, the result type will switch to a collection.immutable.IndexedSeq
at that point. Here are some examples:
scala> import org.scalactic._ import org.scalactic._ scala> for (i <- Every(1, 2, 3)) yield i + 1 res0: org.scalactic.Every[Int] = Many(2, 3, 4) scala> for (i <- Every(1, 2, 3) if i < 10) yield i + 1 res1: scala.collection.immutable.IndexedSeq[Int] = Vector(2, 3, 4) scala> for { | i <- Every(1, 2, 3) | j <- Every('a', 'b', 'c') | } yield (i, j) res3: org.scalactic.Every[(Int, Char)] = Many((1,a), (1,b), (1,c), (2,a), (2,b), (2,c), (3,a), (3,b), (3,c)) scala> for { | i <- Every(1, 2, 3) if i < 10 | j <- Every('a', 'b', 'c') | } yield (i, j) res6: scala.collection.immutable.IndexedSeq[(Int, Char)] = Vector((1,a), (1,b), (1,c), (2,a), (2,b), (2,c), (3,a), (3,b), (3,c))
== Motivation for Every
s ==
Although Every
is a general-purpose, non-empty ordered collection, it was motivated by the desire to enable easy accumulation of errors in Or
s. For examples of Every
used in that use case, see the Accumulating errors with Or
section in the main documentation for Or
.
Type parameters
- T
-
the type of elements contained in this
Every
Attributes
- Companion
- object
- Source
- Every.scala
- Supertypes
-
trait Serializabletrait Producttrait Equalstrait PartialFunction[Int, T]trait Int => Tclass Objecttrait Matchableclass AnyShow all
- Known subtypes
Companion object for abstract class Every
.
Companion object for abstract class Every
.
Attributes
- Companion
- class
- Source
- Every.scala
- Supertypes
-
trait Sumtrait Mirrorclass Objecttrait Matchableclass Any
- Self type
-
Every.type
Provides ScalaTest's “explicitly DSL,” which facilitates the explicit specification of an Equality[T]
or a Uniformity[T]
where Equality[T]
is taken implicitly.
Provides ScalaTest's “explicitly DSL,” which facilitates the explicit specification of an Equality[T]
or a Uniformity[T]
where Equality[T]
is taken implicitly.
The Explicitly DSL can be used with the ===
and !==
operators of Scalactic as well as the should
equal
, be
, contain
, and ===
syntax of ScalaTest matchers.
If you want to customize equality for a type in general, you would likely want to place an implicit Equality[T]
for that type in scope (or in T
's companion object). That implicit equality definition will then be picked up and used when that type is compared for equality with the equal
, be
, and contain
matchers in ScalaTest tests and with ===
in both tests and production code. If you just want to use a custom equality for a single comparison, however, you may prefer to pass it explicitly. For example, if you have an implicit Equality[String]
in scope, you can force a comparison to use the default equality with this syntax:
// In production code: if ((result === "hello")(decided by defaultEquality)) true else false // In tests: result should equal ("hello") (decided by defaultEquality)
The explicitly DSL also provides support for specifying a one-off equality that is based on a normalization. For example, Scalactic offers a StringNormalizations
trait that provides methods such as trimmed
and lowerCased
that return Normalization[String]
instances that normalize by trimming and lower-casing, respectively. If you bring those into scope by mixing in or importing the members of StringNormalizations
, you could use the explicitly DSL like this:
// In production code: if ((result === "hello")(after being lowerCased)) true else false // In tests: result should equal ("hello") (after being lowerCased and trimmed)
If you prefer not to use English-like DSLs in your production code, you can alternatively not use the Explicitly
trait and instead write:
// To explicitly specify an Equality instance, just specify it: if ((result === "hello")(Equality.default)) true else false // To base an Equality instance on a Uniformity, just // call toEquality on it: if ((result === "hello")(lowerCased.toEquality)) true else false
Attributes
- Companion
- object
- Source
- Explicitly.scala
- Supertypes
-
class Objecttrait Matchableclass Any
- Known subtypes
-
object Explicitly.type
Companion object for Explicitly
, which enables the Scalactic explicitly DSL to be imported rather than mixed in, like this:
Companion object for Explicitly
, which enables the Scalactic explicitly DSL to be imported rather than mixed in, like this:
import org.scalactic._ import Explicitly._ // Use the explicitly DSL...
Attributes
- Companion
- trait
- Source
- Explicitly.scala
- Supertypes
- Self type
-
Explicitly.type
Indicates a validation failed, describing the failure with a contained error value.
Indicates a validation failed, describing the failure with a contained error value.
Type parameters
- E
-
the type of value describing a validation failure for this
Fail
Value parameters
- error
-
an error value describing the validation failure
Attributes
- Source
- Validation.scala
- Supertypes
-
trait Validation[E]trait Serializabletrait Producttrait Equalsclass Objecttrait Matchableclass AnyShow all
Trait providing an implicit class that adds a validating
method to Future
, which takes one or more validation functions and returns either the same Future
if either the Future
had already failed or its value passes all the functions, or `ValidationFailedException` containing an error message describing the first validation that failed.
Trait providing an implicit class that adds a validating
method to Future
, which takes one or more validation functions and returns either the same Future
if either the Future
had already failed or its value passes all the functions, or `ValidationFailedException` containing an error message describing the first validation that failed.
Here's an example validation method, which passes if the given Int
is evenly divisible by 10 (i.e., the result will be <code>Pass</code>). If the value does not pass this test, the result is a <code>Fail</code> containing a helpful error message string.
scala> import org.scalactic._ import org.scalactic._ scala> import FutureSugar._ import org.scalactic.FutureSugar._ scala> import scala.concurrent.Future import scala.concurrent.Future scala> import scala.concurrent.ExecutionContext.Implicits.global import scala.concurrent.ExecutionContext.Implicits.global scala> def isRound(i: Int): Validation[ErrorMessage] = | if (i % 10 == 0) Pass else Fail(i + " was not a round number") isRound: (i: Int)org.scalactic.Validation[org.scalactic.ErrorMessage]
Validation will be attempted on a successful Try
. If the validation succeeds, the resulting Future
will be the same successful Future
with the same value. (A "validation" only transforms the Future
if the validation fails, otherwise it is the same Future
. The only difference is its value has now been proven valid.) In the following example, a successful Future[Int]
with the value 100 passes the validation (which checks whether 100 is evenly divisible by 10), therefore the result of the validating
call is the same successful Future
with the same value.
scala> val fut100 = Future(100) fut100: scala.concurrent.Future[Int] = scala.concurrent.impl.Promise$DefaultPromise@67f9c9c6 scala> fut100.value res0: Option[scala.util.Try[Int]] = Some(Success(100)) scala> val round100 = fut100.validating(isRound) round100: scala.concurrent.Future[Int] = scala.concurrent.impl.Promise$DefaultPromise@1ac2f0d1 scala> round100.value res1: Option[scala.util.Try[Int]] = Some(Success(100))
If validation fails, the successful Future
will be transformed into a failed one, with a ValidationFailedException
that contains the error message returned by the validation function. In the following example, 42 fails the validation because it is not evenly divisible by 10:
scala> val fut42 = Future(42) fut42: scala.concurrent.Future[Int] = scala.concurrent.impl.Promise$DefaultPromise@19c6e4d1 scala> fut42.value res2: Option[scala.util.Try[Int]] = Some(Success(42)) scala> val round42 = fut42.validating(isRound) round42: scala.concurrent.Future[Int] = scala.concurrent.impl.Promise$DefaultPromise@b5175d scala> round42.value res3: Option[scala.util.Try[Int]] = Some(Failure(org.scalactic.exceptions.ValidationFailedException: 42 was not a round number))
If validating
is called on a failed Future
, it just returns the same failed Future
:
scala> val futEx = Future[Int] { throw new Exception("oops!") } futEx: scala.concurrent.Future[Int] = scala.concurrent.impl.Promise$DefaultPromise@3ba0299c scala> futEx.value res4: Option[scala.util.Try[Int]] = Some(Failure(java.lang.Exception: oops!)) scala> val roundEx = futEx.validating(isRound) roundEx: scala.concurrent.Future[Int] = scala.concurrent.impl.Promise$DefaultPromise@22bf1acf scala> roundEx.value res5: Option[scala.util.Try[Int]] = Some(Failure(java.lang.Exception: oops!))
The validating
method accepts one or more validation functions. If you pass more than one, they will be tried in order up until the first failure, whose error message will appear in the ValidationFailedException
. In other words, validating
will short circuit at the first error and return that. It will not accumulate errors. For example, the following validation will short circuit after the isDivBy3
function fails:
scala> def isDivBy3(i: Int): Validation[ErrorMessage] = | if (i % 3 == 0) Pass else Fail(i + " was not divisible by 3") isDivBy3: (i: Int)org.scalactic.Validation[org.scalactic.ErrorMessage] scala> def isAnswerToLifeTheUniverseAndEverything(i: Int): Validation[ErrorMessage] = | if (i == 42) Pass else Fail(i + " did not equal 42") isAnswerToLifeTheUniverseAndEverything: (i: Int)org.scalactic.Validation[org.scalactic.ErrorMessage] scala> val futShort = fut100.validating(isRound, isDivBy3, isAnswerToLifeTheUniverseAndEverything) futShort: scala.concurrent.Future[Int] = scala.concurrent.impl.Promise$DefaultPromise@30bb943e scala> futShort.value res11: Option[scala.util.Try[Int]] = Some(Failure(org.scalactic.exceptions.ValidationFailedException: 100 was not divisible by 3))
Attributes
- Companion
- object
- Source
- FutureSugar.scala
- Supertypes
-
class Objecttrait Matchableclass Any
- Known subtypes
-
object FutureSugar.type
Companion object for FutureSugar
enabling its members to be imported as an alternative to mixing them in.
Companion object for FutureSugar
enabling its members to be imported as an alternative to mixing them in.
Attributes
- Companion
- trait
- Source
- FutureSugar.scala
- Supertypes
- Self type
-
FutureSugar.type
Contains a “good” value.
Contains a “good” value.
You can decide what “good” means, but it is expected Good
will be commonly used to hold valid results for processes that may fail with an error instead of producing a valid result.
Value parameters
- g
-
the “good” value
Attributes
Companion object for Good
that offers, in addition to the standard factory method for Good
that takes single “good” type, an parameterless apply used to narrow the Good
type when creating a Bad
.
Provides an implicit conversion that will be applied only if a higher-priority implicit conversion declared a subtrait is not applicable.
Provides an implicit conversion that will be applied only if a higher-priority implicit conversion declared a subtrait is not applicable.
The purpose of this trait is to make the ===
operator symetric. In other words, a ===
invocation will be allowed if subtype relationship exists in either direction. For example, in the following expression, the left hand side is a subtype of the right hand side:
List(1, 2, 3) === Seq(1, 2, 3)
But in the next expression, it the right hand side is a subtype of the left hand side
Seq(1, 2, 3) === List(1, 2, 3)
The first expression above is enabled by the implicit conversion typeCheckedConstraint
in trait TypeCheckedTripleEquals
. The second expression above is enabled by the implicit conversion lowPriorityTypeCheckedConstraint
in this trait.
The reason these two implicit methods aren't both declared in the subtraits is that if the subtype relationship existed in both directions, they would conflict. This can happen when the exact same type is on both the left and right hand sides, because a type is a subtype of itself. By placing one of them in this supertrait, the higher priority conversion will be selected.
Attributes
- Source
- LowPriorityTypeCheckedConstraint.scala
- Supertypes
- Known subtypes
-
trait TypeCheckedTripleEqualsobject TypeCheckedTripleEquals.type
An Every
that contains two or more elements.
An Every
that contains two or more elements.
For more information and examples, see the main documentation for superclass Every
.
Type parameters
- T
-
the type of the element contained in this
Many
Value parameters
- firstElement
-
the first element (with index 0) contained in this
Many
- otherElements
-
a varargs of zero or more other elements (with index 2, 3, ...) contained in this
Many
- secondElement
-
the second element (with index 1) contained in this
Many
Attributes
- Source
- Every.scala
- Supertypes
-
class Every[T]trait Serializabletrait Producttrait Equalstrait PartialFunction[Int, T]trait Int => Tclass Objecttrait Matchableclass AnyShow all
Provides an implicit method that loosens the equality constraint defined by TypeCheckedTripleEquals
or ConversionCheckedTripleEquals
for Scala Map
s to one that more closely matches Scala's approach to Map
equality.
Provides an implicit method that loosens the equality constraint defined by TypeCheckedTripleEquals
or ConversionCheckedTripleEquals
for Scala Map
s to one that more closely matches Scala's approach to Map
equality.
Scala's approach to Map
equality is that if both objects being compared are Map
s, the elements are compared to determine equality. This means you could compare an immutable TreeMap
and a mutable HashMap
for equality, for instance, and get true so long as the two maps contained the same key-value mappings. Here's an example:
scala> import scala.collection.immutable.TreeMap import scala.collection.immutable.TreeMap scala> import scala.collection.mutable.HashMap import scala.collection.mutable.HashMap scala> TreeMap("one" -> 1, "two" -> 2) == HashMap("one" -> 1, "two" -> 2) res0: Boolean = true
Such a comparison would not, however, compile if you used ===
under either TypeCheckedTripleEquals
or ConversionCheckedTripleEquals
, because TreeMap
and HashMap
are not in a subtype/supertype relationship, nor does an implicit conversion by default exist between them:
scala> import org.scalactic._ import org.scalactic._ scala> import TypeCheckedTripleEquals._ import TypeCheckedTripleEquals._ scala> TreeMap("one" -> 1, "two" -> 2) === HashMap("one" -> 1, "two" -> 2) <console>:16: error: types scala.collection.immutable.TreeMap[String,Int] and scala.collection.mutable.HashMap[String,Int] do not adhere to the equality constraint selected for the === and !== operators; the missing implicit parameter is of type org.scalactic.EqualityConstraint[scala.collection.immutable.TreeMap[String,Int], scala.collection.mutable.HashMap[String,Int]] TreeMap("one" -> 1, "two" -> 2) === HashMap("one" -> 1, "two" -> 2) ^
If you mix or import the implicit conversion provided by MapEqualityConstraint
, however, the comparison will be allowed:
scala> import MapEqualityConstraints._ import MapEqualityConstraints._ scala> TreeMap("one" -> 1, "two" -> 2) === HashMap("one" -> 1, "two" -> 2) res2: Boolean = true
The equality constraint provided by this trait requires that both left and right sides are subclasses of scala.collection.GenMap
and that an EqualityConstraint
can be found for both key types and both value types. In the example above, both the TreeMap
and HashMap
are subclasses of scala.collection.GenMap
, and the regular TypeCheckedTripleEquals
provides equality constraints for the key types, both of which are String
, and value types, both of which are Int
. By contrast, this trait would not allow a TreeMap[String, Int]
to be compared against a HashMap[String, java.util.Date]
, because no equality constraint will exist between the value types Int
and Date
:
scala> import java.util.Date import java.util.Date scala> TreeMap("one" -> 1, "two" -> 2) === HashMap("one" -> new Date, "two" -> new Date) <console>:20: error: types scala.collection.immutable.TreeMap[String,Int] and scala.collection.mutable.HashMap[String,java.util.Date] do not adhere to the equality constraint selected for the === and !== operators; the missing implicit parameter is of type org.scalactic.EqualityConstraint[scala.collection.immutable.TreeMap[String,Int], scala.collection.mutable.HashMap[String,java.util.Date]] TreeMap("one" -> 1, "two" -> 2) === HashMap("one" -> new Date, "two" -> new Date) ^
Attributes
- Companion
- object
- Source
- MapEqualityConstraints.scala
- Supertypes
-
class Objecttrait Matchableclass Any
- Known subtypes
-
object MapEqualityConstraints.typeobject TraversableEqualityConstraints.type
Companion object that facilitates the importing of MapEqualityConstraints
members as an alternative to mixing it in. One use case is to import MapEqualityConstraints
members so you can use them in the Scala interpreter.
Companion object that facilitates the importing of MapEqualityConstraints
members as an alternative to mixing it in. One use case is to import MapEqualityConstraints
members so you can use them in the Scala interpreter.
Attributes
- Companion
- trait
- Source
- MapEqualityConstraints.scala
- Supertypes
- Self type
Provides an implicit conversion that allows norm
to be invoked on any value of type T
for which an implicit Normalization[T]
exists.
Provides an implicit conversion that allows norm
to be invoked on any value of type T
for which an implicit Normalization[T]
exists.
Here's an example:
scala> import org.scalactic._ import org.scalactic._ scala> import StringNormalizations._ import StringNormalizations._ scala> implicit val stringNormalization = lowerCased and trimmed stringNormalization: org.scalactic.Uniformity[String] = org.scalactic.Uniformity$$anon$1@19ba67ec scala> import NormMethods._ import NormMethods._ scala> val s = " There " s: String = " There " scala> "Hey " + s + "!" res5: String = Hey There ! scala> "Hey " + s.norm + "!" res6: String = Hey there!
Attributes
- Companion
- object
- Source
- NormMethods.scala
- Supertypes
-
class Objecttrait Matchableclass Any
- Known subtypes
-
object NormMethods.type
Companion object for NormMethods
enabling its members to be imported as an alternative to mixing them in.
Companion object for NormMethods
enabling its members to be imported as an alternative to mixing them in.
Attributes
- Companion
- trait
- Source
- NormMethods.scala
- Supertypes
- Self type
-
NormMethods.type
Defines a custom way to normalize instances of a type.
Defines a custom way to normalize instances of a type.
For example, to normalize Double
s by truncating off any decimal part, you might write:
import org.scalactic._ val truncated = new Normalization[Double] { def normalized(d: Double) = d.floor }
Given this definition you could use it with the Explicitly
DSL like this:
import org.scalatest._ import Matchers._ import TypeCheckedTripleEquals._ (2.1 should === (2.0)) (after being truncated)
Note that to use a Normalization
with the Explicitly
DSL, you'll need to use TypeCheckedTripleEquals
. If you're just using plain-old TripleEquals
, you'll need a Uniformity
, a Normalization
subclass.
If you make the truncated
val
implicit and import or mix in the members of NormMethods
, you can access the behavior by invoking .norm
on Double
s.
implicit val doubleNormalization = truncated import NormMethods._ val d = 2.1 d.norm // returns 2.0
Type parameters
- A
-
the type whose normalization is being defined
Attributes
- Source
- Normalization.scala
- Supertypes
-
class Objecttrait Matchableclass Any
- Known subtypes
-
trait Uniformity[A]trait AbstractStringUniformity
- Self type
An Equality[A]
implementation that determines the equality of two objects by normalizing one or both objects, then comparing the results using an “after normalization” equality referenced from the afterNormalizationEquality
member. By default, the afterNormalizationEquality
is an instance of Equality.default[A]
.
An Equality[A]
implementation that determines the equality of two objects by normalizing one or both objects, then comparing the results using an “after normalization” equality referenced from the afterNormalizationEquality
member. By default, the afterNormalizationEquality
is an instance of Equality.default[A]
.
NormalizingEquality
is returned by the Explicitly
DSL's “after
being
” syntax, using for the afterNormalizationEquality
the implicit Equality
in scope for the type of Uniformity
passed to being
. Here's an example:
scala> import org.scalactic._ import org.scalactic._ scala> import Explicitly._ import Explicitly._ scala> import StringNormalizations._ import StringNormalizations._ scala> after being lowerCased res0: org.scalactic.NormalizingEquality[String] = ComposedNormalizingEquality(Equality.default,lowerCased)
Attributes
- Source
- NormalizingEquality.scala
- Supertypes
- Self type
An Equivalence[A]
implementation that determines the equality of two objects by normalizing one or both objects, then comparing the results using an “after normalization” Equivalence
referenced from the afterNormalizationEquivalence
member. By default, the afterNormalizationEquivalence
is an instance of Equivalence.default[A]
.
An Equivalence[A]
implementation that determines the equality of two objects by normalizing one or both objects, then comparing the results using an “after normalization” Equivalence
referenced from the afterNormalizationEquivalence
member. By default, the afterNormalizationEquivalence
is an instance of Equivalence.default[A]
.
NormalizingEquivalence
is returned by the Explicitly
DSL's “after
being
” syntax, using for the afterNormalizationEquivalence
the implicit Equivalence
in scope for the type of Normalization
passed to being
. Here's an example:
scala> import org.scalactic._ import org.scalactic._ scala> import Explicitly._ import Explicitly._ scala> val lowerCased: Normalization[String] = StringNormalizations.lowerCased lowerCased: org.scalactic.Normalization[String] = lowerCased scala> after being lowerCased res0: org.scalactic.NormalizingEquivalence[String] = ComposedNormalizingEquivalence(Equality.default,lowerCased)
Attributes
- Source
- NormalizingEquivalence.scala
- Supertypes
- Self type
An Every
that contains exactly one element.
An Every
that contains exactly one element.
For more information and examples, see the main documentation for superclass Every
.
Type parameters
- T
-
the type of the element contained in this
One
Value parameters
- loneElement
-
the lone element contained in this
One
Attributes
- Source
- Every.scala
- Supertypes
-
class Every[T]trait Serializabletrait Producttrait Equalstrait PartialFunction[Int, T]trait Int => Tclass Objecttrait Matchableclass AnyShow all
Trait providing an implicit class that adds a toOr
method to Option
, which converts Some
to Good
, None
to Bad
.
Trait providing an implicit class that adds a toOr
method to Option
, which converts Some
to Good
, None
to Bad
.
You can use the toOr
method to record information about why a processing of nested Option
s resulted in None
. For example, the following for
expression results in None
if either the passed optional Person
is None
or else if the contained optional age is None
:
scala> case class Person(name: String, age: Option[Int]) defined class Person scala> def ageOf(person: Option[Person]) = | for { | per <- person | age <- per.age | } yield age ageOf: (person: Option[Person])Option[Int] scala> ageOf(Some(Person("Ralph", Some(32)))) res0: Option[Int] = Some(32) scala> ageOf(Some(Person("Curt", None))) res3: Option[Int] = None scala> ageOf(None) res2: Option[Int] = None
If you instead populate the for
expression with Or
s, supplying an error message or other "bad" value to the toOr
method in case of None
, you'll get an indication of which part failed if a None
is encountered:
scala> import OptionSugar._ import OptionSugar._ scala> def ageOf(person: Option[Person]) = | for { | per <- person toOr "no person here" | age <- per.age toOr "ageless person" | } yield age ageOf: (person: Option[Person])org.scalactic.Or[Int,String] scala> ageOf(Some(Person("Ralph", Some(32)))) res1: org.scalactic.Or[Int,String] = Good(32) scala> ageOf(Some(Person("Curt", None))) res2: org.scalactic.Or[Int,String] = Bad(ageless person) scala> ageOf(None) res3: org.scalactic.Or[Int,String] = Bad(no person here)
Attributes
- Companion
- object
- Source
- OptionSugar.scala
- Supertypes
-
class Objecttrait Matchableclass Any
- Known subtypes
-
object OptionSugar.type
Companion object for OptionSugar
enabling its members to be imported as an alternative to mixing them in.
Companion object for OptionSugar
enabling its members to be imported as an alternative to mixing them in.
Attributes
- Companion
- trait
- Source
- OptionSugar.scala
- Supertypes
- Self type
-
OptionSugar.type
Represents a value that is one of two possible types, with one type being “good” and the other “bad.”
Represents a value that is one of two possible types, with one type being “good” and the other “bad.”
An Or
will either be a “good” value wrapped in an instance of Good
or a “bad” value wrapped in an instance of Bad
.
== The motivation for Or
==
Or
differs from Scala's Either
type in that Either
treats both its Left
and Right
alternatives in an identical manner, whereas Or
treats its two alternatives differently: it favors Good
over Bad
. Because of this, it is more convenient to work with Or
s when you prefer one alternative over the other; for example, if one alternative represents a valid result and another represents an error.
To illustrate, imagine you want to create instances this Person
class from user input strings:
case class Person(name: String, age: Int)
You might write a method that parses the name from user input string and returns an Option[String]
: None
if the string is empty or blank, else the trimmed string wrapped in a Some
:
def parseName(input: String): Option[String] = { val trimmed = input.trim if (!trimmed.isEmpty) Some(trimmed) else None }
You might also write a method that parses the age from user input string and returns an Option[Int]
: None
if either the string is not a valid integer or it is a negative integer, else the string converted to an integer wrapped in a Some
:
def parseAge(input: String): Option[Int] = { try { val age = input.trim.toInt if (age >= 0) Some(age) else None } catch { case _: NumberFormatException => None } }
With these building blocks you could write a method that parses name and age input strings and returns either a Person
, wrapped in a Some
, or None
if either the name or age, or both, was invalid:
def parsePerson(inputName: String, inputAge: String): Option[Person] = for { name <- parseName(inputName) age <- parseAge(inputAge) } yield Person(name, age)
Here are some examples of invoking parsePerson
:
parsePerson("Bridget Jones", "29") // Result: Some(Person(Bridget Jones,29)) parsePerson("Bridget Jones", "") // Result: None parsePerson("Bridget Jones", "-29") // Result: None parsePerson("", "") // Result: None
Now imagine you want to give an error message back if the user's input is invalid. You might rewrite the parsing methods to return an Either
instead. In this case, the desired result is a valid name or age, which by convention should be placed on the right of the Either
. The left will be a String
error message. Here's the new parseName
function, which returns an Either[String, String]
:
def parseName(input: String): Either[String, String] = { val trimmed = input.trim if (!trimmed.isEmpty) Right(trimmed) else Left(s""""${input}" is not a valid name""") }
And here's the new parseAge
function, which returns an Either[String, Int]
:
def parseAge(input: String): Either[String, Int] = { try { val age = input.trim.toInt if (age >= 0) Right(age) else Left(s""""${age}" is not a valid age""") } catch { case _: NumberFormatException => Left(s""""${input}" is not a valid integer""") } }
The new parsePerson
method will return an Either[String, Person]
:
def parsePerson(inputName: String, inputAge: String): Either[String, Person] = for { name <- parseName(inputName).right age <- parseAge(inputAge).right } yield Person(name, age)
Note that Either
requires you to add .right
at the end of each generator in the for
expression. Although the convention is to place the valid result on the right, you must explicitly (and repetitively) indicate that you've done so by transforming the Either
to a RightProjection
by invoking .right
at each step. Given this implementation, the parsePerson
method will now short-circuit at the first sign of trouble (as it did when we used an Option
), but you now get the first error message returned in a Left
. Here are some examples:
parsePerson("Bridget Jones", "29") // Result: Right(Person(Bridget Jones,29)) parsePerson("Bridget Jones", "") // Result: Left("" is not a valid integer) parsePerson("Bridget Jones", "-29") // Result: Left("-29" is not a valid age) parsePerson("", "") // Result: Left("" is not a valid name)
== An Either
with “attitude” ==
Because Or
declares one alternative to be “good” and the other “bad,” it is more convenient than Either
in this kind of situation. One difference to note with Or
is that the Good
alternative is on the left, Bad
on the right. The reason is that Or
is designed to be written using infix notation, and placing the “happy path” first is more readable. For example, instead of writing:
Or[Int, ErrorMessage]
You can write:
Int Or ErrorMessage
Here's how the parseName
method might be written using an Or
, where ErrorMessage
is a type alias for String
declared in the org.scalactic
package object:
import org.scalactic._ def parseName(input: String): String Or ErrorMessage = { val trimmed = input.trim if (!trimmed.isEmpty) Good(trimmed) else Bad(s""""${input}" is not a valid name""") }
You can think of the String
Or
ErrorMessage
result type like this:
TheparseName
method will return a nameString
or, if the input string is not a valid name, anErrorMessage
.
Here's how the parseAge
method might be written:
def parseAge(input: String): Int Or ErrorMessage = { try { val age = input.trim.toInt if (age >= 0) Good(age) else Bad(s""""${age}" is not a valid age""") } catch { case _: NumberFormatException => Bad(s""""${input}" is not a valid integer""") } }
Given these implementations, here's how you'd write the parsePerson
method:
def parsePerson(inputName: String, inputAge: String): Person Or ErrorMessage = for { name <- parseName(inputName) age <- parseAge(inputAge) } yield Person(name, age)
Because of Or
's attitude, you need not write .good
at the end of each generator. Or
will keep going so long as each step produces a Good
, short circuiting at the first sign of a Bad
. Here are a few invocations of this parsePerson
method:
parsePerson("Bridget Jones", "29") // Result: Good(Person(Bridget Jones,29)) parsePerson("Bridget Jones", "") // Result: Bad("" is not a valid integer) parsePerson("Bridget Jones", "-29") // Result: Bad("-29" is not a valid age) parsePerson("", "") // Result: Bad("" is not a valid name)
== Accumulating errors with Or
==
Another difference between Or
and Either
is that Or
enables you to accumulate errors if the Bad
type is an Every
. An Every
is similar to a Seq
in that it contains ordered elements, but different from Seq
in that it cannot be empty. An Every
is either a One
, which contains one and only one element, or a Many
, which contains two or more elements.
Note: an Or
whose Bad
type is an Every
, or one of its subtypes, is called an “accumulating Or
.”
To rewrite the previous example so that errors can be accumulated, you need first to return an Every
as the Bad
type. Here's how you'd change the parseName
method:
def parseName(input: String): String Or One[ErrorMessage] = { val trimmed = input.trim if (!trimmed.isEmpty) Good(trimmed) else Bad(One(s""""${input}" is not a valid name""")) }
Because parseName
will either return a valid name String
wrapped in a Good
, or one error message, wrapped in a Bad
, you would write the Bad
type as One[ErrorMessage]
. The same is true for parseAge
:
def parseAge(input: String): Int Or One[ErrorMessage] = { try { val age = input.trim.toInt if (age >= 0) Good(age) else Bad(One(s""""${age}" is not a valid age""")) } catch { case _: NumberFormatException => Bad(One(s""""${input}" is not a valid integer""")) } }
Because a for
expression short-circuits on the first Bad
encountered, you'll need to use a different approach to write the parsePerson
method. In this example, the withGood
method from trait Accumulation
will do the trick:
import Accumulation._ def parsePerson(inputName: String, inputAge: String): Person Or Every[ErrorMessage] = { val name = parseName(inputName) val age = parseAge(inputAge) withGood(name, age) { Person(_, _) } }
Trait Accumulation
offers overloaded withGood
methods that take 1 to 22 accumulating Or
s, plus a function taking the same number of corresponding Good
values. In this example, if both name
and age
are Good
s, the withGood
method will pass the good name String
and age Int
to the Person(_, _)
function, and return the resulting Person
object wrapped in a Good
. If either name
and age
, or both, are Bad
, withGood
will return the accumulated errors in a Bad
.
The result of parsePerson
, if Bad
, will therefore contain either one or two error messages, i.e., the result will either be a One
or a Many
. As a result, the result type of parsePerson
must be Person
Or
Every[ErrorMessage]
. Regardless of whether a Bad
result contains one or two error messages, it will contain every error message. Here's some invocations of this accumulating version of parsePerson
:
parsePerson("Bridget Jones", "29") // Result: Good(Person(Bridget Jones,29)) parsePerson("Bridget Jones", "") // Result: Bad(One("" is not a valid integer)) parsePerson("Bridget Jones", "-29") // Result: Bad(One("-29" is not a valid age)) parsePerson("", "") // Result: Bad(Many("" is not a valid name, "" is not a valid integer))
Note that in the last example, the Bad
contains an error message for both name and age.
== Other ways to accumulate errors ==
The Accumlation
trait also enables other ways of accumulating errors.
=== Using combined
===
If you have a collection of accumulating Or
s, for example, you can combine them into one Or
using combined
, like this:
List(parseAge("29"), parseAge("30"), parseAge("31")).combined // Result: Good(List(29, 30, 31)) List(parseAge("29"), parseAge("-30"), parseAge("31")).combined // Result: Bad(One("-30" is not a valid age)) List(parseAge("29"), parseAge("-30"), parseAge("-31")).combined // Result: Bad(Many("-30" is not a valid age, "-31" is not a valid age))
=== Using validatedBy
===
Or if you have a collection of values and a function that transforms that type of value into an accumulating Or
s, you can validate the values using the function using validatedBy
, like this:
List("29", "30", "31").validatedBy(parseAge) // Result: Good(List(29, 30, 31)) List("29", "-30", "31").validatedBy(parseAge) // Result: Bad(One("-30" is not a valid age)) List("29", "-30", "-31").validatedBy(parseAge) // Result: Bad(Many("-30" is not a valid age, "-31" is not a valid age))
=== Using zip
===
You can also zip two accumulating Or
s together. If both are Good
, you'll get a Good
tuple containin both original Good
values. Otherwise, you'll get a Bad
containing every error message. Here are some examples:
parseName("Dude") zip parseAge("21") // Result: Good((Dude,21)) parseName("Dude") zip parseAge("-21") // Result: Bad(One("-21" is not a valid age)) parseName("") zip parseAge("-21") // Result: Bad(Many("" is not a valid name, "-21" is not a valid age))
=== Using when
===
In addition, given an accumlating Or
, you can pass one or more validation functions to when
on the Or
to submit that Or
to further scrutiny. A validation function accepts a Good
type and returns a Validation[E]
, where E
is the type in the Every
in the Bad
type. For an Int
Or
One[ErrorMessage]
, for example the validation function type would be Int
=>
Validation[ErrorMessage]
. Here are a few examples:
def isRound(i: Int): Validation[ErrorMessage] = if (i % 10 == 0) Pass else Fail(i + " was not a round number") def isDivBy3(i: Int): Validation[ErrorMessage] = if (i % 3 == 0) Pass else Fail(i + " was not divisible by 3")
If the Or
on which you call when
is already Bad
, you get the same (Bad
) Or
back, because no Good
value exists to pass to the valiation functions:
parseAge("-30").when(isRound, isDivBy3) // Result: Bad(One("-30" is not a valid age))
If the Or
on which you call when
is Good
, and also passes all the validation functions (i.e., the all return None
), you again get the same Or
back, but this time, a Good
one:
parseAge("30").when(isRound, isDivBy3) // Result: Good(30)
If one or more of the validation functions fails, however, you'll get a Bad
back contining every error. Here are some examples:
parseAge("33").when(isRound, isDivBy3) // Result: Bad(One(33 was not a round number)) parseAge("20").when(isRound, isDivBy3) // Result: Bad(One(20 was not divisible by 3)) parseAge("31").when(isRound, isDivBy3) // Result: Bad(Many(31 was not a round number, 31 was not divisible by 3))
Note that you can use when
to accumulate errors in a for
expression involving an accumulating Or
, like this:
for (age <- parseAge("-30") when (isRound, isDivBy3)) yield age // Result: Bad(One("-30" is not a valid age)) for (age <- parseAge("30") when (isRound, isDivBy3)) yield age // Result: Good(30) for (age <- parseAge("33") when (isRound, isDivBy3)) yield age // Result: Bad(One(33 was not a round number)) for (age <- parseAge("20") when (isRound, isDivBy3)) yield age // Result: Bad(One(20 was not divisible by 3)) for (age <- parseAge("31") when (isRound, isDivBy3)) yield age // Result: Bad(Many(31 was not a round number, 31 was not divisible by 3))
== Much ado about Nothing
==
Because Or
has two types, but each of its two subtypes only takes a value of one or the other type, the Scala compiler will infer Nothing
for the unspecified type:
scala> Good(3) res0: org.scalactic.Good[Int,Nothing] = Good(3) scala> Bad("oops") res1: org.scalactic.Bad[Nothing,String] = Bad(oops)
Often Nothing
will work fine, as it will be widened as soon as the compiler encounters a more specific type. Sometimes, however, you may need to specify it. In such situations you can use this syntax:
scala> Good(3).orBad[String] res2: org.scalactic.Good[Int,String] = Good(3) scala> Good[Int].orBad("oops") res3: org.scalactic.Bad[Int,String] = Bad(oops)
If you want to specify both types, because you don't like the inferred type, you can do so like this:
scala> Good[AnyVal, String](3) res4: org.scalactic.Good[AnyVal,String] = Good(3) scala> Bad[Int, ErrorMessage]("oops") res5: org.scalactic.Bad[Int,org.scalactic.ErrorMessage] = Bad(oops)
But you may find the code is clearer if you instead use a type ascription, like this:
scala> Good(3): AnyVal Or String res6: org.scalactic.Or[AnyVal,String] = Good(3) scala> Bad("oops"): Int Or ErrorMessage res7: org.scalactic.Or[Int,org.scalactic.ErrorMessage] = Bad(oops)
Note: The Or
hierarchy was inspired in part by the disjoint union (/
) and Validation
types of scalaz
, the ProcessResult
type of Typesafe Activator, and the Result
type of ScalaKittens.
Attributes
The companion object for Or
providing factory methods for creating Or
s from Either
s and Try
s.
Indicates a validation succeeded.
Indicates a validation succeeded.
Attributes
- Source
- Validation.scala
- Supertypes
-
trait Singletontrait Producttrait Mirrortrait Validation[Nothing]trait Serializabletrait Producttrait Equalsclass Objecttrait Matchableclass AnyShow all
- Self type
-
Pass.type
A function that given any object will produce a “pretty” string representation of that object, where “pretty” is in the eye of the implementer.
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.scalactic._ import org.scalactic._ 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"
(thetoString
result surrounded by double quotes) -
Char
to:'c'
(thetoString
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.scalactic.Good
to:Good("3")
-
org.scalactic.Bad
to:Bad("3")
-
org.scalactic.One
to:One("3")
-
org.scalactic.Many
to:Many("1", "2", "3")
-
scala.collection.Iterable
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.
Attributes
- Companion
- object
- Source
- Prettifier.scala
- Supertypes
-
trait Serializableclass Objecttrait Matchableclass Any
Companion object for Prettifier
that provides a default Prettifier
implementation.
Companion object for Prettifier
that provides a default Prettifier
implementation.
Attributes
- Companion
- trait
- Source
- Prettifier.scala
- Supertypes
-
class Objecttrait Matchableclass Any
- Self type
-
Prettifier.type
Provides an implicit conversion that enables pretty
to be invoked on any object, to transform that object into a String
representation.
Provides an implicit conversion that enables pretty
to be invoked on any object, to transform that object into a String
representation.
Attributes
- Companion
- object
- Source
- PrettyMethods.scala
- Supertypes
-
class Objecttrait Matchableclass Any
- Known subtypes
-
object PrettyMethods.type
Companion object for trait PrettyMethods
enabling its members to be imported as an alternative to mixing them in.
Companion object for trait PrettyMethods
enabling its members to be imported as an alternative to mixing them in.
Attributes
- Companion
- trait
- Source
- PrettyMethods.scala
- Supertypes
- Self type
-
PrettyMethods.type
Attributes
- Source
- PrettyPair.scala
- Supertypes
-
trait Serializabletrait Producttrait Equalsclass Objecttrait Matchableclass AnyShow all
Trait that contains require
, and requireState
, and requireNonNull
methods for checking pre-conditions that give descriptive error messages extracted via a macro.
Trait that contains require
, and requireState
, and requireNonNull
methods for checking pre-conditions that give descriptive error messages extracted via a macro.
These methods of trait Requirements
aim to improve error messages provided when a pre-condition check fails at runtime in production code. Although it is recommended practice to supply helpful error messages when doing pre-condition checks, often people don't. Instead of this:
scala> val length = 5 length: Int = 5 scala> val idx = 6 idx: Int = 6 scala> require(idx >= 0 && idx <= length, "index, " + idx + ", was less than zero or greater than or equal to length, " + length) java.lang.IllegalArgumentException: requirement failed: index, 6, was less than zero or greater than or equal to length, 5 at scala.Predef$.require(Predef.scala:233) ...
People write simply:
scala> require(idx >= 0 && idx <= length) java.lang.IllegalArgumentException: requirement failed at scala.Predef$.require(Predef.scala:221) ...
Note that the detail message of the IllegalArgumentException
thrown by the previous line of code is simply, "requirement failed"
. Such messages often end up in a log file or bug report, where a better error message can save time in debugging the problem. By importing the members of Requirements
(or mixing in its companion trait), you'll get a more helpful error message extracted by a macro, whether or not a clue message is provided:
scala> import org.scalactic._ import org.scalactic._ scala> import Requirements._ import Requirements._ scala> require(idx >= 0 && idx <= length) java.lang.IllegalArgumentException: 6 was greater than or equal to 0, but 6 was not less than or equal to 5 at org.scalactic.Requirements$RequirementsHelper.macroRequire(Requirements.scala:56) ... scala> require(idx >= 0 && idx <= length, "(hopefully that helps)") java.lang.IllegalArgumentException: 6 was greater than or equal to 0, but 6 was not less than or equal to 5 (hopefully that helps) at org.scalactic.Requirements$RequirementsHelper.macroRequire(Requirements.scala:56) ...
The requireState
method provides identical error messages to require
, but throws IllegalStateException
instead of IllegalArgumentException
:
scala> val connectionOpen = false connectionOpen: Boolean = false scala> requireState(connectionOpen) java.lang.IllegalStateException: connectionOpen was false at org.scalactic.Requirements$RequirementsHelper.macroRequireState(Requirements.scala:71) ...
Thus, whereas the require
methods throw the Java platform's standard exception indicating a passed argument violated a precondition, IllegalArgumentException
, the requireState
methods throw the standard exception indicating an object's method was invoked when the object was in an inappropriate state for that method, IllegalStateException
.
The requireNonNull
method takes one or more variables as arguments and throws NullArgumentException
with an error messages that includes the variable names if any are null
. Here's an example:
scala> val e: String = null e: String = null scala> val f: java.util.Date = null f: java.util.Date = null scala> requireNonNull(a, b, c, d, e, f) org.scalactic.exceptions.NullArgumentException: e and f were null at org.scalactic.Requirements$RequirementsHelper.macroRequireNonNull(Requirements.scala:101) ...
Although trait Requirements
can help you debug problems that occur in production, bear in mind that a much better alternative is to make it impossible for such events to occur at all. Use the type system to ensure that all pre-conditions are met so that the compiler can find broken pre-conditions and point them out with compiler error messages. When this is not possible or practical, however, trait Requirements
is helpful.
Attributes
- Companion
- object
- Source
- Requirements.scala
- Supertypes
-
class Objecttrait Matchableclass Any
- Known subtypes
-
object Requirements.type
Companion object that facilitates the importing of Requirements
members as an alternative to mixing it in. One use case is to import Requirements
members so you can use them in the Scala interpreter:
Companion object that facilitates the importing of Requirements
members as an alternative to mixing it in. One use case is to import Requirements
members so you can use them in the Scala interpreter:
$scala -classpath scalatest.jar Welcome to Scala 2.13.6 (OpenJDK 64-Bit Server VM, Java yyy). Type in expressions for evaluation. Or try :help. scala> import org.scalactic.Requirements._ import org.scalactic.Requirements._ scala> val a = 1 a: Int = 1 scala> require(a == 2) java.lang.IllegalArgumentException: 1 did not equal 2 at org.scalactic.Requirements$RequirementsHelper.macroRequire(Requirements.scala:56) at .<init>(<console>:20) at .<clinit>(<console>) at .<init>(<console>:7) at .<clinit>(<console>) at $print(<console>) at sun.reflect.NativeMethodAccessorImpl.invoke...
Attributes
- Companion
- trait
- Source
- Requirements.scala
- Supertypes
- Self type
-
Requirements.type
Attributes
- Source
- Requirements.scala
- Supertypes
-
class Objecttrait Matchableclass Any
- Self type
-
RequirementsMacro.type
Provides an implicit method that loosens the equality constraint defined by TypeCheckedTripleEquals
or ConversionCheckedTripleEquals
for Scala Seq
s to one that more closely matches Scala's approach to Seq
equality.
Provides an implicit method that loosens the equality constraint defined by TypeCheckedTripleEquals
or ConversionCheckedTripleEquals
for Scala Seq
s to one that more closely matches Scala's approach to Seq
equality.
Scala's approach to Seq
equality is that if both objects being compared are Seq
s, the elements are compared to determine equality. This means you could compare an immutable Vector
and a mutable ListBuffer
for equality, for instance, and get true so long as the two Seq
s contained the same elements in the same order. Here's an example:
scala> import scala.collection.mutable.ListBuffer import scala.collection.mutable.ListBuffer scala> Vector(1, 2) == ListBuffer(1, 2) res0: Boolean = true
Such a comparison would not, however, compile if you used ===
under either TypeCheckedTripleEquals
or ConversionCheckedTripleEquals
, because Vector
and ListBuffer
are not in a subtype/supertype relationship, nor does an implicit conversion by default exist between them:
scala> import org.scalactic._ import org.scalactic._ scala> import TypeCheckedTripleEquals._ import TypeCheckedTripleEquals._ scala> Vector(1, 2) === ListBuffer(1, 2) <console>:16: error: types scala.collection.immutable.Vector[Int] and scala.collection.mutable.ListBuffer[Int] do not adhere to the equality constraint selected for the === and !== operators; the missing implicit parameter is of type org.scalactic.EqualityConstraint[scala.collection.immutable.Vector[Int], scala.collection.mutable.ListBuffer[Int]] Vector(1, 2) === ListBuffer(1, 2) ^
If you mix or import the implicit conversion provided by SeqEqualityConstraint
, however, the comparison will be allowed:
scala> import SeqEqualityConstraints._ import SeqEqualityConstraints._ scala> Vector(1, 2) === ListBuffer(1, 2) res2: Boolean = true
The equality constraint provided by this trait requires that both left and right sides are subclasses of scala.collection.GenSeq
and that an EqualityConstraint
can be found for the element types. In the example above, both the Vector
and ListBuffer
are subclasses of scala.collection.GenSeq
, and the regular TypeCheckedTripleEquals
provides equality constraints for the element types, both of which are Int
. By contrast, this trait would not allow a Vector[Int]
to be compared against a ListBuffer[java.util.Date]
, because no equality constraint will exist between the element types Int
and Date
:
scala> import java.util.Date import java.util.Date scala> Vector(1, 2) === ListBuffer(new Date, new Date) <console>:20: error: types scala.collection.immutable.Vector[Int] and scala.collection.mutable.ListBuffer[java.util.Date] do not adhere to the equality constraint selected for the === and !== operators; the missing implicit parameter is of type org.scalactic.EqualityConstraint[scala.collection.immutable.Vector[Int], scala.collection.mutable.ListBuffer[java.util.Date]] Vector(1, 2) === ListBuffer(new Date, new Date) ^
Attributes
- Companion
- object
- Source
- SeqEqualityConstraints.scala
- Supertypes
-
class Objecttrait Matchableclass Any
- Known subtypes
-
object SeqEqualityConstraints.typeobject TraversableEqualityConstraints.type
Companion object that facilitates the importing of SeqEqualityConstraints
members as an alternative to mixing it in. One use case is to import SeqEqualityConstraints
members so you can use them in the Scala interpreter.
Companion object that facilitates the importing of SeqEqualityConstraints
members as an alternative to mixing it in. One use case is to import SeqEqualityConstraints
members so you can use them in the Scala interpreter.
Attributes
- Companion
- trait
- Source
- SeqEqualityConstraints.scala
- Supertypes
- Self type
Provides an implicit method that loosens the equality constraint defined by TypeCheckedTripleEquals
or ConversionCheckedTripleEquals
for Scala Set
s to one that more closely matches Scala's approach to Set
equality.
Provides an implicit method that loosens the equality constraint defined by TypeCheckedTripleEquals
or ConversionCheckedTripleEquals
for Scala Set
s to one that more closely matches Scala's approach to Set
equality.
Scala's approach to Set
equality is that if both objects being compared are Set
s, the elements are compared to determine equality. This means you could compare an immutable TreeSet
and a mutable HashSet
for equality, for instance, and get true so long as the two Set
s contained the same elements in the same order. Here's an example:
scala> import scala.collection.immutable.TreeSet import scala.collection.immutable.TreeSet scala> import scala.collection.mutable.HashSet import scala.collection.mutable.HashSet scala> TreeSet(1, 2) == HashSet(1, 2) res0: Boolean = true
Such a comparison would not, however, compile if you used ===
under either TypeCheckedTripleEquals
or ConversionCheckedTripleEquals
, because TreeSet
and HashSet
are not in a subtype/supertype relationship, nor does an implicit conversion by default exist between them:
scala> import org.scalactic._ import org.scalactic._ scala> import TypeCheckedTripleEquals._ import TypeCheckedTripleEquals._ scala> TreeSet(1, 2) === HashSet(1, 2) <console>:16: error: types scala.collection.immutable.TreeSet[Int] and scala.collection.mutable.HashSet[Int] do not adhere to the equality constraint selected for the === and !== operators; the missing implicit parameter is of type org.scalactic.EqualityConstraint[scala.collection.immutable.TreeSet[Int], scala.collection.mutable.HashSet[Int]] TreeSet(1, 2) === HashSet(1, 2) ^
If you mix or import the implicit conversion provided by SetEqualityConstraint
, however, the comparison will be allowed:
scala> import SetEqualityConstraints._ import SetEqualityConstraints._ scala> TreeSet(1, 2) === HashSet(1, 2) res2: Boolean = true
The equality constraint provided by this trait requires that both left and right sides are subclasses of scala.collection.GenSet
and that an EqualityConstraint
can be found for the element types. In the example above, both the TreeSet
and HashSet
are subclasses of scala.collection.GenSet
, and the regular TypeCheckedTripleEquals
provides equality constraints for the element types, both of which are Int
. By contrast, this trait would not allow a TreeSet[Int]
to be compared against a HashSet[java.util.Date]
, because no equality constraint will exist between the element types Int
and Date
:
scala> import java.util.Date import java.util.Date scala> TreeSet(1, 2) === HashSet(new Date, new Date) <console>:20: error: types scala.collection.immutable.TreeSet[Int] and scala.collection.mutable.HashSet[java.util.Date] do not adhere to the equality constraint selected for the === and !== operators; the missing implicit parameter is of type org.scalactic.EqualityConstraint[scala.collection.immutable.TreeSet[Int], scala.collection.mutable.HashSet[java.util.Date]] TreeSet(1, 2) === HashSet(new Date, new Date) ^
Attributes
- Companion
- object
- Source
- SetEqualityConstraints.scala
- Supertypes
-
class Objecttrait Matchableclass Any
- Known subtypes
-
object SetEqualityConstraints.typeobject TraversableEqualityConstraints.type
Companion object that facilitates the importing of SetEqualityConstraints
members as an alternative to mixing it in. One use case is to import SetEqualityConstraints
members so you can use them in the Scala interpreter.
Companion object that facilitates the importing of SetEqualityConstraints
members as an alternative to mixing it in. One use case is to import SetEqualityConstraints
members so you can use them in the Scala interpreter.
Attributes
- Companion
- trait
- Source
- SetEqualityConstraints.scala
- Supertypes
- Self type
Size limit value class.
Size limit value class.
Attributes
- Source
- SizeLimit.scala
- Supertypes
-
trait Serializabletrait Producttrait Equalsclass Objecttrait Matchableclass AnyShow all
Case class that stores the name and value of a variable or expression.
Case class that stores the name and value of a variable or expression.
See the main documentation for trait Snapshots
for more information and examples.
Value parameters
- name
-
the name of the expression
- value
-
the value of the expression
Attributes
- Source
- Snapshots.scala
- Supertypes
-
trait Serializabletrait Producttrait Equalsclass Objecttrait Matchableclass AnyShow all
An IndexedSeq[Snapshot]
providing toString
and lines
methods that can be useful for debug and log messages about program state.
An IndexedSeq[Snapshot]
providing toString
and lines
methods that can be useful for debug and log messages about program state.
See the main documentation for trait Snapshots
for more information and examples.
Attributes
Attributes
- Companion
- class
- Source
- Snapshots.scala
- Supertypes
-
class Objecttrait Matchableclass Any
- Self type
-
SnapshotSeq.type
Trait that provides a snap
method that takes one or more arguments and results in a SnapshotSeq
, whose toString
lists the names and values of each argument.
Trait that provides a snap
method that takes one or more arguments and results in a SnapshotSeq
, whose toString
lists the names and values of each argument.
The intended use case of this trait is to help you write debug and log messages that give a "snapshot" of program state. Here's an example:
scala> import Snapshots._ import Snapshots._ scala> snap(a, b, c, d, e, f) res3: org.scalactic.SnapshotSeq = a was 1, b was 2, c was 3, d was 4, e was null, f was null
SnapshotSeq
offers a lines
method that places each variable name/value pair on its own line:
scala> snap(a, b, c, d, e, f).lines res4: String = a was 1 b was 2 c was 3 d was 4 e was null f was null
Or, because a SnapshotSeq
is a IndexedSeq[Snapshot]
, you can process it just like any other Seq
, for example:
scala> snap(a, b, c, d, e, f).mkString("Wow! ", ", and ", ". That's so awesome!") res6: String = Wow! a was 1, and b was 2, and c was 3, and d was 4, and e was null, and f was null. That's so awesome!
Attributes
- Companion
- object
- Source
- Snapshots.scala
- Supertypes
-
class Objecttrait Matchableclass Any
- Known subtypes
-
object Snapshots.type
Companion object that facilitates the importing of Snapshots
members as an alternative to mixing it in. One use case is to import Snapshots
members so you can use them in the Scala interpreter:
Companion object that facilitates the importing of Snapshots
members as an alternative to mixing it in. One use case is to import Snapshots
members so you can use them in the Scala interpreter:
$scala -classpath scalatest.jar Welcome to Scala 2.13.6 (OpenJDK 64-Bit Server VM, Java yyy). Type in expressions for evaluation. Or try :help. scala> import org.scalactic.Snapshots._ import org.scalatest.Snapshots._ scala> val a = 8 a: Int = 8 scala> snap(a) res0: scala.collection.immutable.Vector[org.scalactic.Snapshot] = Vector(a = 8)
Attributes
- Companion
- trait
- Source
- Snapshots.scala
- Supertypes
- Self type
-
Snapshots.type
Attributes
- Source
- Snapshots.scala
- Supertypes
-
class Objecttrait Matchableclass Any
- Self type
-
SnapshotsMacro.type
Provides methods that produce Uniformity[String]
instances for various ways to normalize strings for equality comparisons.
Provides methods that produce Uniformity[String]
instances for various ways to normalize strings for equality comparisons.
Attributes
- Companion
- object
- Source
- StringNormalizations.scala
- Supertypes
-
class Objecttrait Matchableclass Any
- Known subtypes
-
object StringNormalizations.type
Companion object to trait StringNormalizations
that provides an alternative to mixing it in.
Companion object to trait StringNormalizations
that provides an alternative to mixing it in.
Attributes
- Companion
- trait
- Source
- StringNormalizations.scala
- Supertypes
- Self type
-
StringNormalizations.type
Trait providing an implicit conversion that adds a times
method to Int
s that will repeat a given side-effecting operation multiple times.
Trait providing an implicit conversion that adds a times
method to Int
s that will repeat a given side-effecting operation multiple times.
Here's an example in which a friendly greeting is printed three times:
3 times println("Hello again, world!")
Running the above code would yield this output:
Hello again, world! Hello again, world! Hello again, world!
If you need to repeat a block of statements multiple times, just enclose them in parentheses, like this:
2 times { print("Hello ") print("again, ") println("world!") }
Running the above code would yield:
Hello again, world! Hello again, world!
This trait enables times
to be invoked on 0 and any positive integer, but attempting to invoke times
on a negative integer will result in an IllegalArgumentException
.
Attributes
- Companion
- object
- Source
- TimesOnInt.scala
- Supertypes
-
class Objecttrait Matchableclass Any
- Known subtypes
-
object TimesOnInt.type
Companion object that facilitates the importing of TimesOnInt
members as an alternative to mixing it in.
Companion object that facilitates the importing of TimesOnInt
members as an alternative to mixing it in.
One use case of this companion object is to import TimesOnInt
members so you can use them in the Scala interpreter. Here's an example:
scala> import org.scalatest.TimesOnInt._ import org.scalatest.TimesOnInt._ scala> 3 times println("Hello again, world!") Hello again, world! Hello again, world! Hello again, world!
Attributes
- Companion
- trait
- Source
- TimesOnInt.scala
- Supertypes
- Self type
-
TimesOnInt.type
Trait containing an implicit conversion that adds a +-
method to Numeric
types, which enables spreads to be expressed in terms of a pivot and tolerance.
Trait containing an implicit conversion that adds a +-
method to Numeric
types, which enables spreads to be expressed in terms of a pivot and tolerance.
For example, the TripleEquals
trait (and its type-checking siblings TypeCheckedTripleEquals
and ConversionCheckedTripleEquals
) enable you to write:
a === (1.0 +- 0.1)
Attributes
- Companion
- object
- Source
- Tolerance.scala
- Supertypes
-
class Objecttrait Matchableclass Any
- Known subtypes
-
object Tolerance.type
Companion object to trait Tolerance
that facilitates the importing of Tolerance
members as an alternative to mixing it in. One use case is to import Tolerance
members so you can use them in the Scala interpreter:
Companion object to trait Tolerance
that facilitates the importing of Tolerance
members as an alternative to mixing it in. One use case is to import Tolerance
members so you can use them in the Scala interpreter:
$ scala -classpath scalactic.jar Welcome to Scala 2.13.6 (OpenJDK 64-Bit Server VM, Java yyy). Type in expressions for evaluation. Or try :help. scala> import org.scalactic._ import org.scalactic._ scala> import Tolerance._ import Tolerance._ scala> 1.0 +- 0.1 res0: org.scalactic.TripleEqualsSupport.Spread[Double] = Spread(1.0,0.1)
Attributes
- Companion
- trait
- Source
- Tolerance.scala
- Supertypes
- Self type
-
Tolerance.type
Provides Equality
and Equivalence
instances for Numeric
types that compare for equality with a given tolerance.
Provides Equality
and Equivalence
instances for Numeric
types that compare for equality with a given tolerance.
Here's an example:
scala> import org.scalactic._ import org.scalactic._ scala> import TripleEquals._ import TripleEquals._ scala> 2.001 === 2.0 res0: Boolean = false scala> implicit val doubleEquality = TolerantNumerics.tolerantDoubleEquality(0.01) doubleEquality: org.scalactic.Equality[Double] = org.scalactic.TolerantNumerics$$anon$1@16c2bd13 scala> 2.001 === 2.0 res1: Boolean = true
Attributes
- Companion
- object
- Source
- TolerantNumerics.scala
- Supertypes
-
class Objecttrait Matchableclass Any
- Known subtypes
-
object TolerantNumerics.type
Companion object for TolerantNumerics
that enables its members to be imported as an alternative to mixing them in.
Companion object for TolerantNumerics
that enables its members to be imported as an alternative to mixing them in.
Attributes
- Companion
- trait
- Source
- TolerantNumerics.scala
- Supertypes
- Self type
-
TolerantNumerics.type
Provides three implicit methods that loosen the equality constraint defined by TypeCheckedTripleEquals
for Scala Traversable
s to one that more closely matches Scala's approach to Traversable
equality.
Provides three implicit methods that loosen the equality constraint defined by TypeCheckedTripleEquals
for Scala Traversable
s to one that more closely matches Scala's approach to Traversable
equality.
Scala's approach to Traversable
equality is that if the objects being compared are ether both Seq
s, both Set
s, or both Map
s, the elements are compared to determine equality. This means you could compare an immutable Vector
and a mutable ListBuffer
for equality, for instance, and get true so long as the two Seq
s contained the same elements in the same order. Here's an example:
scala> import scala.collection.mutable.ListBuffer import scala.collection.mutable.ListBuffer scala> Vector(1, 2) == ListBuffer(1, 2) res0: Boolean = true
Such a comparison would not, however, compile if you used ===
under TypeCheckedTripleEquals
, because Vector
and ListBuffer
are not in a subtype/supertype relationship:
scala> import org.scalactic._ import org.scalactic._ scala> import TypeCheckedTripleEquals._ import TypeCheckedTripleEquals._ scala> Vector(1, 2) === ListBuffer(1, 2) <console>:16: error: types scala.collection.immutable.Vector[Int] and scala.collection.mutable.ListBuffer[Int] do not adhere to the equality constraint selected for the === and !== operators; the missing implicit parameter is of type org.scalactic.CanEqual[scala.collection.immutable.Vector[Int], scala.collection.mutable.ListBuffer[Int]] Vector(1, 2) === ListBuffer(1, 2) ^
If you mix or import the implicit conversion provided by TraversableEqualityConstraint
, however, the comparison will be allowed:
scala> import TraversableEqualityConstraints._ import TraversableEqualityConstraints._ scala> Vector(1, 2) === ListBuffer(1, 2) res2: Boolean = true
The equality constraints provided by this trait require that left and right sides are both subclasses of either scala.collection.GenSeq
, scala.collection.GenSet
, or scala.collection.GenMap
, and that an CanEqual
can be found for the element types for Seq
and Set
, or the key and value types for Map
s. In the example above, both the Vector
and ListBuffer
are subclasses of scala.collection.GenSeq
, and the regular TypeCheckedTripleEquals
provides equality constraints for the element types, both of which are Int
. By contrast, this trait would not allow a Vector[Int]
to be compared against a ListBuffer[java.util.Date]
, because no equality constraint will exist between the element types Int
and Date
:
scala> import java.util.Date import java.util.Date scala> Vector(1, 2) === ListBuffer(new Date, new Date) <console>:20: error: types scala.collection.immutable.Vector[Int] and scala.collection.mutable.ListBuffer[java.util.Date] do not adhere to the equality constraint selected for the === and !== operators; the missing implicit parameter is of type org.scalactic.CanEqual[scala.collection.immutable.Vector[Int], scala.collection.mutable.ListBuffer[java.util.Date]] Vector(1, 2) === ListBuffer(new Date, new Date) ^
This trait simply mixes together SeqEqualityConstraints
, SetEqualityConstraints
, and MapEqualityConstraints
.
Attributes
- Companion
- object
- Source
- TraversableEqualityConstraints.scala
- Supertypes
-
trait MapEqualityConstraintstrait SetEqualityConstraintstrait SeqEqualityConstraintsclass Objecttrait Matchableclass AnyShow all
- Known subtypes
-
object TraversableEqualityConstraints.type
Companion object that facilitates the importing of TraversableEqualityConstraints
members as an alternative to mixing it in. One use case is to import TraversableEqualityConstraints
members so you can use them in the Scala interpreter.
Companion object that facilitates the importing of TraversableEqualityConstraints
members as an alternative to mixing it in. One use case is to import TraversableEqualityConstraints
members so you can use them in the Scala interpreter.
Attributes
- Companion
- trait
- Source
- TraversableEqualityConstraints.scala
- Supertypes
-
trait MapEqualityConstraintstrait SetEqualityConstraintstrait SeqEqualityConstraintsclass Objecttrait Matchableclass AnyShow all
- Self type
Provides ===
and !==
operators that return Boolean
, delegate the equality determination to an Equality
type class, and require no relationship between the types of the two values compared.
Provides ===
and !==
operators that return Boolean
, delegate the equality determination to an Equality
type class, and require no relationship between the types of the two values compared.
Recommended Usage: Trait TripleEquals is useful (in both production and test code) when you need determine equality for a type of object differently than its equals method: either you can't change the equals method, or the equals method is sensible generally, but you are in a special situation where you need something else. You can use the SuperSafe Community Edition compiler plugin to get a compile-time safety check of types being compared with === . In situations where you need a stricter type check, you can use TypeCheckedTripleEquals . |
This trait will override or hide implicit methods defined by its sibling trait, TypeCheckedTripleEquals
, and can therefore be used to temporarily turn of type checking in a limited scope. Here's an example, in which TypeCheckedTripleEquals
will cause a compiler error:
import org.scalactic._ import TypeCheckedTripleEquals._ object Example { def cmp(a: Int, b: Long): Int = { if (a === b) 0 // This line won't compile else if (a < b) -1 else 1 } def cmp(s: String, t: String): Int = { if (s === t) 0 else if (s < t) -1 else 1 } }
Because Int
and Long
are not in a subtype/supertype relationship, comparing 1
and 1L
in the context of TypeCheckedTripleEquals
will generate a compiler error:
Example.scala:9: error: types Int and Long do not adhere to the equality constraint selected for the === and !== operators; they must either be in a subtype/supertype relationship; the missing implicit parameter is of type org.scalactic.Constraint[Int,Long] if (a === b) 0 // This line won't compile ^ one error found
You can “turn off” the type checking locally by importing the members of TripleEquals
in a limited scope:
package org.scalactic.examples.tripleequals import org.scalactic._ import TypeCheckedTripleEquals._ object Example { def cmp(a: Int, b: Long): Int = { import TripleEquals._ if (a === b) 0 else if (a < b) -1 else 1 } def cmp(s: String, t: String): Int = { if (s === t) 0 else if (s < t) -1 else 1 } }
With the above change, the Example.scala
file compiles fine. Type checking is turned off only inside the first cmp
method that takes an Int
and a Long
. TypeCheckedTripleEquals
is still enforcing its type constraint, for example, for the s === t
expression in the other overloaded cmp
method that takes strings.
Because the methods in TripleEquals
(and its siblings)override all the methods defined in supertype TripleEqualsSupport
, you can achieve the same kind of nested tuning of equality constraints whether you mix in traits, import from companion objects, or use some combination of both.
In short, you should be able to select a primary constraint level via either a mixin or import, then change that in nested scopes however you want, again either through a mixin or import, without getting any implicit conversion ambiguity. The innermost constraint level in scope will always be in force.
Attributes
- Companion
- object
- Source
- TripleEquals.scala
- Supertypes
- Known subtypes
-
object TripleEquals.type
Companion object to trait TripleEquals
that facilitates the importing of TripleEquals
members as an alternative to mixing it in. One use case is to import TripleEquals
members so you can use them in the Scala interpreter:
Companion object to trait TripleEquals
that facilitates the importing of TripleEquals
members as an alternative to mixing it in. One use case is to import TripleEquals
members so you can use them in the Scala interpreter:
$ scala -classpath scalatest.jar Welcome to Scala 2.13.6 (OpenJDK 64-Bit Server VM, Java yyy). Type in expressions for evaluation. Or try :help. scala> import org.scalactic._ import org.scalactic._ scala> import TripleEquals._ import TripleEquals._ scala> 1 + 1 === 2 res0: Boolean = true
Attributes
- Companion
- trait
- Source
- TripleEquals.scala
- Supertypes
- Self type
-
TripleEquals.type
Trait that defines abstract methods used to enforce compile-time type constraints for equality comparisons, and defines ===
and !==
operators used by matchers.
Trait that defines abstract methods used to enforce compile-time type constraints for equality comparisons, and defines ===
and !==
operators used by matchers.
The abstract methods of this trait are selectively implemented as implicit by subclasses to enable a spectrum of type constraints for the ===
and !==
operators. As an illustration, if in the expression, a === b
, the type of a
is A
and b
is B
, the following three levels of compile-time checking can be obtained from TripleEqualsSupport
subtraits:
Unchecked - A
and B
can be any two types. This constraint level is available from subtrait TripleEquals
.
Statically-checked - A
must be a subtype of B
, or vice versa, or must cooperate such that the equality laws stated in the equals
contract are preserved. This (intermediate) constraint level is available by using subtrait TripleEquals
and installing the SuperSafe Community Edition Scala compiler plugin.
Type-checked - A
must be a subtype of B
, or vice versa. (Both A
and B
can be the same type, because a type is considered a subtype of itself.) This (strongest) constraint level is available from subtrait TypeCheckedTripleEquals
.
This trait defines all methods that need to be defined implicitly by the subtraits so that if multiple subtraits are used together, the inner-most subtrait in scope can not only enable the implicits it needs by overriding or hiding those methods (currently-in-scope as regular, non-implicit methods) and making them implicit, it can also disable any implicits enabled by its sibling subtraits in enclosing scopes. For example, if your test class mixes in TypeCheckedTripleEquals
, inside your test class the following methods will be implicit:
-
convertToCheckingEqualizer
-
typeCheckedConstraint
-
lowPriorityTypeCheckedConstraint
-
convertEquivalenceToAToBConstraint
-
convertEquivalenceToBToAConstraint
If in the body of a test you want to turn off the type checking, you can import the members of TripleEquals
in the body of that test. This will not only hide non-implicit methods convertToEqualizer
unconstrainedEquality
of TypeCheckedTripleEquals
, replacing those with implicit ones defined in TripleEquals
, it will also hide the three methods made implicit in TypeCheckedTripleEquals
(and listed above), replacing them by non-implicit ones.
In short, you should be able to select a primary constraint level via either a mixin or import, then change that in nested scopes however you want, again either through a mixin or import, without getting any implicit conversion ambiguity. The innermost constraint level in scope will always be in force.
Attributes
- Companion
- object
- Source
- TripleEqualsSupport.scala
- Supertypes
-
class Objecttrait Matchableclass Any
- Known subtypes
-
trait TypeCheckedTripleEqualsobject TypeCheckedTripleEquals.typetrait TripleEqualsobject TripleEquals.type
Attributes
- Companion
- trait
- Source
- TripleEqualsSupport.scala
- Supertypes
-
class Objecttrait Matchableclass Any
- Self type
-
TripleEqualsSupport.type
Trait providing an implicit class that adds a toOr
method to Try
, which converts Success
to Good
, and Failure
to Bad
, as well as a validating
method, which takes one or more validation functions and returns either the same Try
if either the Try
had already failed or its value passes all the functions, or `ValidationFailedException` containing an error message describing the first validation that failed.
Trait providing an implicit class that adds a toOr
method to Try
, which converts Success
to Good
, and Failure
to Bad
, as well as a validating
method, which takes one or more validation functions and returns either the same Try
if either the Try
had already failed or its value passes all the functions, or `ValidationFailedException` containing an error message describing the first validation that failed.
Here's an example validation method, which passes if the given Int
is evenly divisible by 10 (i.e., the result will be <code>Pass</code>). If the value does not pass this test, the result is a <code>Fail</code> containing a helpful error message string.
scala> import org.scalactic._ import org.scalactic._ scala> import TrySugar._ import TrySugar._ scala> import scala.util.Try import scala.util.Try scala> def isRound(i: Int): Validation[ErrorMessage] = | if (i % 10 == 0) Pass else Fail(i + " was not a round number") isRound: (i: Int)org.scalactic.Validation[org.scalactic.ErrorMessage]
Validation will be attempted on a successful Try
. If the validation succeeds, the resulting Try
will be the same successful Try
with the same value. (A "validation" only transforms the Try
if the validation fails, otherwise it is the same Try
. The only difference is its value has now been proven valid.) In the following example, a successful Try[Int]
with the value 100 passes the validation (which checks whether 100 is evenly divisible by 10), therefore the result of the validating
call is the same successful Try
with the same value.
scala> val try100 = Try(100) try100: scala.util.Try[Int] = Success(100) scala> val round100 = try100.validating(isRound) round100: scala.util.Try[Int] = Success(100)
If validation fails, the successful Try
will be transformed into a failed one, with a ValidationFailedException
that contains the error message returned by the validation function. In the following example, 42 fails the validation because it is not evenly divisible by 10:
scala> val try42 = Try(42) try42: scala.util.Try[Int] = Success(42) scala> val round42 = try42.validating(isRound) round42: scala.util.Try[Int] = Failure(org.scalactic.exceptions.ValidationFailedException: 42 was not a round number)
If validating
is called on a failed Try
, it just returns the same failed Try
:
scala> val tryEx = Try[Int] { throw new Exception("oops!") } tryEx: scala.util.Try[Int] = Failure(java.lang.Exception: oops!) scala> val roundEx = tryEx.validating(isRound) roundEx: scala.util.Try[Int] = Failure(java.lang.Exception: oops!)
The validating
method accepts one or more validation functions. If you pass more than one, they will be tried in order up until the first failure, whose error message will appear in the ValidationFailedException
. In other words, validating
will short circuit at the first error and return that. It will not accumulate errors. For example, the following validation will short circuit after the isDivBy3
function fails:
scala> def isDivBy3(i: Int): Validation[ErrorMessage] = | if (i % 3 == 0) Pass else Fail(i + " was not divisible by 3") isDivBy3: (i: Int)org.scalactic.Validation[org.scalactic.ErrorMessage] scala> def isAnswerToLifeTheUniverseAndEverything(i: Int): Validation[ErrorMessage] = | if (i == 42) Pass else Fail(i + " did not equal 42") isAnswerToLifeTheUniverseAndEverything: (i: Int)org.scalactic.Validation[org.scalactic.ErrorMessage] scala> try100.validating(isRound, isDivBy3, isAnswerToLifeTheUniverseAndEverything) res0: scala.util.Try[Int] = Failure(org.scalactic.exceptions.ValidationFailedException: 100 was not divisible by 3)
Here are some examples of the toOr
method:
scala> try100.toOr res1: org.scalactic.Or[Int,Throwable] = Good(100) scala> tryEx.toOr res2: org.scalactic.Or[Int,Throwable] = Bad(java.lang.Exception: oops!)
Attributes
- Companion
- object
- Source
- TrySugar.scala
- Supertypes
-
class Objecttrait Matchableclass Any
- Known subtypes
-
object TrySugar.type
Companion object for TrySugar
enabling its members to be imported as an alternative to mixing them in.
Companion object for TrySugar
enabling its members to be imported as an alternative to mixing them in.
Attributes
- Companion
- trait
- Source
- TrySugar.scala
- Supertypes
- Self type
-
TrySugar.type
Provides ===
and !==
operators that return Boolean
, delegate the equality determination to an Equality
type class, and require the types of the two values compared to be in a subtype/supertype relationship.
Provides ===
and !==
operators that return Boolean
, delegate the equality determination to an Equality
type class, and require the types of the two values compared to be in a subtype/supertype relationship.
Recommended Usage: Trait TypeCheckedTripleEquals is useful (in both production and test code) when you need a stricter type check than is provided by the SuperSafe Community Edition compiler plugin for TripleEquals . For example, if you are developing a library that uses advanced features of Scala's type system, you may want to enforce in your tests that the types appearing in equality comparisons match exactly. |
By default under TripleEquals
, any use of ===
will compile, just like the ==
operator:
scala> import org.scalactic._ import org.scalactic._ scala> import TripleEquals._ import TripleEquals._ scala> 1L === 1 // A Long can equal an Int res0: Boolean = true scala> List(1, 2, 3) === Vector(1, 2, 3) // A List can equal a Vector res1: Boolean = true scala> "hi" === 1 // Likely a bug, because a String can never equal an Int res2: Boolean = false
With SuperSafe Community Edition installed, the first two expressions above will be allowed to compile, but the third (which represents a likely bug) will not:
scala> import org.scalactic._ import org.scalactic._ scala> import TripleEquals._ import TripleEquals._ scala> 1L === 1 res0: Boolean = true scala> List(1, 2, 3) === Vector(1, 2, 3) res1: Boolean = true scala> "hi" === 1 // SuperSafe catches the bug at compile time <console>:17: error: [Artima SuperSafe] Values of type String and Int may not be compared with the === operator. If you really want to compare them for equality, configure Artima SuperSafe to allow those types to be compared for equality. For more information on this kind of error, see: http://www.artima.com/supersafe_user_guide.html#safer-equality "hi" === 1 ^
By contrast, TypeCheckedTripleEquals
will prevent any of the above three expressions from compiling:
scala> import org.scalactic._ import org.scalactic._ scala> import TypeCheckedTripleEquals._ import TypeCheckedTripleEquals._ scala> 1L === 1 <console>:17: error: types Long and Int do not adhere to the type constraint selected for the === and !== operators; the missing implicit parameter is of type org.scalactic.CanEqual[Long,Int] 1L === 1 ^ scala> List(1, 2, 3) === Vector(1, 2, 3) <console>:17: error: types List[Int] and scala.collection.immutable.Vector[Int] do not adhere to the type constraint selected for the === and !== operators; the missing implicit parameter is of type org.scalactic.CanEqual[List[Int],scala.collection.immutable.Vector[Int]] List(1, 2, 3) === Vector(1, 2, 3) ^ scala> "hi" === 1 <console>:17: error: types String and Int do not adhere to the type constraint selected for the === and !== operators; the missing implicit parameter is of type org.scalactic.CanEqual[String,Int] "hi" === 1 ^
Trait TypeCheckedTripleEquals
rejects comparisons of types Int
and Long
, List[Int]
and Vector[Int]
, and String
and Int
, because none have a direct subtype/supertype relationship. To compare two types that are unrelated by inheritance under TypeCheckedTripleEquals
, you could convert one of them to the other type (because a type is both a subtype and supertype of itself). Here's an example:
scala> 1L === 1.toLong // Now both sides are Long res0: Boolean = true scala> List(1, 2, 3) === Vector(1, 2, 3).toList // Now both sides are List[Int] res1: Boolean = true
Nevertheless, a better (and the recommended) way to deal with this situation is to use a widening type ascription. A type ascription is simply a colon and a type placed next to a variable, usually surrounded by parentheses. For example, because AnyVal
is a common supertype of Int
and Long
, you could solve the type error by widening the type of one side or the other to AnyVal
. Because AnyVal
is a supertype of both Int
and Long
, the type constraint will be satisfied:
scala> 1 === (1L: AnyVal) res2: Boolean = true scala> (1: AnyVal) === 1L res3: Boolean = true
Similarly, since Seq[Int]
is a common supertype of both Vector[Int]
and List[Int]
, the type constraint can be satisfied by widening either to their common supertype, Seq[Int]
:
scala> List(1, 2, 3) === (Vector(1, 2, 3): Seq[Int]) res4: Boolean = true scala> (List(1, 2, 3): Seq[Int]) === Vector(1, 2, 3) res5: Boolean = true
The primary intended use case for TypeCheckedTripleEquals
is to enable tests to be very strict about which types can compared for equality, but it can also be used with production code where this level of strictness is desired.
== Forcing implicit conversions before equality checks ==
You can also use a type ascription to force an implicit conversion before a value participates in an equality comparison. For example, although JavaConversions
provides an implicit conversion between java.util.Set
and scala.collection.mutable.Set
, under TypeCheckedTripleEquals
an equality comparison between those two types will not be allowed:
scala> import collection.JavaConversions._ import collection.JavaConversions._ scala> import collection.mutable import collection.mutable scala> import TypeCheckedTripleEquals._ import TypeCheckedTripleEquals._ scala> mutable.Set.empty[String] === new java.util.HashSet[String] <console>:36: error: types scala.collection.mutable.Set[String] and java.util.HashSet[String] do not adhere to the type constraint selected for the === and !== operators; the missing implicit parameter is of type org.scalactic.CanEqual[scala.collection.mutable.Set[String],java.util.HashSet[String]] mutable.Set.empty[String] === new java.util.HashSet[String] ^
To force an implicit conversion of the Java HashSet
to a Scala mutable.Set
, after which the type constraint will be satisfied, you can use a type ascription:
scala> mutable.Set.empty[String] === (new java.util.HashSet[String]: mutable.Set[String]) res0: Boolean = true
== Scoping equality policies ==
This trait will override or hide implicit methods defined by TripleEquals
and can therefore be used to temporarily turn on or off type checking in a limited scope. Here's an example, in which TypeCheckedTripleEquals
will cause a compiler error:
import org.scalactic._ import TypeCheckedTripleEquals._ object Example { def cmp(a: Int, b: Long): Int = { if (a === b) 0 // This line won't compile else if (a < b) -1 else 1 } def cmp(s: String, t: String): Int = { if (s === t) 0 else if (s < t) -1 else 1 } }
Because Int
and Long
are not in a subtype/supertype relationship, comparing 1
and 1L
in the context of TypeCheckedTripleEquals
will generate a compiler error:
Example.scala:9: error: types Int and Long do not adhere to the type constraint selected for the === and !== operators; the missing implicit parameter is of type org.scalactic.CanEqual[Int,Long] if (a === b) 0 // This line won't compile ^ one error found
You can “relax” the type checking locally by importing the members of TripleEquals
in a limited scope:
package org.scalactic.examples.conversioncheckedtripleequals import org.scalactic._ import TypeCheckedTripleEquals._ object Example { def cmp(a: Int, b: Long): Int = { import TripleEquals._ if (a === b) 0 else if (a < b) -1 else 1 } def cmp(s: String, t: String): Int = { if (s === t) 0 else if (s < t) -1 else 1 } }
With the above change, the Example.scala
file compiles fine. The strict checking is disabled only inside the first cmp
method that takes an Int
and a Long
. TypeCheckedTripleEquals
is still enforcing its type constraint, for example, for the s === t
expression in the other overloaded cmp
method that takes strings.
Because the methods TripleEquals
and TypeCheckedTripleEquals
override all the methods defined in supertype TripleEqualsSupport
, you can achieve the same kind of nested tuning of equality constraints whether you mix in traits, import from companion objects, or use some combination of both.
In short, you should be able to select a primary constraint level via either a mixin or import, then change that in nested scopes however you want, again either through a mixin or import, without getting any implicit conversion ambiguity. The innermost constraint level in scope will always be in force.
Attributes
- Companion
- object
- Source
- TypeCheckedTripleEquals.scala
- Supertypes
- Known subtypes
-
object TypeCheckedTripleEquals.type
Companion object to trait TypeCheckedTripleEquals
that facilitates the importing of TypeCheckedTripleEquals
members as an alternative to mixing it in. One use case is to import TypeCheckedTripleEquals
members so you can use them in the Scala interpreter:
Companion object to trait TypeCheckedTripleEquals
that facilitates the importing of TypeCheckedTripleEquals
members as an alternative to mixing it in. One use case is to import TypeCheckedTripleEquals
members so you can use them in the Scala interpreter:
$ scala -classpath scalatest.jar Welcome to Scala 2.13.6 (OpenJDK 64-Bit Server VM, Java yyy). Type in expressions for evaluation. Or try :help. scala> import org.scalactic._ import org.scalactic._ scala> import TypeCheckedTripleEquals._ import TypeCheckedTripleEquals._ scala> 1 + 1 === 2 res0: Boolean = true
Attributes
- Companion
- trait
- Source
- TypeCheckedTripleEquals.scala
- Supertypes
-
trait TypeCheckedTripleEqualstrait TripleEqualsSupportclass Objecttrait Matchableclass AnyShow all
- Self type
Defines a custom way to normalize instances of a type that can also handle normalization of that type when passed as Any
.
Defines a custom way to normalize instances of a type that can also handle normalization of that type when passed as Any
.
For example, to normalize Double
s by truncating off any decimal part, you might write:
import org.scalactic._ val truncated = new Uniformity[Double] { def normalized(d: Double) = d.floor def normalizedCanHandle(o: Any) = o.isInstanceOf[Double] def normalizedOrSame(o: Any): Any = o match { case d: Double => normalized(d) case _ => o } }
Given this definition you could use it with the Explicitly
DSL like this:
import org.scalatest._ import Matchers._ 2.1 should equal (2.0) (after being truncated)
If you make the truncated
val
implicit and import or mix in the members of NormMethods
, you can access the behavior by invoking .norm
on Double
s.
implicit val doubleUniformity = truncated import NormMethods._ val d = 2.1 d.norm // returns 2.0
Note that by creating a Uniformity
rather than just an instance of its supertype, Normalization
, it can be used more generally. For example, Uniformity
s allow you to the Explicitly
DSL with TripleEquals
, whereas Normalization
s require TypeCheckedTripleEquals
. Uniformity
s also enable you to use the Explicitly
DSL with ScalaTest's should
===
, equal
, and contain
matcher syntax, whereas a plain Normalization
can only be used with should
===
, and only under TypeCheckedTripleEquals
.
Type parameters
- A
-
the type whose uniformity is being defined
Attributes
- Source
- Uniformity.scala
- Supertypes
- Known subtypes
-
trait AbstractStringUniformity
- Self type
-
Uniformity[A]
Represents the result of a validation, either the object Pass
if the validation succeeded, else an instance of Fail
containing an error value describing the validation failure.
Represents the result of a validation, either the object Pass
if the validation succeeded, else an instance of Fail
containing an error value describing the validation failure.
Validation
s are used to filter Or
s in for
expressions or filter
method calls. For example, consider these methods:
import org.scalactic._ def isRound(i: Int): Validation[ErrorMessage] = if (i % 10 == 0) Pass else Fail(i + " was not a round number") def isDivBy3(i: Int): Validation[ErrorMessage] = if (i % 3 == 0) Pass else Fail(i + " was not divisible by 3")
Because isRound
and isDivBy3
take an Int
and return a Validation[ErrorMessage]
, you can use them in filters in for
expressions involving Or
s of type Int
Or
ErrorMessage
. Here's an example:
for (i <- Good(3) if isRound(i) && isDivBy3(i)) yield i // Result: Bad(3 was not a round number)
Validation
s can also be used to accumulate error using when
, a method that's made available by trait Accumulation
on accumualting Or
s (Or
s whose Bad
type is an Every[T]
). Here are some examples:
import Accumulation._ for (i <- Good(3) when (isRound, isDivBy3)) yield i // Result: Bad(One(3 was not a round number)) for (i <- Good(4) when (isRound, isDivBy3)) yield i // Result: Bad(Many(4 was not a round number, 4 was not divisible by 3))
Note: You can think of Validation
as an “Option
with attitude,” where Pass
is a None
that indicates validation success and Fail
is a Some
whose value describes the validation failure.
Type parameters
- E
-
the type of error value describing a validation failure for this
Validation
Attributes
- Source
- Validation.scala
- Supertypes
-
trait Serializabletrait Producttrait Equalsclass Objecttrait Matchableclass AnyShow all
- Known subtypes
Types
Type alias for String
.
Deprecated types
The name org.scalactic.Chain
has been deprecated and will be removed in a future version of Scalactic. Please use its new name, org.scalatest.anyvals.NonEmptyList
, instead.
The name org.scalactic.Chain
has been deprecated and will be removed in a future version of Scalactic. Please use its new name, org.scalatest.anyvals.NonEmptyList
, instead.
This type has been renamed for consistency with other 'NonEmpty
' anyvals.
Attributes
- Deprecated
- true
- Source
- package.scala
Value members
Concrete methods
Returns the result of evaluating the given block f
, wrapped in a Good
, or if an exception is thrown, the Throwable
, wrapped in a Bad
.
Returns the result of evaluating the given block f
, wrapped in a Good
, or if an exception is thrown, the Throwable
, wrapped in a Bad
.
Here are some examples:
scala> import org.scalactic._ import org.scalactic._ scala> attempt { 2 / 1 } res0: org.scalactic.Or[Int,Throwable] = Good(2) scala> attempt { 2 / 0 } res1: org.scalactic.Or[Int,Throwable] = Bad(java.lang.ArithmeticException: / by zero)
Value parameters
- f
-
the block to attempt to evaluate
Attributes
- Returns
-
the result of evaluating the block, wrapped in a
Good
, or the thrown exception, wrapped in aBad
- Source
- package.scala
Concrete fields
The version number of Scalactic.
The version number of Scalactic.
Attributes
- Returns
-
the Scalactic version number.
- Source
- package.scala
Deprecated fields
The name org.scalactic.Chain
has been deprecated and will be removed in a future version of Scalactic. Please use its new name, org.scalatest.anyvals.NonEmptyList
, instead.
The name org.scalactic.Chain
has been deprecated and will be removed in a future version of Scalactic. Please use its new name, org.scalatest.anyvals.NonEmptyList
, instead.
This type has been renamed for consistency with other 'NonEmpty
' anyvals.
Attributes
- Deprecated
- true
- Source
- package.scala
The name org.scalactic.End
has been deprecated and will be removed in a future version of Scalactic. Please use its new name, org.scalatest.anyvals.End
, instead.
The name org.scalactic.End
has been deprecated and will be removed in a future version of Scalactic. Please use its new name, org.scalatest.anyvals.End
, instead.
This type has been renamed for consistency with other 'NonEmpty
' anyvals.
Attributes
- Deprecated
- true
- Source
- package.scala