Skip to content
This repository was archived by the owner on Jan 24, 2025. It is now read-only.

Diff invariant #318

Merged
merged 6 commits into from
Oct 29, 2021
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
42 changes: 39 additions & 3 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,43 @@ lazy val core = (projectMatrix in file("core"))
scalaVersions = List(scala212, scala213)
)

lazy val scalatest = (projectMatrix in file("scalatest"))
lazy val scalatestMust = (projectMatrix in file("scalatest-must"))
.settings(commonSettings)
.settings(
name := "diffx-scalatest-must",
libraryDependencies ++= Seq(
"org.scalatest" %%% "scalatest-mustmatchers" % scalatestVersion,
"org.scalatest" %%% "scalatest-matchers-core" % scalatestVersion,
"org.scalatest" %%% "scalatest-flatspec" % scalatestVersion % Test
)
)
.dependsOn(core)
.jvmPlatform(
scalaVersions = List(scala212, scala213)
)
.jsPlatform(
scalaVersions = List(scala212, scala213)
)

lazy val scalatestShould = (projectMatrix in file("scalatest-should"))
.settings(commonSettings)
.settings(
name := "diffx-scalatest-should",
libraryDependencies ++= Seq(
"org.scalatest" %%% "scalatest-shouldmatchers" % scalatestVersion,
"org.scalatest" %%% "scalatest-matchers-core" % scalatestVersion,
"org.scalatest" %%% "scalatest-flatspec" % scalatestVersion % Test
)
)
.dependsOn(core)
.jvmPlatform(
scalaVersions = List(scala212, scala213)
)
.jsPlatform(
scalaVersions = List(scala212, scala213)
)

lazy val scalatestLegacy = (projectMatrix in file("scalatest"))
.settings(commonSettings)
.settings(
name := "diffx-scalatest",
Expand Down Expand Up @@ -209,14 +245,14 @@ lazy val docs = (projectMatrix in file("generated-docs")) // important: it must
),
mdocOut := file("generated-docs/out")
)
.dependsOn(core, scalatest, specs2, utest, refined, tagging, cats, munit)
.dependsOn(core, scalatestShould, specs2, utest, refined, tagging, cats, munit)
.jvmPlatform(scalaVersions = List(scala213))

val testJVM = taskKey[Unit]("Test JVM projects")
val testJS = taskKey[Unit]("Test JS projects")

val allAggregates =
core.projectRefs ++ scalatest.projectRefs ++
core.projectRefs ++ scalatestMust.projectRefs ++ scalatestShould.projectRefs ++ scalatestLegacy.projectRefs ++
specs2.projectRefs ++ utest.projectRefs ++ cats.projectRefs ++
refined.projectRefs ++ tagging.projectRefs ++ docs.projectRefs ++ munit.projectRefs

Expand Down
3 changes: 2 additions & 1 deletion core/src/main/scala/com/softwaremill/diffx/Diff.scala
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
package com.softwaremill.diffx

import com.softwaremill.diffx.ObjectMatcher.{IterableEntry, MapEntry, SetEntry}
import com.softwaremill.diffx.generic.{DiffMagnoliaDerivation, MagnoliaDerivedMacro}
import com.softwaremill.diffx.instances._

trait Diff[-T] { outer =>
trait Diff[T] { outer =>
def apply(left: T, right: T): DiffResult = apply(left, right, DiffContext.Empty)
def apply(left: T, right: T, context: DiffContext): DiffResult

Expand Down
26 changes: 20 additions & 6 deletions docs-sources/test-frameworks/scalatest.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,38 @@ To use with scalatest, add the following dependency:

## sbt

For use with `should` matchers:
```scala
"com.softwaremill.diffx" %% "diffx-scalatest" % "@VERSION@" % Test
"com.softwaremill.diffx" %% "diffx-scalatest-should" % "@VERSION@" % Test
```

For use with `must` matchers:
```scala
"com.softwaremill.diffx" %% "diffx-scalatest-should" % "@VERSION@" % Test
```

## mill

For use with `should` matchers:
```scala
ivy"com.softwaremill.diffx::diffx-scalatest::@VERSION@"
ivy"com.softwaremill.diffx::diffx-scalatest-must::@VERSION@"
```

For use with `must` matchers:
```scala
ivy"com.softwaremill.diffx::diffx-scalatest-must::@VERSION@"
```

## Usage

Then, extend the `com.softwaremill.diffx.scalatest.DiffMatcher` trait or `import com.softwaremill.diffx.scalatest.DiffMatcher._`.
Then, depending on the chosen matcher style extend or import relevant trait/object:
- should -> `com.softwaremill.diffx.scalatest.DiffShouldMatcher`
- must -> `com.softwaremill.diffx.scalatest.DiffMustMatcher`

After that you will be able to use syntax such as:

```scala mdoc:compile-only
import org.scalatest.matchers.should.Matchers._
import com.softwaremill.diffx.scalatest.DiffMatcher._
import com.softwaremill.diffx.scalatest.DiffShouldMatcher._
import com.softwaremill.diffx.generic.auto._

sealed trait Parent
Expand All @@ -40,5 +54,5 @@ val left: Foo = Foo(
Some(right)
)

left should matchTo(right)
left shouldMatchTo(right)
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package com.softwaremill.diffx.scalatest

import com.softwaremill.diffx.{ConsoleColorConfig, Diff}
import org.scalactic.{Prettifier, source}
import org.scalatest.Assertion
import org.scalatest.matchers.must.Matchers
import org.scalatest.matchers.{MatchResult, Matcher}

trait DiffMustMatcher {

implicit def convertToAnyMustMatcher[T: Diff](
any: T
)(implicit pos: source.Position, prettifier: Prettifier, consoleColorConfig: ConsoleColorConfig): AnyMustWrapper[T] =
new AnyMustWrapper[T](any, pos, prettifier, consoleColorConfig, Diff[T])

final class AnyMustWrapper[T](
val leftValue: T,
val pos: source.Position,
val prettifier: Prettifier,
val consoleColorConfig: ConsoleColorConfig,
val diff: Diff[T]
) extends Matchers {

def mustMatchTo(rightValue: T): Assertion = {
Matchers
.convertToAnyMustWrapper[T](leftValue)(pos, prettifier)
.must(matchTo[T](rightValue)(diff, consoleColorConfig))
}

private def matchTo[A: Diff](right: A)(implicit c: ConsoleColorConfig): Matcher[A] = { left =>
val result = Diff[A].apply(left, right)
if (!result.isIdentical) {
val diff =
result.show().split('\n').mkString(Console.RESET, s"${Console.RESET}\n${Console.RESET}", Console.RESET)
MatchResult(matches = false, s"Matching error:\n$diff", "")
} else {
MatchResult(matches = true, "", "")
}
}
}
}

object DiffMustMatcher extends DiffMustMatcher
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package com.softwaremill.diffx.scalatest

import com.softwaremill.diffx.generic.auto._
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.must.Matchers

class DiffMatcherTest extends AnyFlatSpec with Matchers with DiffMustMatcher {
val right: Foo = Foo(
Bar("asdf", 5, Map("a" -> 2)),
List(123, 1234),
Some(Bar("asdf", 5, Map("a" -> 2)))
)
val left: Foo = Foo(
Bar("asdf", 66, Map("b" -> 3)),
List(1234),
Some(right)
)

ignore should "work" in {
left mustMatchTo (right)
}

it should "work with option and some" in {
Option("test") mustMatchTo (Some("test"))
}
}
sealed trait Parent
case class Bar(s: String, i: Int, ss: Map[String, Int]) extends Parent
case class Foo(bar: Bar, b: List[Int], parent: Option[Parent]) extends Parent
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package com.softwaremill.diffx.scalatest

import com.softwaremill.diffx.{ConsoleColorConfig, Diff}
import org.scalactic.{Prettifier, source}
import org.scalatest.Assertion
import org.scalatest.matchers.should.Matchers
import org.scalatest.matchers.{MatchResult, Matcher}

trait DiffShouldMatcher {
implicit def convertToAnyShouldMatcher[T: Diff](
any: T
)(implicit pos: source.Position, prettifier: Prettifier, c: ConsoleColorConfig): AnyShouldWrapper[T] =
new AnyShouldWrapper[T](any, pos, prettifier, c, Diff[T])

final class AnyShouldWrapper[T](
val leftValue: T,
val pos: source.Position,
val prettifier: Prettifier,
val c: ConsoleColorConfig,
val d: Diff[T]
) extends Matchers {

def shouldMatchTo(rightValue: T): Assertion = {
Matchers.convertToAnyShouldWrapper[T](leftValue)(pos, prettifier).should(matchTo[T](rightValue)(d, c))
}

private def matchTo[A: Diff](right: A)(implicit c: ConsoleColorConfig): Matcher[A] = { left =>
val result = Diff[A].apply(left, right)
if (!result.isIdentical) {
val diff =
result.show().split('\n').mkString(Console.RESET, s"${Console.RESET}\n${Console.RESET}", Console.RESET)
MatchResult(matches = false, s"Matching error:\n$diff", "")
} else {
MatchResult(matches = true, "", "")
}
}
}
}

object DiffShouldMatcher extends DiffShouldMatcher
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package com.softwaremill.diffx.scalatest

import com.softwaremill.diffx.generic.auto._
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.should.Matchers

class DiffShouldMatcherTest extends AnyFlatSpec with DiffShouldMatcher with Matchers {
val right: Foo = Foo(
Bar("asdf", 5, Map("a" -> 2)),
List(123, 1234),
Some(Bar("asdf", 5, Map("a" -> 2)))
)
val left: Foo = Foo(
Bar("asdf", 66, Map("b" -> 3)),
List(1234),
Some(right)
)

ignore should "work" in {
left shouldMatchTo (right)
}

it should "work with option and some" in {
Option("test") shouldMatchTo Some("test")
}
}
sealed trait Parent
case class Bar(s: String, i: Int, ss: Map[String, Int]) extends Parent
case class Foo(bar: Bar, b: List[Int], parent: Option[Parent]) extends Parent
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,19 @@ package com.softwaremill.diffx.scalatest
import com.softwaremill.diffx.{ConsoleColorConfig, Diff}
import org.scalatest.matchers.{MatchResult, Matcher}

@deprecated("Use DiffShouldMatcher or DiffMustMatcher instead")
trait DiffMatcher {
def matchTo[A: Diff](right: A)(implicit c: ConsoleColorConfig): Matcher[A] = { left =>
val result = Diff[A].apply(left, right)
if (!result.isIdentical) {
val diff = result.show().split('\n').mkString(Console.RESET, s"${Console.RESET}\n${Console.RESET}", Console.RESET)
val diff =
result.show().split('\n').mkString(Console.RESET, s"${Console.RESET}\n${Console.RESET}", Console.RESET)
MatchResult(matches = false, s"Matching error:\n$diff", "")
} else {
MatchResult(matches = true, "", "")
}
}
}

@deprecated("Use DiffShouldMatcher or DiffMustMatcher instead")
object DiffMatcher extends DiffMatcher
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package com.softwaremill.diffx.scalatest

import com.softwaremill.diffx.generic.auto._
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.should.Matchers
import com.softwaremill.diffx.generic.auto._

class DiffMatcherTest extends AnyFlatSpec with Matchers with DiffMatcher {
val right: Foo = Foo(
Expand Down