Giter Site home page Giter Site logo

diffx's Introduction

diffx

Build Status Maven Central diffx-core Scala version support

Gitter Scala Steward badge Documentation Status

Maintenance mode

โš ๏ธ Diffx is no longer actively developed.

No new features will be added.

Pull requests with bug fixes will still be merged for some time.

New users are encouraged to try out a better alternative - difflicious

Old users should migrate to difflicious by the end of 2024.

I am planning to archive this project by that time unless someone volunteers to take it over.

If you spot something that is missing in difflicious that blocks your migration, please don't hesitate and open an issue there.

If you are curious why I decided to do that here is a short summary:

  • diffx didn't have any development for quite some time. Sure some libraries are just done and there is no need for constant development. In my opinion this is not the case for diffx as its internals should be refactored. Also there are some open bugs that should be taken care of.
  • I simply don't have time and energy to maintain it anymore
  • difflicious has better design so there is no point in keeping diffx around

Thank you all for using this project.

Documentation

diffx documentation is available at diffx-scala.readthedocs.io.

Modifying documentation

The documentation is typechecked using mdoc. The sources for the documentation exist in docs-sources. Don't modify the generated documentation in generated-docs, as these files will get overwritten!

When generating documentation, it's best to set the version to the current one, so that the generated doc files don't include modifications with the current snapshot version.

That is, in sbt run: set version := "0.5.0", before running mdoc in docs.

Releasing a new version

$ nix develop
$ sbt release

Copyright

Copyright (C) 2019 SoftwareMill https://softwaremill.com.

diffx's People

Contributors

adamw avatar baztoune avatar dabd avatar dependabot[bot] avatar ghostbuster91 avatar jatcwang avatar jtjeferreira avatar krever avatar kubukoz avatar matankdr avatar mergify[bot] avatar mkrzemien avatar nadavwr avatar otrebski avatar scala-steward avatar stephennancekivell avatar unaiuribarri-tomtom avatar xplosunn avatar xuwei-k avatar yuanyuma avatar zaneli avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

diffx's Issues

ScalaTest matchTo to support matching Options

Hi, I get a compilation error when i.e.

import com.softwaremill.diffx.scalatest.DiffMatcher

callMethodThatReturnsOption(...) should matchTo(Some(x))

it works fine for sequences. Weirdly it works fine with code like
Some(5) should matchTo(Some(5)) but not if the left part is a method invocation.

On scala 2.13 and these deps:

val ScalaTest = ivy"org.scalatest::scalatest:3.2.0"
val Diffx = Seq(ivy"com.softwaremill.diffx::diffx-core:0.3.29", ivy"com.softwaremill.diffx::diffx-scalatest:0.3.29")

Semi-auto derivation fails for reference to type with self-extension

The example below fails with the following error:

debug/Debug.scala:18: error: magnolia: could not find Diff.Typeclass for type Option[foobar.Debug.A]
    in parameter 'id' of product type foobar.Debug.B

  implicit val diffB: Derived[Diff[B]] = Diff.derived[B]

Versions:

  • diffx: 0.4.5
  • Magnolia: 0.17.0
  • Mercator: 0.3.0
  • Scala 2.13.5 but also reproduces on 2.12.13
package foobar

import com.softwaremill.diffx._

object Debug {

  // This is scalapb.Message in real code.
  trait T[C]

  // Removing the inheritance makes it compile.
  final case class A() extends T[A]

  final case class B(id: Option[A])
  implicit val diffA: Derived[Diff[A]] = Diff.derived[A]
  implicit val diffB: Derived[Diff[B]] = Diff.derived[B]
  // Fails with: error: magnolia: could not find Diff.Typeclass for type Option[foobar.Debug.Identifier]
}

The issue goes away when removing the extension of T but as mentioned in the comment this comes from generated ScalaPb code so this is not an option.

fix edit on github button

Despite provided configuration edit on gh button redirects to generated sources

# configure edit on github: https://docs.readthedocs.io/en/latest/guides/vcs.html
html_context = {
    'display_github': True, # Integrate GitHub
    'github_user': 'softwaremill', # Username
    'github_repo': 'diffx', # Repo name
    'github_version': 'master', # Version
    'conf_py_path': '/docs-sources/', # Path in the checkout to the docs root
}

java.lang.InstantiationError when using diffx with java annotations

Hi)

I've found a tricky error when matching over case class annotated with java annotations.
Minimal example:

// in src/main dir:
package com.example

@Deprecated
case class Bar(x: String, y: Int)

// in src/test dir
package com.example

import com.softwaremill.diffx.scalatest.DiffMatcher
import org.scalatest.{FlatSpec, Matchers}

class TestSpec extends FlatSpec with Matchers with DiffMatcher {
  "diffx" should "work" in {
    Bar(x = "a", y = 1) should matchTo(
      Bar(x = "a", y = 0)
    )
  }
}

Then I've got the following exception:

[info] com.example.TestSpec *** ABORTED ***
[info]   java.lang.InstantiationError: java.lang.Deprecated
[info]   at com.example.TestSpec$$anon$1.<init>(TestSpec.scala:8)
[info]   at com.example.TestSpec.$anonfun$new$1(TestSpec.scala:8)
// and then some scalatest/sbt stack trace mase

Removing annotation solves this exception, but in some cases it's not an option.
(for instance when using swagger annotations).

Is it a known behavior?

Scalatest mixin to override the behavior of `Matchers`?

In our codebase we use the scalatest Matchers trait pretty heavily.

Is it possible to extend that trait and override the code in it such that the interface remains the same but the errors are reported using diffx? I could add an extra mixin to a base test class, but changing every single test file in the project is awkward. I don't want to "just" add the DiffMatcher trait ad-hoc because the codebase already suffers from "too many ways to assert" problems in consistency.

Supporting full comparison between NonEmptyList

Here an example, where I need to include the head as part of the implicit to make it works:

import cats.data.NonEmptyList
import com.softwaremill.diffx.scalatest.DiffMatcher
import com.softwaremill.diffx.{Derived, Diff}
import org.scalatest.{FlatSpec, Matchers}

class NonEmptyListDiffxTest extends FlatSpec with Matchers with DiffMatcher {

  case class Person(id: Int, firstName: String, surname: String)

  case class Test(id: Int, people: NonEmptyList[Person])

  val person1 = Person(1, "Anna", "Blue")
  val person2 = Person(2, "Jason", "Red")
  val person3 = Person(3, "Anna", "Blue")

  //  implicit val diffPerson: Diff[Person] = Derived[Diff[Person]].ignore(_.id) It does not work 

  implicit val diffTest: Diff[Test] = Derived[Diff[Test]].ignore(_.id).ignore(_.people.head.id)

  val list: NonEmptyList[Person] = NonEmptyList.of(person1, person2)
  val list2: NonEmptyList[Person] = NonEmptyList.of(person3, person2)

  val test1 = Test(1, list)
  val test2 = Test(2, list2)

  test1 should matchTo(test2)
}

Change Diff back to invariant TC

Context

Diff was made a contravariant typeclass quite some time in #92 due to #17

It all boils down to that simple line of code:
Option("test") should matchTo(Some("a"))

Without that change it wouldn't compile because should expects Matcher[Option[String]] and it gets Matcher[Some[String]].
Matcher is a contravariant type which means that we have a reversed subtyping relation between the class and its type parameter. Given A <: B we have Matcher[B] <: Matcher[A].

