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

org.scalactic.Equivalence.scala Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2001-2013 Artima, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.scalactic

/**
 * 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 Equalitys, 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 Doubles 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
 * 
* */ trait Equivalence[T] { /** * Indicates whether the objects passed as a and b are equal. * *

* Note: this areEquivalent method means essentially the same thing as the areEqual method * of trait Equality, the difference only being the static type of the * right-hand value. This method is named areEquivalent instead * of areEqual so that it can be implemented in terms of areEqual in trait * Equality (which extends Equivalence). *

* * @param a a left-hand-side object being compared with another (right-hand-side one) for equality (e.g., a == b) * @param b a right-hand-side object being compared with another (left-hand-side one) for equality (e.g., a == b) * @return true if the passed objects are "equal," as defined by this Equivalence instance */ def areEquivalent(a: T, b: T): Boolean } /** * Companion object for trait Equivalence that provides a factory method for producing * default Equivalence instances. */ object Equivalence { /** * Provides default Equivalence implementations for the specified type whose * areEqual method first calls .deep on any Array (on either the left or right side), * then compares the resulting objects with ==. * * @return a default Equivalence[T] */ implicit def default[T]: Equivalence[T] = Equality.default[T] }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy