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

Diff covariant #317

Closed
wants to merge 2 commits into from
Closed
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
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 {

def matchTo[A](right: A): A = right

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

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

def must(rightValue: T)(implicit c: ConsoleColorConfig): Assertion = {
Matchers.convertToAnyMustWrapper(leftValue)(pos, prettifier).must(matchTo(rightValue))
}

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,30 @@
package com.softwaremill.diffx.scalatest

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

class DiffMatcherTest extends AnyFlatSpec with Matchers with DiffMustMatcher with OptionValues {
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 must matchTo(right)
}

it should "work with option and some" in {
Option("test") must matchTo(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,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.should.Matchers
import org.scalatest.matchers.{MatchResult, Matcher}

trait DiffShouldMatcher extends DiffShouldMatcherImp {

def matchTo[A](right: A): A = right

implicit def convertToAnyShouldMatcher[T: Diff](
any: T
)(implicit pos: source.Position, prettifier: Prettifier): AnyShouldWrapper[T] =
new AnyShouldWrapper[T](any, pos, prettifier)
}

trait DiffShouldMatcherImp {
class AnyShouldWrapper[T: Diff](
val leftValue: T,
val pos: source.Position,
val prettifier: Prettifier
) extends Matchers {

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

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,30 @@
package com.softwaremill.diffx.scalatest

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

class DiffShouldMatcherTest extends AnyFlatSpec with Matchers with DiffShouldMatcher with OptionValues {
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 should matchTo(right)
}

it should "work with option and some" in {
Option("test") should matchTo(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,10 +1,11 @@
package com.softwaremill.diffx.scalatest

import com.softwaremill.diffx.generic.auto._
import org.scalatest.OptionValues
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 {
class DiffMatcherTest extends AnyFlatSpec with Matchers with DiffMatcher with OptionValues {
val right: Foo = Foo(
Bar("asdf", 5, Map("a" -> 2)),
List(123, 1234),
Expand Down