Skip to main content

RoundTripTester

Module​

"io.kevinlee" %% "extras-hedgehog-circe" % "0.57.0" % Test

or for Scala.js:

"io.kevinlee" %%% "extras-hedgehog-circe" % "0.57.0" % Test

Test JSON Encoder and Decoder​

RoundTripTester tests the available Circe JSON Encoder and Decoder by:

  • Encoding the given type A into a JSON String using Encoder[A].
  • Decoding the JSON String back into the original type A using Decoder[A].
RoundTripTester(sometypeA).test()
// hedgehog.Result

Examples:​

import extras.hedgehog.circe.RoundTripTester

import cats._
import io.circe._

import hedgehog._
import hedgehog.runner._

object SomethingSpec extends Properties {
override def tests: List[Test] = List(
property("round-trip test Something JSON Codec", roundTripTest),
property("round-trip test Something JSON Codec - failure case", roundTripTestWithDecodeFailure),
property("round-trip test Something JSON Codec - failure case (indent 8)", roundTripTestWithDecodeFailureIndent8),
)

def roundTripTest: Property =
for {
something <- genSomething.log("something")
} yield {
RoundTripTester(something).test()
}

def roundTripTestWithDecodeFailure: Property =
for {
something <- genSomething
.map(something => SomethingWithDecodeFailure(something.id, something.name))
.log("something")
} yield {
RoundTripTester(something).test()
}

def roundTripTestWithDecodeFailureIndent8: Property =
for {
something <- genSomething
.map(something => SomethingWithDecodeFailure(something.id, something.name))
.log("something")
} yield {
RoundTripTester(something)
.indent(8)
.test()
}

def genSomething: Gen[Something] =
for {
id <- Gen.int(Range.linear(1, 100))
name <- Gen.string(Gen.unicode, Range.linear(3, 20))
} yield Something(id, name)


final case class Something(id: Int, name: String)
object Something {
implicit val somethingShow: Show[Something] =
something => s"Something(id = ${something.id.toString}, name = ${something.name})"

implicit val somethingCodec: Codec[Something] = io.circe.generic.semiauto.deriveCodec
}


final case class SomethingWithDecodeFailure(id: Int, name: String)

object SomethingWithDecodeFailure {
implicit val somethingWithDecodeFailureShow: Show[SomethingWithDecodeFailure] =
somethingWithDecodeFailure =>
List(
s"id = ${somethingWithDecodeFailure.id.toString}",
s"name = ${somethingWithDecodeFailure.name}",
).mkString(
"SomethingWithDecodeFailure(",
", ",
")",
)

implicit val somethingWithDecodeFailureEncoder: Encoder[SomethingWithDecodeFailure] =
io.circe.generic.semiauto.deriveEncoder

implicit val somethingWithDecodeFailureDecoder: Decoder[SomethingWithDecodeFailure] =
Decoder.instance(c =>
for {
id <- c.downField("blah").as[Int]
name <- c.downField("name").as[String]
} yield SomethingWithDecodeFailure(id, name)
)
}

}


// This is only for this document so you don't need this.
SomethingSpec.main(Array.empty)
// Using random seed: 160674243108
// + repl.MdocSession$MdocApp0$SomethingSpec$.round-trip test Something JSON Codec: OK, passed 100 tests
// - repl.MdocSession$MdocApp0$SomethingSpec$.round-trip test Something JSON Codec - failure case: Falsified after 0 passed tests
// > something: SomethingWithDecodeFailure(1,���)
// > modules/extras-hedgehog-circe/jvm/src/main/scala-2/extras/hedgehog/circe/RoundTripTester.scala:40
// > at repl.MdocSession$MdocApp0$SomethingSpec$.round-trip test Something JSON Codec - failure case(RoundTripTester.scala:40)
// > Round-trip test for SomethingSpec.SomethingWithDecodeFailure failed with error:
// > > Error: DecodingFailure at .blah: Missing required field
// > > ---
// > > Input: SomethingWithDecodeFailure(id = 1, name = ���)
// > > ---
// > > JSON: {
// > "id" : 1,
// > "name" : "\u0000\u0000\u0000"
// > }
// > >
// - repl.MdocSession$MdocApp0$SomethingSpec$.round-trip test Something JSON Codec - failure case (indent 8): Falsified after 0 passed tests
// > something: SomethingWithDecodeFailure(1,���)
// > modules/extras-hedgehog-circe/jvm/src/main/scala-2/extras/hedgehog/circe/RoundTripTester.scala:40
// > at repl.MdocSession$MdocApp0$SomethingSpec$.round-trip test Something JSON Codec - failure case (indent 8)(RoundTripTester.scala:40)
// > Round-trip test for SomethingSpec.SomethingWithDecodeFailure failed with error:
// > > Error: DecodingFailure at .blah: Missing required field
// > > ---
// > > Input: SomethingWithDecodeFailure(id = 1, name = ���)
// > > ---
// > > JSON: {
// > "id" : 1,
// > "name" : "\u0000\u0000\u0000"
// > }
// > >