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

org.scalautils.Equality.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.scalautils

/**
 * Defines a custom way to determine equality for a type.
 *
 * 

* 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.scalautils._
 * import org.scalautils._
 *
 * 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 Doubles 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.scalautils.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

* *

* ScalaUtils 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
 *   }
 * 
* * Note: The Equality type class was inspired in part by the Equal type class of the * scalaz project. *

* * @tparam A the type whose equality is being customized */ trait Equality[A] extends Equivalence[A] { /* *

* The equals method of java.lang.Object and areEqual method of trait Equality have a similar * signatures and behavior, and you write them in a similar way. * When using TypeCheckedTripleEquals or * ConversionCheckedTripleEquals, however, *

* */ /** * Indicates whether the objects passed as a and b are equal. * * @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 Equality instance */ def areEqual(a: A, b: Any): Boolean final def areEquivalent(a: A, b: A): Boolean = areEqual(a, b) } object Equality { def apply[A](uniformity: Uniformity[A]): Equality[A] = { new NormalizingEquality[A] { def normalized(a: A): A = uniformity.normalized(a) def normalizedCanHandle(b: Any): Boolean = uniformity.normalizedCanHandle(b) def normalizedOrSame(b: Any): Any = uniformity.normalizedOrSame(b) } } /** * A default Equality implementation (which can be used for any type) whose * areEqual method first calls .deep on any array (on either the left or right side), * then compares the resulting objects with ==. */ implicit def default[A]: Equality[A] = new DefaultEquality[A] }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy