Skip to content

Commit

Permalink
use the Diffable typeclass as an equality typeclass
Browse files Browse the repository at this point in the history
  • Loading branch information
etorreborre committed Jan 30, 2017
1 parent 7dbaa19 commit 699fb51
Show file tree
Hide file tree
Showing 8 changed files with 154 additions and 113 deletions.
8 changes: 4 additions & 4 deletions matcher/src/main/scala/org/specs2/matcher/AnyMatchers.scala
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,12 @@ trait AnyBaseMatchers {
/** matches if a == b */
def equalTo[T](t: =>T) = beEqualTo(t)
/** matches if a == b */
def beTypedEqualTo[T : Diffable](t: =>T, equality: (T, T) => Boolean = (t1:T, t2:T) => t1 == t2) =
new EqualityMatcher(t, equality)
def beTypedEqualTo[T : Diffable](t: =>T) =
new EqualityMatcher(t)

/** matches if a == b */
def typedEqualTo[T](t: =>T, equality: (T, T) => Boolean = (t1:T, t2:T) => t1 == t2) =
beTypedEqualTo(t, equality)
def typedEqualTo[T](t: =>T) =
beTypedEqualTo(t)

/** matches if a == b after an implicit conversion */
def be_==~[T : Diffable, S](s: =>S)(implicit convert: S => T): Matcher[T] = new EqualityMatcher(convert(s)).
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,4 @@ import org.specs2.matcher.describe.Diffable
/**
* Typed equality Matcher with fallback comparison results
*/
class BeTypedEqualTo[T](t: =>T, equality: (T, T) => Boolean = (t1:T, t2:T) => t1 == t2) extends
EqualityMatcher[T](t, equality)(Diffable.fallbackDiffable)
class BeTypedEqualTo[T](t: =>T) extends EqualityMatcher[T](t)(Diffable.fallbackDiffable)
26 changes: 5 additions & 21 deletions matcher/src/main/scala/org/specs2/matcher/EqualityMatcher.scala
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@ import org.specs2.text.NotNullStrings._

import scala.collection.{GenTraversable, GenTraversableOnce}

class EqualityMatcher[T : Diffable](t: =>T, equality: (T, T) => Boolean = (t1:T, t2:T) => t1 == t2) extends AdaptableMatcher[T] { outer =>
class EqualityMatcher[T : Diffable](t: =>T) extends AdaptableMatcher[T] { outer =>

protected val ok: String => String = identity
protected val ko: String => String = identity

def adapt(f: T => T, okFunction: String => String, koFunction: String => String) = {
new EqualityMatcher(f(t), equality) {
new EqualityMatcher(f(t)) {
override def apply[S <: T](s: Expectable[S]): MatchResult[S] = {
val originalValues = s"\nOriginal values\n Expected: '$t'\n Actual : '${s.value}'"
result(super.apply(s.map(f)).updateMessage(_ + originalValues), s)
Expand All @@ -23,39 +23,23 @@ class EqualityMatcher[T : Diffable](t: =>T, equality: (T, T) => Boolean = (t1:T,
}
}

/**
* we perform 2 kinds of check, depending on the elements to compare
*
* - unordered sequences (maps, sets) are being compared with a matching algorithm
* - arrays are being compared with the deep equality and a matching algorithm is used for missing elements
* - sequences are being compared with the regular equality and a matching algorithm is used for missing elements
* - other objects are being compared using the regular equality
*
* @return a MatchResult describing the outcome of the match
*/
def apply[S <: T](b: Expectable[S]): MatchResult[S] = {
val (actual, expected) = (b.value, t)
val isEqual = checkEquality(actual, expected)
val diff = Diffable.diff(actual, expected)

failureDetailsFor(actual, expected) match {
case Some(failureDetail) =>
result(isEqual,
result(diff.identical,
ok(s"${b.description} == '${expected.notNull}'"),
ko(b.describe(diff.render)), b, failureDetail)

case None =>
result(isEqual,
result(diff.identical,
ok(s"${b.description} == '${expected.notNull}'"),
ko(b.describe(diff.render)), b, expected.notNull, actual.notNull)
}
}

private def checkEquality(actual: Any, expected: Any): Boolean =
(actual, expected) match {
case (e1: Array[_], e2: Array[_]) => e1.deep == e2.deep
case (e1, e2) => e1 == e2
}

private def failureDetailsFor(actual: Any, expected: Any): Option[Details] =
(actual, expected) match {
case (e1: Map[_, _], e2: Map[_, _]) => Some( FailureMapDetails(e1.toMap[Any, Any], e2.toMap[Any, Any]) )
Expand Down
Loading

0 comments on commit 699fb51

Please sign in to comment.