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

org.specs2.matcher.AnyMatchers.scala Maven / Gradle / Ivy

package org.specs2
package matcher

import text.Quote._
import scala.reflect.ClassTag

/**
 * This trait provides matchers which are applicable to any type of value
 */
trait AnyMatchers extends AnyBaseMatchers with AnyBeHaveMatchers
object AnyMatchers extends AnyMatchers

private[specs2]
trait AnyBaseMatchers {

  /** matches if a == true */
  def beTrue = new BeTrueMatcher
  /** matches if a == false */
  def beFalse = (new BeTrueMatcher).not

  /** matches if a eq b */
  def beTheSameAs[T <: AnyRef](t: =>T) = new BeTheSameAs(t)
  /** alias for beTheSameAs */
  def be[T <: AnyRef](t: =>T) = beTheSameAs(t)

  /** matches if a == b */
  def be_==[T](t: =>T) = beEqualTo(t)
  /** matches if a != b */
  def be_!=[T](t: =>T) = be_==(t).not
  /** matches if a == b */
  def be_===[T](t: =>T) = beTypedEqualTo(t)
  /** matches if a == b */
  def ===[T](t: =>T) = be_===(t)
  /** matches if a != b */
  def be_!==[T](t: =>T) = be_===(t).not
  /** matches if a != b */
  def !==[T](t: =>T) = be_!==(t)
  /** matches if a == b */
  def beEqualTo[T](t: =>T) = new BeEqualTo(t)
  /** matches if a == b */
  def equalTo[T](t: =>T) = beEqualTo(t)
  /** matches if a == b */
  def beTypedEqualTo[T](t: =>T, equality: (T, T) => Boolean = (t1:T, t2:T) => t1 == t2) =
    new BeTypedEqualTo(t, equality)
  /** matches if a == b */
  def typedEqualTo[T](t: =>T, equality: (T, T) => Boolean = (t1:T, t2:T) => t1 == t2) =
    beTypedEqualTo(t, equality)
  /** matches if a == b after an implicit conversion */
  def be_==~[T, S](s: =>S)(implicit convert: S => T): Matcher[T] = new BeTypedEqualTo(convert(s)).
    adapt(identity, identity, identity)
  /** matches if a == b after an implicit conversion */
  def ==~[T, S](s: =>S)(implicit convert: S => T): Matcher[T] = be_==~(s)(convert)

  /** negate a matcher */
  def not[T](m: Matcher[T]) = m.not
  
  /** matches if a.isEmpty */
  def beEmpty[T <% Any { def isEmpty: Boolean }] = new Matcher[T] {
    def apply[S <: T](iterable: Expectable[S]) = {
      result(iterable.value.isEmpty,
             iterable.description + " is empty", 
             iterable.description + " is not empty", iterable)
    }
  }

  /** matches if the value is null */
  def beNull[T] = new BeNull[T]

  /** matches if a is null when v is null and a is not null when v is not null */
  def beAsNullAs[T](a: =>T) = new Matcher[T](){
    def apply[S <: T](y: Expectable[S]) = {
      val x = a
      result(x == null && y.value == null || x != null && y.value != null,
             "both values are null",
             if (x == null) y.description + " is not null" else q(x) + " is not null" + 
             y.optionalDescription.map(" but " + _ + " is null").getOrElse(""), 
             y)
    }
  }

  /** matches if t.toSeq.exists(_ == v) */
  def beOneOf[T](t: T*): Matcher[T] = BeOneOf(t)
  /** alias for beOneOf */
  def beAnyOf[T](t: T*): Matcher[T] = BeOneOf(t)

  /** matches if the value returns a successful result when applied to a PartialFunction */
  def beLike[T](pattern: PartialFunction[T, MatchResult[_]]) = new Matcher[T] {
    def apply[S <: T](a: Expectable[S]) = {
      val r = if (pattern.isDefinedAt(a.value)) pattern.apply(a.value) else MatchFailure("", "", a)
      result(r.isSuccess,
             a.description + " is correct: " + r.message,
             a.description + " is incorrect: " + r.message,
             a)
    }
  }
  /** matches if v.getClass == c */
  def haveClass[T : ClassTag] = new Matcher[AnyRef] {
    def apply[S <: AnyRef](x: Expectable[S]) = {
      val c = implicitly[ClassTag[T]].runtimeClass
      val xClass = x.value.getClass
      result(xClass == c,
             x.description + " has class " + q(c.getName),
             x.description + " doesn't have class " + q(c.getName) + ". It has class " + q(xClass.getName),
             x)
    }
  }
  /** matches if c.isAssignableFrom(v.getClass.getSuperclass) */
  def haveSuperclass[T : ClassTag] = new Matcher[AnyRef] {
    def apply[S <: AnyRef](x: Expectable[S]) = {
      val c = implicitly[ClassTag[T]].runtimeClass
      val xClass = x.value.getClass
      result(c.isAssignableFrom(xClass.getSuperclass),
             x.description + " has super class " + q(c.getName),
             x.description + " doesn't have super class " + q(c.getName) + ". It has super class " + q(xClass.getSuperclass.getName),
             x)
    }
  }

  /** matches if x.getClass.getInterfaces.contains(T) */
  def haveInterface[T : ClassTag] = new Matcher[AnyRef] {
    def apply[S <: AnyRef](x: Expectable[S]) = {
      val c = implicitly[ClassTag[T]].runtimeClass
      val xClass = x.value.getClass
      result(xClass.getInterfaces.contains(c),
             x.description + " has interface " + q(c.getName),
             x.description + " doesn't have interface " + q(c.getName) + ". It has interface " + xClass.getInterfaces.mkString(", "),
             x)
    }
  }

  /** matches if v.isAssignableFrom(c) */
  def beAssignableFrom[T : ClassTag] = new Matcher[Class[_]] {
    def apply[S <: Class[_]](x: Expectable[S]) = {
      val c = implicitly[ClassTag[T]].runtimeClass
      result(x.value.isAssignableFrom(c), 
             x.description + " is assignable from " + q(c.getName), 
             x.description + " is not assignable from " + q(c.getName), 
             x)
    }
  }

  def beAnInstanceOf[T: ClassTag] = new Matcher[AnyRef] {
    def apply[S <: AnyRef](x: Expectable[S]) = {
      val c = implicitly[ClassTag[T]].runtimeClass
      val xClass = x.value.getClass
      val xWithClass = x.mapDescription(d => s"'$d: ${xClass.getName}'")
      result(c.isAssignableFrom(xClass),
             xWithClass.description + " is an instance of " + q(c.getName),
             xWithClass.description + " is not an instance of " + q(c.getName),
             xWithClass)
    }
  }
}


/**
 * Matcher for a boolean value which must be true
 */
class BeTrueMatcher extends Matcher[Boolean] {
  def apply[S <: Boolean](v: Expectable[S]) = {
    result(v.value, v.description + " is true", v.description + " is false", v) 
  }
}

/**
 * Equality Matcher
 */
class BeEqualTo(t: =>Any) extends BeTypedEqualTo(t)
/**
 * This matcher always matches any value of type T
 */
case class AlwaysMatcher[T]() extends Matcher[T] {
  def apply[S <: T](e: Expectable[S]) = result(true, "ok", "ko", e)
}
/**
 * This matcher never matches any value of type T
 */
case class NeverMatcher[T]() extends Matcher[T] {
  def apply[S <: T](e: Expectable[S]) = result(false, "ok", "ko", e)
}
/**
 * This trait allows to write expressions like
 * 
 *  `1 must be equalTo(1)`
 */
trait AnyBeHaveMatchers extends BeHaveMatchers { outer: AnyMatchers =>
  implicit def anyBeHaveMatcher[T](result: MatchResult[T]): AnyBeHaveMatchers[T] = new AnyBeHaveMatchers(result)
  class AnyBeHaveMatchers[T](result: MatchResult[T]) {
    def be_==(t: T) = result(outer.be_==(t))
    def be_!=(t: T) = result(outer.be_!=(t))
    def be_===(t: T) = result(outer.be_===(t))
    def be_!==(t: T) = result(outer.be_!==(t))
    def be_==~[S](s: =>S)(implicit convert: S => T) = result(outer.be_==~[T, S](s))
    def equalTo(t: T) = result(outer.be_==(t))
    def asNullAs(a: =>T) = result(outer.beAsNullAs(a))
    def beAnyOf(t: T*) = result(outer.beAnyOf(t:_*))
    def beOneOf(t: T*) = result(outer.beOneOf(t:_*))
    def anyOf(t: T*) = result(outer.beAnyOf(t:_*))
    def oneOf(t: T*) = result(outer.beOneOf(t:_*))
    def beNull = result(outer.beNull)
  }

