Created
November 28, 2018 07:37
-
-
Save Fristi/b2378c0aa321b652bc96a96872295d56 to your computer and use it in GitHub Desktop.
specs2 `Diffable` magnolia derivation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import magnolia.{CaseClass, Magnolia, SealedTrait} | |
import org.specs2.matcher.describe._ | |
import scala.language.experimental.macros | |
object DiffableDerivation { | |
/** binds the Magnolia macro to this derivation object */ | |
implicit def genDiffable[T]: Diffable[T] = macro Magnolia.gen[T] | |
/** type constructor for new instances of the typeclass */ | |
type Typeclass[T] = Diffable[T] | |
/** defines how new Arbitrary typeclasses for nested case classes should be constructed */ | |
def combine[T](ctx: CaseClass[Diffable, T]): Diffable[T] = | |
new Diffable[T] { | |
override def diff(actual: T, expected: T): ComparisonResult = { | |
val res = ctx.parameters.map { param => | |
val result = param.typeclass.diff(param.dereference(actual), param.dereference(expected)) | |
CaseClassPropertyComparison(param.label, result, result.identical) | |
} | |
if (res.forall(_.identical)) CaseClassIdentical(ctx.typeName.short) | |
else CaseClassDifferent(ctx.typeName.short, res) | |
} | |
} | |
/** Given a sealed trait, picks a random Arbitrary instance for one of the elements*/ | |
def dispatch[T](ctx: SealedTrait[Diffable, T]): Diffable[T] = new Diffable[T] { | |
override def diff(actual: T, expected: T): ComparisonResult = ctx.dispatch(actual) { sub => | |
if (sub.cast.isDefinedAt(expected)) sub.typeclass.diff(sub.cast(actual), sub.cast(expected)) | |
else OtherDifferent(actual, expected) | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import org.specs2.matcher.Matchers | |
import org.specs2.mutable.Specification | |
import DiffableDerivation._ | |
import org.specs2.matcher.describe._ | |
import scala.collection.mutable.ArrayBuffer | |
class DiffableDerivationSpec extends Specification with Matchers { | |
"Diffable type class derivation" >> { | |
"should derive correctly for product type" >> { | |
"identical" >> { | |
genDiffable[Address].diff(Address("a", 2), Address("a", 2)) must beEqualTo(CaseClassIdentical("Address")) | |
} | |
"different" >> { | |
genDiffable[Address].diff(Address("a", 2), Address("a", 4)) must beEqualTo(CaseClassDifferent("Address",ArrayBuffer(CaseClassPropertyComparison("street",PrimitiveIdentical("a"),true), CaseClassPropertyComparison("houseNumber",PrimitiveDifference(2,4),false)))) | |
} | |
} | |
"should derive correctly for nested types" >> { | |
"identical" >> { | |
genDiffable[Person].diff(Person("Mark", 1337, Address("a", 2)), Person("Mark", 1337, Address("a", 2))) must beEqualTo(CaseClassIdentical("Person")) | |
} | |
"different" >> { | |
genDiffable[Person].diff(Person("Mark", 1337, Address("a", 2)), Person("Mark", 1338, Address("a", 3))) must beEqualTo( | |
CaseClassDifferent("Person", | |
ArrayBuffer( | |
CaseClassPropertyComparison("name",PrimitiveIdentical("Mark"),true), | |
CaseClassPropertyComparison("age",PrimitiveDifference(1337,1338),false), | |
CaseClassPropertyComparison("address", CaseClassDifferent("Address", | |
ArrayBuffer( | |
CaseClassPropertyComparison("street",PrimitiveIdentical("a"),true), | |
CaseClassPropertyComparison("houseNumber",PrimitiveDifference(2,3),false) | |
)), false | |
) | |
))) | |
} | |
} | |
} | |
} | |
case class Person(name: String, age: Int, address: Address) | |
case class Address(street: String, houseNumber: Int) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
object Refined { | |
implicit def diffableRefinedType[S, P](implicit S: Diffable[S]): Diffable[Refined[S, P]] = new Diffable[Refined[S, P]] { | |
override def diff(actual: Refined[S, P], expected: Refined[S, P]): ComparisonResult = S.diff(actual.value, expected.value) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment