Skip to content

Instantly share code, notes, and snippets.

@dacr
Last active May 27, 2023 06:28
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dacr/79d03a9883fb2dc9c4d85e6f3711a002 to your computer and use it in GitHub Desktop.
Save dacr/79d03a9883fb2dc9c4d85e6f3711a002 to your computer and use it in GitHub Desktop.
Circe scala json API cookbook as unit test cases. / published by https://github.com/dacr/code-examples-manager #b22ead77-d362-409d-baf7-8070a5def33f/17ce636b2c8a612692f562118dd9c8ddd44b482
// summary : Circe scala json API cookbook as unit test cases.
// keywords : scala, scalatest, circe, json, @testable
// publish : gist
// authors : David Crosson
// license : Apache NON-AI License Version 2.0 (https://raw.githubusercontent.com/non-ai-licenses/non-ai-licenses/main/NON-AI-APACHE2)
// id : b22ead77-d362-409d-baf7-8070a5def33f
// created-on : 2019-05-25T20:49:38Z
// managed-by : https://github.com/dacr/code-examples-manager
// run-with : scala-cli $file
// ---------------------
//> using scala "3.3.0"
//> using dep "org.scalatest::scalatest:3.2.16"
//> using dep "io.circe::circe-parser:0.14.1"
//> using dep "io.circe::circe-generic:0.14.1"
//> using objectWrapper
// ---------------------
import io.circe.*
import io.circe.generic.auto.*
import io.circe.parser.*
import io.circe.syntax.*
import io.circe.Encoder.*
import org.scalatest.*
import matchers.*
import OptionValues.*
import java.time.OffsetDateTime
import java.util.UUID
// =============================================================================
case class Someone(name: String, age: Int)
case class Event(when: OffsetDateTime, who: Someone, what: String)
case class SomethingOptional(id: String, content: Option[String], items: Option[Array[String]])
case class Record(id: String, items: List[String])
case class RecordWithUUID(uuid: UUID)
// =============================================================================
class JsonCirceCookBook extends flatspec.AnyFlatSpec with should.Matchers {
override def suiteName = "JsonCirceCookBook"
"circe" should "parse json strings" in {
val json = """{"name":"John Doe", "age":42}"""
val doc = parse(json).getOrElse(Json.Null)
val cursor = doc.hcursor
cursor.get[String]("name").toOption.value should equal("John Doe")
}
it should "parse complex data types perfectly" in {
val json = """{"who":{"name":"John Doe", "age":42}, "what":"new", "when":"2020-10-24T08:56:36.294Z"}"""
val event = parse(json).flatMap(_.as[Event]).toOption
event.value.who.name shouldBe "John Doe"
event.value.who.age shouldBe 42
event.value.what shouldBe "new"
event.value.when shouldBe OffsetDateTime.parse("2020-10-24T08:56:36.294Z")
}
it should "support optional field" in {
val json1 = """{"id":"42"}"""
val json2 = """{"id":"42", "content":"yes", "items":["a","b"]}"""
parse(json1).flatMap(_.as[SomethingOptional]).toOption.value.content shouldBe None
parse(json1).flatMap(_.as[SomethingOptional]).toOption.value.items shouldBe None
parse(json2).flatMap(_.as[SomethingOptional]).toOption.value.content shouldBe Some("yes")
parse(json2).flatMap(_.as[SomethingOptional]).toOption.value.items.value.size shouldBe 2
}
it should "support arrays" in {
val json = """{"id":"42", "items":["yes", "no"]}"""
parse(json).flatMap(_.as[Record]).toOption.value.id shouldBe "42"
}
it should "support uuid" in {
val json = """{"uuid":"c5e4e9c6-99d0-4bad-ba14-c9b1c20f5530"}"""
parse(json).flatMap(_.as[RecordWithUUID]).toOption.value.uuid shouldBe UUID.fromString("c5e4e9c6-99d0-4bad-ba14-c9b1c20f5530")
}
it should "be able to handle supplementary fields" in {
val json = """{"name":"joe", "age":42, "gender":"male"}"""
parse(json).flatMap(_.as[Someone]).toOption.value.name shouldBe "joe"
}
it should "AST" in {
val json = """{"name":"joe"}"""
val result = parse(json).flatMap(_.as[Json]).toOption.value
val job = result.asObject
job.flatMap(_.apply("name")).flatMap(_.asString).value shouldBe "joe"
}
it should "be possible to create a JsonObject by hand using generic JsonObject" in {
val job1:Json = JsonObject().add("name", encodeString("joe")).asJson
val job2:Json =
JsonObject()
.add("name", encodeString("joe"))
.add("address",
JsonObject()
.add("country", encodeString("france"))
.asJson
).asJson
val job3:Json =
JsonObject("name"->encodeString("joe")).asJson
val job4:Json = Json.fromJsonObject(JsonObject("name"->encodeString("joe")))
}
it should "be possible to create a JsonObject by hand using Map data structure" in {
//val scason = Map("name"->"joe", "address"->Map("country"->"spain"))
//val job1:Json = scason.asJson
//val job2 = io.circe.
info("This is not possible by choice & design !")
}
}
org.scalatest.tools.Runner.main(Array("-oDF", "-s", classOf[JsonCirceCookBook].getName))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment