Skip to content

Add scalactic explicit dependency, make use of Equality by default on eqTo #51

New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Merged
merged 7 commits into from
Oct 25, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ target/
dist/
.gradle/
build/
*.sc
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ The most popular mocking framework for Java, now in Scala!!!

[![Download](https://api.bintray.com/packages/mockito/maven/mockito-scala/images/download.svg) ](https://bintray.com/mockito/maven/mockito-scala/_latestVersion)
[![Maven Central](https://img.shields.io/maven-central/v/org.mockito/mockito-scala_2.12.svg)](https://search.maven.org/search?q=mockito-scala)

[![Gitter chat](https://badges.gitter.im/gitterHQ/gitter.png)](https://gitter.im/mockito-scala/)
## Why separate project?

The library has independent developers, release cycle and versioning from core mockito library (https://github.com/mockito/mockito). This is intentional because core Mockito developers don't use Scala and cannot confidently review PRs, and set the vision for the Scala library.
Expand Down
5 changes: 3 additions & 2 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,14 @@ lazy val commonSettings =

lazy val commonLibraries = Seq(
"org.mockito" % "mockito-core" % "2.21.0",
"org.scalatest" %% "scalatest" % "3.0.5" % "provided"
"org.scalactic" %% "scalactic" % "3.0.5",
"org.scalatest" %% "scalatest" % "3.0.5" % "provided",
)

lazy val common = (project in file("common"))
.settings(
commonSettings,
libraryDependencies += "org.mockito" % "mockito-core" % "2.21.0",
libraryDependencies ++= commonLibraries,
libraryDependencies += "org.scala-lang" % "scala-reflect" % scalaVersion.value,
publish := {},
publishLocal := {},
Expand Down
2 changes: 1 addition & 1 deletion build.sh
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
#!/usr/bin/env bash
java -Xms512M -Xmx2G -Xss2M -XX:ReservedCodeCacheSize=192m -XX:+CMSClassUnloadingEnabled -Dfile.encoding=UTF-8 -jar sbt/sbt-launch.jar -Dsbt.parser.simple=true clean test 'set every publishTo := Some(Resolver.file("local-repo", file("target/dist")))' '+ publish'
java -Xms512M -Xmx2G -Xss2M -XX:ReservedCodeCacheSize=192m -XX:+CMSClassUnloadingEnabled -Dfile.encoding=UTF-8 -jar sbt/sbt-launch.jar -Dsbt.parser.simple=true clean +test 'set every publishTo := Some(Resolver.file("local-repo", file("target/dist")))' '+ publish'
13 changes: 8 additions & 5 deletions common/src/main/scala/org/mockito/matchers/EqMatchers.scala
Original file line number Diff line number Diff line change
@@ -1,18 +1,21 @@
package org.mockito
package matchers

import org.mockito.{ ArgumentMatchers => JavaMatchers }
import org.mockito.{ArgumentMatchers => JavaMatchers}
import org.scalactic.Equality

import scala.reflect.ClassTag

private[mockito] trait EqMatchers {

/**
* Delegates to <code>ArgumentMatchers.eq()</code>, it renames the method to <code>eqTo</code> to
* avoid clashes with the Scala <code>eq</code> method used for reference equality
*
* Creates a matcher that delegates on {{org.scalactic.Equality}} so you can always customise how the values are compared
*/
def eqTo[T](value: T): T = JavaMatchers.eq(value)
def eqTo[T](value: T)(implicit $eq: Equality[T]): T =
ThatMatchers.argThat(new ArgumentMatcher[T] {
override def matches(v: T): Boolean = $eq.areEqual(v, value)
override def toString: String = s"eqTo($value)"
})

/**
* Delegates to <code>ArgumentMatchers.same()</code>, it's only here so we expose all the `ArgumentMatchers`
Expand Down
43 changes: 43 additions & 0 deletions common/src/main/scala/org/mockito/matchers/NumericMatchers.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package org.mockito.matchers

import org.mockito.ArgumentMatcher
import org.scalactic.TripleEqualsSupport.Spread

/**
* I transform everything to BigDecimal so any kind of number type can be compared
Expand All @@ -15,13 +16,55 @@ class N {

import ThatMatchers.argThat

/**
* Creates a matcher that works only if there is a Numeric[T] associated with the type, this allows you to write stuff like
*
* aMock.pepe(4.1)
* aMock.pepe(n > 4) was called
*
*/
def >[N: Numeric](n: N): N = argThat[N](new NumericMatcher(n, ">", _ > _))

/**
* Creates a matcher that works only if there is a Numeric[T] associated with the type, this allows you to write stuff like
*
* aMock.pepe(4)
* aMock.pepe(n >= 4) was called
*
*/
def >=[N: Numeric](n: N): N = argThat[N](new NumericMatcher(n, ">=", _ >= _))

/**
* Creates a matcher that works only if there is a Numeric[T] associated with the type, this allows you to write stuff like
*
* aMock.pepe(3.1)
* aMock.pepe(n < 4) was called
*
*/
def <[N: Numeric](n: N): N = argThat[N](new NumericMatcher(n, "<", _ < _))

/**
* Creates a matcher that works only if there is a Numeric[T] associated with the type, this allows you to write stuff like
*
* aMock.pepe(4)
* aMock.pepe(n <= 4) was called
*
*/
def <=[N: Numeric](n: N): N = argThat[N](new NumericMatcher(n, "<=", _ <= _))

/**
* Creates a matcher that delegates on {{org.scalactic.TripleEqualsSupport.Spread}} so you can get around the lack of
* precision on floating points, e.g.
*
* aMock.barDouble(4.999)
* verify(aMock).barDouble(=~(5.0 +- 0.001))
*
*/
def =~[T](spread: Spread[T]): T =
ThatMatchers.argThat(new ArgumentMatcher[T] {
override def matches(v: T): Boolean = spread.isWithin(v)
override def toString: String = s"=~($spread)"
})
}

private[mockito] trait NumericMatchers {
Expand Down
13 changes: 13 additions & 0 deletions core/src/test/scala/user/org/mockito/matchers/EqMatchersTest.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package user.org.mockito.matchers

import org.mockito.{ArgumentMatchersSugar, MockitoSugar}
import org.mockito.exceptions.verification.WantedButNotInvoked
import org.scalactic.{Equality, StringNormalizations}
import org.scalatest.{FlatSpec, Matchers => ScalaTestMatchers}

class EqMatchersTest extends FlatSpec with MockitoSugar with ScalaTestMatchers with ArgumentMatchersSugar {
Expand Down Expand Up @@ -151,4 +153,15 @@ class EqMatchersTest extends FlatSpec with MockitoSugar with ScalaTestMatchers w
verify(aMock).baz(refEq(Baz("Hello", "World")))
verify(aMock).baz(refEq(Baz("Hello", "Mars"), "param2"))
}

"eqTo[T]" should "work when an implicit Equality is in scope" in {
import StringNormalizations._

implicit val eq: Equality[String] = decided by defaultEquality[String] afterBeing lowerCased

val aMock = mock[Foo]

aMock.bar("meh")
verify(aMock).bar(eqTo("MEH"))
}
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
package user.org.mockito.matchers

import org.mockito.{ArgumentMatchersSugar, IdiomaticMockito}
import org.mockito.{ ArgumentMatchersSugar, IdiomaticMockito }
import org.mockito.exceptions.verification.WantedButNotInvoked
import org.scalatest.{FlatSpec, Matchers}
import org.scalatest.{ FlatSpec, Matchers }

class NumberMatchersTest extends FlatSpec with IdiomaticMockito with Matchers with ArgumentMatchersSugar {
class NumericMatchersTest extends FlatSpec with IdiomaticMockito with Matchers with ArgumentMatchersSugar {

trait Foo {
class Foo {
def pepe[N](n: N, v: String = "meh"): N = ???
}

Expand Down Expand Up @@ -69,4 +69,16 @@ class NumberMatchersTest extends FlatSpec with IdiomaticMockito with Matchers wi
aMock.pepe(n <= 3.0) was called
}
}

"=~" should "work" in {
val aMock = mock[Foo]

aMock.pepe(4.999)

aMock.pepe(n =~ 5.0 +- 0.001) was called

an[WantedButNotInvoked] shouldBe thrownBy {
aMock.pepe(n =~ 5.0 +- 0.00001) was called
}
}
}
1 change: 1 addition & 0 deletions macro/src/main/scala/org/mockito/Utils.scala
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ object Utils {
case q"$_.n.>=[$_]($_)($_)" => true
case q"$_.n.<[$_]($_)($_)" => true
case q"$_.n.<=[$_]($_)($_)" => true
case q"$_.n.=~[$_]($_)" => true

case q"$_.Captor.asCapture[$_]($_)" => true

Expand Down