Basic Differs
This page covers basic Differ instances, including value Differs, collection Differs, and Differs for types that
should always be ignored.
The examples below assume the following imports:
import difflicious.*
import difflicious.implicits.*
Value Differs / Differ.useEquals
For basic types like Int, Double and String we typically can compare them directly, for example by using the
equals method.
If you have a type where you don't want any advanced diffing, then you can use Differ.useEquals to make a
Differ instance for it.
case class MyInt(i: Int)
object MyInt {
implicit val differ: Differ[MyInt] = Differ.useEquals[MyInt](valueToString = _.toString)
}
MyInt.differ.diff(MyInt(1), MyInt(2))
MyInt(1) -> MyInt(2)
Collection Differs
Difflicious provides Differ instances for common collection shapes such as sequences, maps, and sets.
case class Person(name: String, age: Int)
object Person {
implicit val differ: Differ[Person] = Differ.derived[Person]
}
Seq Differ
Differs for sequences allow diffing immutable sequences like Seq, List, and Vector.
By default, Seq Differs will match elements by their index in the sequence.
In the example below:
- Bob's age is different
- Alice isn't expected to be in the list
- Charles is expected but missing
val alice = Person("Alice", 30)
val bob = Person("Bob", 25)
val bob50 = Person("Bob", 50)
val charles = Person("Charles", 80)
Differ.seqDiffer[List, Person].diff(
List(alice, bob50),
List(alice, bob, charles)
)
List( Person( name: "Alice", age: 30, ), Person( name: "Bob", age: 50 -> 25, ), Person( name: "Charles", age: 80, ), )
Pair by field
In many test scenarios we actually don't care about order of elements, as long as the two sequences contain the same elements. One example of this is inserting multiple records into a database and then retrieving them, where you expect the same records to be returned but not necessarily in the original order.
In this case, you can configure a Differ to pair by a field instead.
val differByName = Differ[List[Person]].pairBy(_.name)
differByName.diff(
List(bob50, charles, alice),
List(alice, bob, charles)
)
When we match by a person's name instead of index, we can now easily spot that Bob has the wrong age.
List( Person( name: "Bob", age: 50 -> 25, ), Person( name: "Charles", age: 80, ), Person( name: "Alice", age: 30, ), )
Map Differ
Map Differs pair entries with the same keys and compare the values. Missing key-values will also be reported in the result.
It requires:
- a
ValueDifferinstance for the map key type, for display purposes - a
Differinstance for the map value type
Differ[Map[String, Person]].diff(
Map(
"a" -> alice,
"b" -> bob
),
Map(
"b" -> bob50,
"c" -> charles
),
)
Map( "a" -> Person( name: "Alice", age: 30, ), "b" -> Person( name: "Bob", age: 25 -> 50, ), "c" -> Person( name: "Charles", age: 80, ), )
Set Differ
Set Differs can diff two Sets by pairing the set elements and diffing them.
By default, the pairing is based on matching elements that are equal to each other using equals.
However, you most likely want to pair elements using a field on an element instead for better diff reports.
Pair by field
For the best error reporting, you want to configure SetDiffer to pair by a field.
val differByName: Differ[Set[Person]] = Differ[Set[Person]].pairBy(_.name)
differByName.diff(
Set(bob50, charles, alice),
Set(alice, bob, charles)
)
Set( Person( name: "Bob", age: 50 -> 25, ), Person( name: "Charles", age: 80, ), Person( name: "Alice", age: 30, ), )
Always Ignored Differ
Sometimes for certain types you can't really compare them, for example when the type is not a plain data structure.
In that case you can use Differ.alwaysIgnore.
class CantCompare()
val alwaysIgnoredDiffer: Differ[CantCompare] = Differ.alwaysIgnore[CantCompare]