Unfortunately, that decision turned out to be a blocker in the long run when migrating to scala3 (see scala/scala3#13146 and softwaremill/magnolia#336)

In general, I think that it makes more sens for Diff to be invariant because its instances are derived from the primitives up, which means that we first get to know how to compare Somes to later build on top of that a Diff for Options.

There is no need for a special relation between Diff[A] and Diff[B] where A <: B because when we have Diff[B] and some As these As can be lifted to B type.

What about scalatest

While these days we have other great test frameworks available, scalatest still remains one of the most popular.
Without a contravariance scalatest users would need to adapt their code-bases either by getting value out of option:

fooOpt.value should matchTo(fooExpected)

or by specifying types explicitly:

fooOpt should matchTo(Some(fooExpected): Option[String])

or by using Option constructor:

fooOpt should matchTo(Option(fooExpected))

Why can't we have invariant Diff instances and usability in the scalatest?

It seems that we can. In order to make our problematic line compile, we need to change the complex types around our values to be covariant. That way we will invert the relation and in the end get Matcher[A] <: Matcher[B] where A <: B. Obviously that won't be a scalatest matcher anymore.

The downside of that is that we need to override the should method, which means

  • the matcher won't work with must matchers
  • eventually we need to call the original should matcher which means that we need to have an additional dependency.

Because of that we should create new artifacts: diffx-scalatest-should and diffx-scalatest-must which will contain fixes for particular matching styles.

Update: Above solution turned out to be impossible because of ambiguity. Because of that I decided to implement a simpler solution which is to have a single-word matcher like shouldMatchTo and mustMatchTo.

Writing generic methods that use matchTo

I'm having trouble writing a method that uses matchTo on a generic type. I'm using the scala test integration, but using Diff.apply directly produces the same results. For example:

def testSomething[A](expected: A, actual: A): Unit = {
  expected should matchTo(actual)
}

This produces the following error:

[error] ... could not find implicit value for evidence parameter of type com.softwaremill.diffx.Diff[A]
[error]     expected should matchTo(actual)
[error]                            ^

Changing the definition to this:

def testSomething[A: Diff](expected: A, actual: A): Unit = {
  expected should matchTo(actual)
}

Moves the error to the callsite. I'm using simple case classes when calling this method. How can I acquire an implicit instance of Diff for my case class?

intelligent set diffs

apart from computing additional/missing elements, we could try to pair up mismatching elements when diffing sets in an intelligent way, so that two (different) elements are paired up in the final diff using "minimal difference". Or maybe we could assume that elements should be paired if they have e.g. 3 differences at most?

Additional/Missing String rendering look inverted (Iterable/multiline String/...)

Hi, I use the diffx-specs2 integration in my project, with great satisfaction and I now plan to use diffx-core to generate a change list for my users. But I noticed a difference when I used the String rendering, which looks inverted for Iterable and multiline String

Diff.compare("abc", "abc000").show // renders "-abc -> +abc000" which is OK
Diff.compare("abc", "abc\n000").show // renders "abc -000" although 000 is added to the right
Diff.compare(Seq("abc", "def"), Seq("abc")).show // renders List(0: abc, 1: +def) although an element is removed

It looks like showIntended should be inverted for DiffResultMissing and DiffResultAdditional, or did I miss something ? I'm willing to provide a PR if needed. Thanks !

Comparison between sealed traits implementation with ignored fields is not working

Here an example:

import com.softwaremill.diffx.scalatest.DiffMatcher
import com.softwaremill.diffx.{Derived, Diff}
import org.scalatest.{FlatSpec, Matchers}

class Test extends FlatSpec with Matchers with DiffMatcher {

  sealed trait Base {
    def id: Int
    def name: String
  }

  final case class SubtypeOne(id: Int, name: String) extends Base

  final case class SubtypeTwo(id: Int, name: String) extends Base

  case class Example(base: Base)

  case class Example1(bases: List[Base])

  implicit val b: Diff[Base] = Derived[Diff[Base]].ignore(_.id)
  implicit val e: Diff[Example] = Derived[Diff[Example]].ignore(_.base.id)
  implicit val ex: Diff[Example1] = Derived[Diff[Example1]].ignore(_.bases.each.id)

  val baseRight = SubtypeOne(1, "one")
  val baseRight1 = SubtypeOne(1, "one")
  val baseLeft = SubtypeOne(2, "one")

  val exampleRight = Example(baseRight)
  val exampleLeft = Example(baseLeft)

  val examplesRight = Example1(List(baseRight))
  val examplesLeft = Example1(List(baseLeft))

  baseLeft should matchTo(baseRight)
  exampleLeft should matchTo(exampleRight)
  examplesRight should matchTo(examplesLeft)
}

matchTo does not work on Option

Option("test") should equal(Some("test"))

Option("test") should matchTo(Some("test"))
overloaded method value should with alternatives:
[error]   (endWithWord: org.scalatest.words.EndWithWord)(implicit ev: Option[String] <:< String)TaskSnapshotFormatSpec.this.ResultOfEndWithWordForString <and>
[error]   (startWithWord: org.scalatest.words.StartWithWord)(implicit ev: Option[String] <:< String)TaskSnapshotFormatSpec.this.ResultOfStartWithWordForString <and>
[error]   (includeWord: org.scalatest.words.IncludeWord)(implicit ev: Option[String] <:< String)TaskSnapshotFormatSpec.this.ResultOfIncludeWordForString <and>
[error]   (notExist: org.scalatest.words.ResultOfNotExist)(implicit existence: org.scalatest.enablers.Existence[Option[String]])org.scalatest.Assertion <and>
[error]   (existWord: org.scalatest.words.ExistWord)(implicit existence: org.scalatest.enablers.Existence[Option[String]])org.scalatest.Assertion <and>
[error]   (containWord: org.scalatest.words.ContainWord)org.scalatest.words.ResultOfContainWord[Option[String]] <and>
[error]   (haveWord: org.scalatest.words.HaveWord)TaskSnapshotFormatSpec.this.ResultOfHaveWordForExtent[Option[String]] <and>
[error]   (beWord: org.scalatest.words.BeWord)TaskSnapshotFormatSpec.this.ResultOfBeWordForAny[Option[String]] <and>
[error]   (inv: org.scalactic.TripleEqualsSupport.TripleEqualsInvocationOnSpread[Option[String]])(implicit ev: Numeric[Option[String]])org.scalatest.Assertion <and>
[error]   [U](inv: org.scalactic.TripleEqualsSupport.TripleEqualsInvocation[U])(implicit constraint: org.scalactic.CanEqual[Option[String],U])org.scalatest.Assertion <and>
[error]   (notWord: org.scalatest.words.NotWord)org.scalatest.words.ResultOfNotWordForAny[Option[String]] <and>
[error]   [TYPECLASS1[_], TYPECLASS2[_]](rightMatcherFactory2: org.scalatest.matchers.MatcherFactory2[Option[String],TYPECLASS1,TYPECLASS2])(implicit typeClass1: TYPECLASS1[Option[String]], implicit typeClass2: TYPECLASS2[Option[String]])org.scalatest.Assertion <and>
[error]   [TYPECLASS1[_]](rightMatcherFactory1: org.scalatest.matchers.MatcherFactory1[Option[String],TYPECLASS1])(implicit typeClass1: TYPECLASS1[Option[String]])org.scalatest.Assertion <and>
[error]   (rightMatcherX1: org.scalatest.matchers.Matcher[Option[String]])org.scalatest.Assertion
[error]  cannot be applied to (com.softwaremill.diffx.scalatest.DiffMatcher.DiffForMatcher[Some[String]])
[error]     Option("test") should matchTo(Some("test"))

matchTo does not work with value classes

case class Foo(private val id: String) extends AnyVal

Foo("test") should equal(Foo("test"))
Foo("test") should matchTo(Foo("test"))

could not find implicit value for evidence parameter of type com.softwaremill.diffx.Diff[io.waylay.engine.runtime.format.Foo]
[error] Foo("test") should matchTo(Foo("test"))

bad qualifier received: mkAttributedQualifier

I was able to reproduce an error that I encountered in a real project as a minmal example.

The example is here https://github.com/markus1189/diffx-test/blob/master/src/main/scala/example/Hello.scala

What's strange is that it works if the tagged type uses String instead of Int (Double breaks as well, maybe something involving AnyVal?)

The concrete error is:

[info] Compiling 1 Scala source to /tmp/bar/diffx-test/target/scala-2.13/classes ...
[error]                                                                                                   
[error]   bad qualifier received: mkAttributedQualifier(<notype>, <none>)
[error]      while compiling: /tmp/bar/diffx-test/src/main/scala/example/Hello.scala
[error]         during phase: typer
[error]      library version: version 2.13.1
[error]     compiler version: version 2.13.1
[error]   reconstructed args: -bootclasspath /nix/store/lm5rrzcv6q4klcrrwh0dwv74pppf6206-openjdk-8u222-ga/lib/openjdk/jre/lib/resources.jar:/nix/store/lm5rrzcv6q4klcrrwh0dwv74pppf6206-openjdk-8u222-ga/lib/openjdk
/jre/lib/rt.jar:/nix/store/lm5rrzcv6q4klcrrwh0dwv74pppf6206-openjdk-8u222-ga/lib/openjdk/jre/lib/sunrsasign.jar:/nix/store/lm5rrzcv6q4klcrrwh0dwv74pppf6206-openjdk-8u222-ga/lib/openjdk/jre/lib/jsse.jar:/nix/store
/lm5rrzcv6q4klcrrwh0dwv74pppf6206-openjdk-8u222-ga/lib/openjdk/jre/lib/jce.jar:/nix/store/lm5rrzcv6q4klcrrwh0dwv74pppf6206-openjdk-8u222-ga/lib/openjdk/jre/lib/charsets.jar:/nix/store/lm5rrzcv6q4klcrrwh0dwv74pppf
6206-openjdk-8u222-ga/lib/openjdk/jre/lib/jfr.jar:/nix/store/lm5rrzcv6q4klcrrwh0dwv74pppf6206-openjdk-8u222-ga/lib/openjdk/jre/classes:/home/markus/.coursier/cache/v1/https/repo1.maven.org/maven2/org/scala-lang/s
cala-library/2.13.1/scala-library-2.13.1.jar -classpath /tmp/bar/diffx-test/target/scala-2.13/classes:/home/markus/.coursier/cache/v1/https/repo1.maven.org/maven2/org/scala-lang/scala-compiler/2.13.1/scala-compil
er-2.13.1.jar:/home/markus/.coursier/cache/v1/https/repo1.maven.org/maven2/jline/jline/2.14.6/jline-2.14.6.jar:/home/markus/.coursier/cache/v1/https/repo1.maven.org/maven2/com/softwaremill/diffx/diffx-core_2.13/0
.3.17/diffx-core_2.13-0.3.17.jar:/home/markus/.coursier/cache/v1/https/repo1.maven.org/maven2/com/propensive/mercator_2.13/0.2.1/mercator_2.13-0.2.1.jar:/home/markus/.coursier/cache/v1/https/repo1.maven.org/maven
2/org/fusesource/jansi/jansi/1.12/jansi-1.12.jar:/home/markus/.coursier/cache/v1/https/repo1.maven.org/maven2/org/scala-lang/scala-reflect/2.13.1/scala-reflect-2.13.1.jar:/home/markus/.coursier/cache/v1/https/rep
o1.maven.org/maven2/com/propensive/magnolia_2.13/0.12.6/magnolia_2.13-0.12.6.jar
[error]                                                                                                   
[error]   last tree to typer: Select(This(package diffx), Diff)
[error]        tree position: line 29 of /tmp/bar/diffx-test/src/main/scala/example/Hello.scala
[error]             tree tpe: com.softwaremill.diffx.Diff.type
[error]               symbol: object Diff in package diffx
[error]    symbol definition: object Diff (a ModuleSymbol)
[error]       symbol package: com.softwaremill.diffx
[error]        symbol owners: object Diff
[error]            call site: object TestError in package example in package example
[error] 
[error] == Source file context for tree position ==
[error] 
[error]     26 
[error]     27   val foo = Foo(Minute(5))
[error]     28 
[error]     29   Diff[Foo].apply(foo, foo)
[error]     30 }
[error]     31 
[error] /tmp/bar/diffx-test/src/main/scala/example/Hello.scala:29:7: could not find implicit value for evidence parameter of type com.softwaremill.diffx.Diff[example.TestError.Foo]
[error]   Diff[Foo].apply(foo, foo)
[error]       ^
[error] two errors found

Any ideas how to fix this?

Documentation for customizing subclass instances when deriving parent instances

Would be good if there are some docs on how to customize instances when derivation is involved. For example a user might try to use ignore on id field of a subclass like this:

sealed trait Parent
case class A(id: String, value: Int) extends Parent
case class B(id: String, value: Int) extends Parent

implicit val diffA: Diff[A] = Derived[Diff[A]].ignore(_.id)

val result: Parent = A("id1", 12)
val expected: Parent = A("id2", 12)

result should matchTo(expected)

However confusingly their Diff[A] instance doesn't work. They need to do this instead:

implicit val diffA: Derived[Diff[A]] = Derived(Diff.gen[A].ignore(_.id))

In order for the customized instance to be picked up by the magnolia derivation. (By using Diff.gen We also get a compiler warning from magnolia about "using fallback derivation for String" which is a separate issue but should be documented/fixed)

Do you think this is the proper way to resolve this? If so I'm happy to add to the docs.

LeftProjection.get warning (Magnolia issue)

We use fatal-warnings and using diffx produces the following warning:

[warn] /home/markus/repos/clones/diffx/core/src/test/scala/com/softwaremill/diffx/DiffTest.scala:375:22: method get in class LeftProjection is deprecated (since 2.13.0): use `Either.swap.getOrElse` instead

The issue is in magnolia: softwaremill/magnolia#192

Once a new version is released, it would be cool to update this library as well :)

Scala 2.11 cross compile

I would like to use this library with scala 2.11.
From quick look there is upstream dependency on neme-plugin.
Is it difficult to support 2.11?

equal lists don't match

    List("a") should equal(List("a"))

    List("a") should matchTo(List("a"))

the assertion fails but the shown diff shows no differences

image

Can't derive Diff for a case class with all default arguments

Example:

import com.softwaremill.diffx.Diff

// both args have defaults:
case class Buh(
  a: String = "",
  b: Int = 1
)

// fails
Diff[Buh]

Here is a runnable snippet:
https://scastie.scala-lang.org/kKEQ1SZzTmudSGJGvO5BGg

This broke with the Magnolia version upgrade: #93

I tried overriding Magnolia version to the latest, but it didn't help. Using latest Diffx with overriden Magnolia 0.12.8 does work.

So I know it's a problem with Magnolia, but I thought it's worth reporting here first. Let me know if I should report it there instead.

StackOverflowException during coproduct derivation when using semi-auto

Given following coproduct

sealed trait ACoproduct extends Product with Serializable
object ACoproduct {
  case class ProductA(id: String) extends ACoproduct
  case class ProductB(id: String) extends ACoproduct
}

when defining diff instance for such coproduct inside method:

  "should work for coproducts" in {
    implicit val dACoproduct: Diff[ACoproduct] = Diff.derived[ACoproduct]

    Diff[ACoproduct].apply(ProductA("1"), ProductA("1")) shouldBe Identical(ProductA("1"))
  }

Compilation fails with the following message:

DiffSemiautoTest.scala:43:62: forward reference extends over definition of value dACoproduct
[error]     implicit val dACoproduct: Diff[ACoproduct] = Diff.derived[ACoproduct]

Moving instance definition to the class level fixes the compilation but causes Stackoverflow exception in runtime:

[info] com.softwaremill.diffx.test.DiffSemiautoTest *** ABORTED ***
[info]   java.lang.StackOverflowError:
[info]   at magnolia.SealedTrait.rec$1(interface.scala:403)
[info]   at magnolia.SealedTrait.dispatch(interface.scala:408)
[info]   at com.softwaremill.diffx.generic.DiffMagnoliaDerivation.com$softwaremill$diffx$generic$DiffMagnoliaDerivation$$$anonfun$dispatch$1(DiffMagnoliaDerivation.scala:31)

Wrapping both the instance and the result type with the Derived class fixes that problem in both cases:

implicit val dACoproduct: Derived[Diff[ACoproduct]] = Derived(Diff.derived[ACoproduct])