  implicit def toAnyRefMatcherResult[T <: AnyRef](result: MatchResult[T]): AnyRefMatcherResult[T] = new AnyRefMatcherResult(result)
  class AnyRefMatcherResult[T <: AnyRef](result: MatchResult[T]) {
    def beTheSameAs(t: T) = result(outer.beTheSameAs(t))
  }

  implicit def toAnyMatcherResult(result: MatchResult[AnyRef]): AnyMatcherResult = new AnyMatcherResult(result)
  class AnyMatcherResult(result: MatchResult[AnyRef]) {
    def haveClass[T : ClassTag] = result(outer.haveClass[T])
    def anInstanceOf[T : ClassTag] = result(beAnInstanceOf[T])
  }

  implicit def toClassMatcherResult(result: MatchResult[Class[_]]): ClassMatcherResult = new ClassMatcherResult(result)
  class ClassMatcherResult(result: MatchResult[Class[_]]) {
    def assignableFrom = result(outer.beAssignableFrom)
  }
  
  implicit def anyWithEmpty[T <% Any { def isEmpty: Boolean }](result: MatchResult[T]): AnyWithEmptyMatchers[T] =
    new AnyWithEmptyMatchers(result)

  class AnyWithEmptyMatchers[T <% Any { def isEmpty: Boolean }](result: MatchResult[T]) {
    def empty = result(outer.beEmpty[T])
    def beEmpty = result(outer.beEmpty[T])
  }
  implicit def toBeLikeResultMatcher[T](result: MatchResult[T]): BeLikeResultMatcher[T] = new BeLikeResultMatcher(result)
  class BeLikeResultMatcher[T](result: MatchResult[T]) {
    def like(pattern: =>PartialFunction[T, MatchResult[_]]) = result(outer.beLike(pattern))
    def likeA(pattern: =>PartialFunction[T, MatchResult[_]]) = result(outer.beLike(pattern))
  }
  def asNullAs[T](a: =>T) = beAsNullAs(a)
  def like[T](pattern: =>PartialFunction[T, MatchResult[_]]) = beLike(pattern)
  def beLikeA[T](pattern: =>PartialFunction[T, MatchResult[_]]) = beLike(pattern)
  def likeA[T](pattern: =>PartialFunction[T, MatchResult[_]]) = beLike(pattern)
  def empty[T <: Any { def isEmpty: Boolean }] = beEmpty[T]
  def oneOf[T](t: T*) = beOneOf(t:_*)
  def anyOf[T](t: T*) = beAnyOf(t:_*)
  def klass[T : ClassTag]: Matcher[AnyRef] = outer.haveClass[T]
  def superClass[T : ClassTag]: Matcher[AnyRef] = outer.haveSuperclass[T]
  def interface[T : ClassTag]: Matcher[AnyRef] = outer.haveInterface[T]
  def assignableFrom[T : ClassTag] = outer.beAssignableFrom[T]
  def anInstanceOf[T : ClassTag] = outer.beAnInstanceOf[T]
}

class BeTheSameAs[T <: AnyRef](t: =>T) extends Matcher[T] {
  def apply[S <: T](a: Expectable[S]) = {
    val b = t
    result(a.value eq b, a.description + " is the same as " + q(b), a.description + " is not the same as " + q(b), a)
  }
}

class BeNull[T] extends Matcher[T] {
  def apply[S <: T](value: Expectable[S]) = {
    result(value.value == null,
           value.description + " is null",
           value.description + " is not null", value)
  }
}

case class BeOneOf[T](t: Seq[T]) extends Matcher[T] {
  def apply[S <: T](y: Expectable[S]) = {
    val x = t
    result(x.contains(y.value),
      y.description + s" is contained in " + q(x.mkString(", ")),
      y.description + s" is not contained in " + q(x.mkString(", ")),
      y)
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy