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

Commit 422f01c

Browse files
Diff invariant (#318)
* Convert Diff back to invariant type * Create new modules for scalatest specialized for matchers * Update docs * Remove redundant trait * Simplify diff matcher to single word * Update docs
1 parent c60e84c commit 422f01c

File tree

9 files changed

+207
-12
lines changed

9 files changed

+207
-12
lines changed

build.sbt

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,43 @@ lazy val core = (projectMatrix in file("core"))
6868
scalaVersions = List(scala212, scala213)
6969
)
7070

71-
lazy val scalatest = (projectMatrix in file("scalatest"))
71+
lazy val scalatestMust = (projectMatrix in file("scalatest-must"))
72+
.settings(commonSettings)
73+
.settings(
74+
name := "diffx-scalatest-must",
75+
libraryDependencies ++= Seq(
76+
"org.scalatest" %%% "scalatest-mustmatchers" % scalatestVersion,
77+
"org.scalatest" %%% "scalatest-matchers-core" % scalatestVersion,
78+
"org.scalatest" %%% "scalatest-flatspec" % scalatestVersion % Test
79+
)
80+
)
81+
.dependsOn(core)
82+
.jvmPlatform(
83+
scalaVersions = List(scala212, scala213)
84+
)
85+
.jsPlatform(
86+
scalaVersions = List(scala212, scala213)
87+
)
88+
89+
lazy val scalatestShould = (projectMatrix in file("scalatest-should"))
90+
.settings(commonSettings)
91+
.settings(
92+
name := "diffx-scalatest-should",
93+
libraryDependencies ++= Seq(
94+
"org.scalatest" %%% "scalatest-shouldmatchers" % scalatestVersion,
95+
"org.scalatest" %%% "scalatest-matchers-core" % scalatestVersion,
96+
"org.scalatest" %%% "scalatest-flatspec" % scalatestVersion % Test
97+
)
98+
)
99+
.dependsOn(core)
100+
.jvmPlatform(
101+
scalaVersions = List(scala212, scala213)
102+
)
103+
.jsPlatform(
104+
scalaVersions = List(scala212, scala213)
105+
)
106+
107+
lazy val scalatestLegacy = (projectMatrix in file("scalatest"))
72108
.settings(commonSettings)
73109
.settings(
74110
name := "diffx-scalatest",
@@ -209,14 +245,14 @@ lazy val docs = (projectMatrix in file("generated-docs")) // important: it must
209245
),
210246
mdocOut := file("generated-docs/out")
211247
)
212-
.dependsOn(core, scalatest, specs2, utest, refined, tagging, cats, munit)
248+
.dependsOn(core, scalatestShould, specs2, utest, refined, tagging, cats, munit)
213249
.jvmPlatform(scalaVersions = List(scala213))
214250

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

218254
val allAggregates =
219-
core.projectRefs ++ scalatest.projectRefs ++
255+
core.projectRefs ++ scalatestMust.projectRefs ++ scalatestShould.projectRefs ++ scalatestLegacy.projectRefs ++
220256
specs2.projectRefs ++ utest.projectRefs ++ cats.projectRefs ++
221257
refined.projectRefs ++ tagging.projectRefs ++ docs.projectRefs ++ munit.projectRefs
222258

core/src/main/scala/com/softwaremill/diffx/Diff.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
package com.softwaremill.diffx
2+
23
import com.softwaremill.diffx.ObjectMatcher.{IterableEntry, MapEntry, SetEntry}
34
import com.softwaremill.diffx.generic.{DiffMagnoliaDerivation, MagnoliaDerivedMacro}
45
import com.softwaremill.diffx.instances._
56

6-
trait Diff[-T] { outer =>
7+
trait Diff[T] { outer =>
78
def apply(left: T, right: T): DiffResult = apply(left, right, DiffContext.Empty)
89
def apply(left: T, right: T, context: DiffContext): DiffResult
910

docs-sources/test-frameworks/scalatest.md

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,24 +4,38 @@ To use with scalatest, add the following dependency:
44

55
## sbt
66

7+
For use with `should` matchers:
78
```scala
8-
"com.softwaremill.diffx" %% "diffx-scalatest" % "@VERSION@" % Test
9+
"com.softwaremill.diffx" %% "diffx-scalatest-should" % "@VERSION@" % Test
10+
```
11+
12+
For use with `must` matchers:
13+
```scala
14+
"com.softwaremill.diffx" %% "diffx-scalatest-should" % "@VERSION@" % Test
915
```
1016

1117
## mill
1218

19+
For use with `should` matchers:
1320
```scala
14-
ivy"com.softwaremill.diffx::diffx-scalatest::@VERSION@"
21+
ivy"com.softwaremill.diffx::diffx-scalatest-must::@VERSION@"
22+
```
23+
24+
For use with `must` matchers:
25+
```scala
26+
ivy"com.softwaremill.diffx::diffx-scalatest-must::@VERSION@"
1527
```
1628

1729
## Usage
1830

19-
Then, extend the `com.softwaremill.diffx.scalatest.DiffMatcher` trait or `import com.softwaremill.diffx.scalatest.DiffMatcher._`.
31+
Then, depending on the chosen matcher style extend or import relevant trait/object:
32+
- should -> `com.softwaremill.diffx.scalatest.DiffShouldMatcher`
33+
- must -> `com.softwaremill.diffx.scalatest.DiffMustMatcher`
34+
2035
After that you will be able to use syntax such as:
2136

2237
```scala mdoc:compile-only
23-
import org.scalatest.matchers.should.Matchers._
24-
import com.softwaremill.diffx.scalatest.DiffMatcher._
38+
import com.softwaremill.diffx.scalatest.DiffShouldMatcher._
2539
import com.softwaremill.diffx.generic.auto._
2640

2741
sealed trait Parent
@@ -40,5 +54,5 @@ val left: Foo = Foo(
4054
Some(right)
4155
)
4256

43-
left should matchTo(right)
57+
left shouldMatchTo(right)
4458
```
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package com.softwaremill.diffx.scalatest
2+
3+
import com.softwaremill.diffx.{ConsoleColorConfig, Diff}
4+
import org.scalactic.{Prettifier, source}
5+
import org.scalatest.Assertion
6+
import org.scalatest.matchers.must.Matchers
7+
import org.scalatest.matchers.{MatchResult, Matcher}
8+
9+
trait DiffMustMatcher {
10+
11+
implicit def convertToAnyMustMatcher[T: Diff](
12+
any: T
13+
)(implicit pos: source.Position, prettifier: Prettifier, consoleColorConfig: ConsoleColorConfig): AnyMustWrapper[T] =
14+
new AnyMustWrapper[T](any, pos, prettifier, consoleColorConfig, Diff[T])
15+
16+
final class AnyMustWrapper[T](
17+
val leftValue: T,
18+
val pos: source.Position,
19+
val prettifier: Prettifier,
20+
val consoleColorConfig: ConsoleColorConfig,
21+
val diff: Diff[T]
22+
) extends Matchers {
23+
24+
def mustMatchTo(rightValue: T): Assertion = {
25+
Matchers
26+
.convertToAnyMustWrapper[T](leftValue)(pos, prettifier)
27+
.must(matchTo[T](rightValue)(diff, consoleColorConfig))
28+
}
29+
30+
private def matchTo[A: Diff](right: A)(implicit c: ConsoleColorConfig): Matcher[A] = { left =>
31+
val result = Diff[A].apply(left, right)
32+
if (!result.isIdentical) {
33+
val diff =
34+
result.show().split('\n').mkString(Console.RESET, s"${Console.RESET}\n${Console.RESET}", Console.RESET)
35+
MatchResult(matches = false, s"Matching error:\n$diff", "")
36+
} else {
37+
MatchResult(matches = true, "", "")
38+
}
39+
}
40+
}
41+
}
42+
43+
object DiffMustMatcher extends DiffMustMatcher
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package com.softwaremill.diffx.scalatest
2+
3+
import com.softwaremill.diffx.generic.auto._
4+
import org.scalatest.flatspec.AnyFlatSpec
5+
import org.scalatest.matchers.must.Matchers
6+
7+
class DiffMatcherTest extends AnyFlatSpec with Matchers with DiffMustMatcher {
8+
val right: Foo = Foo(
9+
Bar("asdf", 5, Map("a" -> 2)),
10+
List(123, 1234),
11+
Some(Bar("asdf", 5, Map("a" -> 2)))
12+
)
13+
val left: Foo = Foo(
14+
Bar("asdf", 66, Map("b" -> 3)),
15+
List(1234),
16+
Some(right)
17+
)
18+
19+
ignore should "work" in {
20+
left mustMatchTo (right)
21+
}
22+
23+
it should "work with option and some" in {
24+
Option("test") mustMatchTo (Some("test"))
25+
}
26+
}
27+
sealed trait Parent
28+
case class Bar(s: String, i: Int, ss: Map[String, Int]) extends Parent
29+
case class Foo(bar: Bar, b: List[Int], parent: Option[Parent]) extends Parent
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package com.softwaremill.diffx.scalatest
2+
3+
import com.softwaremill.diffx.{ConsoleColorConfig, Diff}
4+
import org.scalactic.{Prettifier, source}
5+
import org.scalatest.Assertion
6+
import org.scalatest.matchers.should.Matchers
7+
import org.scalatest.matchers.{MatchResult, Matcher}
8+
9+
trait DiffShouldMatcher {
10+
implicit def convertToAnyShouldMatcher[T: Diff](
11+
any: T
12+
)(implicit pos: source.Position, prettifier: Prettifier, c: ConsoleColorConfig): AnyShouldWrapper[T] =
13+
new AnyShouldWrapper[T](any, pos, prettifier, c, Diff[T])
14+
15+
final class AnyShouldWrapper[T](
16+
val leftValue: T,
17+
val pos: source.Position,
18+
val prettifier: Prettifier,
19+
val c: ConsoleColorConfig,
20+
val d: Diff[T]
21+
) extends Matchers {
22+
23+
def shouldMatchTo(rightValue: T): Assertion = {
24+
Matchers.convertToAnyShouldWrapper[T](leftValue)(pos, prettifier).should(matchTo[T](rightValue)(d, c))
25+
}
26+
27+
private def matchTo[A: Diff](right: A)(implicit c: ConsoleColorConfig): Matcher[A] = { left =>
28+
val result = Diff[A].apply(left, right)
29+
if (!result.isIdentical) {
30+
val diff =
31+
result.show().split('\n').mkString(Console.RESET, s"${Console.RESET}\n${Console.RESET}", Console.RESET)
32+
MatchResult(matches = false, s"Matching error:\n$diff", "")
33+
} else {
34+
MatchResult(matches = true, "", "")
35+
}
36+
}
37+
}
38+
}
39+
40+
object DiffShouldMatcher extends DiffShouldMatcher
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package com.softwaremill.diffx.scalatest
2+
3+
import com.softwaremill.diffx.generic.auto._
4+
import org.scalatest.flatspec.AnyFlatSpec
5+
import org.scalatest.matchers.should.Matchers
6+
7+
class DiffShouldMatcherTest extends AnyFlatSpec with DiffShouldMatcher with Matchers {
8+
val right: Foo = Foo(
9+
Bar("asdf", 5, Map("a" -> 2)),
10+
List(123, 1234),
11+
Some(Bar("asdf", 5, Map("a" -> 2)))
12+
)
13+
val left: Foo = Foo(
14+
Bar("asdf", 66, Map("b" -> 3)),
15+
List(1234),
16+
Some(right)
17+
)
18+
19+
ignore should "work" in {
20+
left shouldMatchTo (right)
21+
}
22+
23+
it should "work with option and some" in {
24+
Option("test") shouldMatchTo Some("test")
25+
}
26+
}
27+
sealed trait Parent
28+
case class Bar(s: String, i: Int, ss: Map[String, Int]) extends Parent
29+
case class Foo(bar: Bar, b: List[Int], parent: Option[Parent]) extends Parent

scalatest/src/main/scala/com/softwaremill/diffx/scalatest/DiffMatcher.scala

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,19 @@ package com.softwaremill.diffx.scalatest
33
import com.softwaremill.diffx.{ConsoleColorConfig, Diff}
44
import org.scalatest.matchers.{MatchResult, Matcher}
55

6+
@deprecated("Use DiffShouldMatcher or DiffMustMatcher instead")
67
trait DiffMatcher {
78
def matchTo[A: Diff](right: A)(implicit c: ConsoleColorConfig): Matcher[A] = { left =>
89
val result = Diff[A].apply(left, right)
910
if (!result.isIdentical) {
10-
val diff = result.show().split('\n').mkString(Console.RESET, s"${Console.RESET}\n${Console.RESET}", Console.RESET)
11+
val diff =
12+
result.show().split('\n').mkString(Console.RESET, s"${Console.RESET}\n${Console.RESET}", Console.RESET)
1113
MatchResult(matches = false, s"Matching error:\n$diff", "")
1214
} else {
1315
MatchResult(matches = true, "", "")
1416
}
1517
}
1618
}
1719

20+
@deprecated("Use DiffShouldMatcher or DiffMustMatcher instead")
1821
object DiffMatcher extends DiffMatcher

scalatest/src/test/scala/com/softwaremill/diffx/scalatest/DiffMatcherTest.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
package com.softwaremill.diffx.scalatest
22

3+
import com.softwaremill.diffx.generic.auto._
34
import org.scalatest.flatspec.AnyFlatSpec
45
import org.scalatest.matchers.should.Matchers
5-
import com.softwaremill.diffx.generic.auto._
66

77
class DiffMatcherTest extends AnyFlatSpec with Matchers with DiffMatcher {
88
val right: Foo = Foo(

0 commit comments

Comments
 (0)