but it doesn't seem that it should work like that.

Trouble deriving Diff for refined type

magnolia: could not infer Diff.Typeclass for refined type Id

This occurs in the following usage:

  object Foo extends RefinedSupport {
    implicit val diffId: Diff[Id]                 = Diff.derived[Id]
  }

Id is defined using zio-prelude's Subtype (similar to Newtype), e.g.:

  type Id = Id.Type
  object Id extends Subtype[TimeUUID]

  implicit val orderId: Order[Id]       = Order.by[Id, UUID](_.uuid)
  implicit val orderingId: Ordering[Id] = orderId.toOrdering

Any help or suggestions would be much appreciated ๐Ÿ˜„

proposal: rewrite semi-auto derivation to return regular diff instances

Why?
Because it is not needed for semi-auto derivation and adds only some noise.

The only problem is with coproducts because Diff is contravariant in T.

  implicit val dACoproduct: Diff[ACoproduct] = Diff.derived[ACoproduct]

Above code yields following error:

forward reference extends over definition of value dACoproduct
[error]     implicit val dACoproduct: Diff[ACoproduct] = Diff.derived[ACoproduct]
[error]        

One workaround for that would be to provide a custom macro for derivation of coproducts
More or less something like:

  implicit val dACoproduct: Diff[ACoproduct] = Diff.coproduct[ACoproduct](diffSubA, diffSubB)

Another way would be to delegate derivation of coproducts through MagnoliaDerivedMacro so it returns Derived[Diff] but that breaks symmetry.

Improve MatchResults error message.

Junit test results (e.g. in Jenkins) simply show "Matching error" as and a stack trace.

Ideally, this would present some high-level summary of the matching error.

Cannot compare scala.Range

import com.softwaremill.diffx._

object DiffTest {
  def main(args: Array[String]): Unit = {
    val v1 = Range(0, 1)
    val v2 = Range(0, 1)
    compare(v1, v2)
  }
}

Exception in thread "main" java.lang.IllegalArgumentException: The given value Range 0 until 1 is not a sub type of TypeName(scala.collection.immutable,Range,List())
at magnolia.SealedTrait.rec$1(interface.scala:270)
at magnolia.SealedTrait.dispatch(interface.scala:272)
at com.softwaremill.diffx.DiffMagnoliaDerivation

Multiline strings comparison

When you compare multiline strings, diffx says that they are different (obviously). But the output is hard to read.

Sample test:

import com.softwaremill.diffx.scalatest.DiffMatcher
import org.scalatest.freespec.AnyFreeSpec
import org.scalatest.matchers.should.Matchers

class StringComparisonTestSuite extends AnyFreeSpec with Matchers with DiffMatcher {
  "multiline strings" in {
    val s1 = """a1
b2
c3"""

    val s2 = """a1
d2
c3"""

    s1 should matchTo(s2)
  }
}

will print:

a1
b2
c3 -> a1
d2
c3

(red before "->" and green after).

It would be great to have other output, e.g.:

a1
b2 -> d2
c3

The simplest solution IMO is to split strings by lines and compare them as lists.

What do you think?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.