Search code examples
scalacirce

Decoded circe array inside case class always failing case class comparison test?


For this case class:

import io.circe.generic.JsonCodec

@JsonCodec
case class Stuff(things: Array[String])

This test passes ok (case class to json test):

import io.circe.parser.decode
import io.circe.syntax._
import org.scalatest._

val caseClass = Stuff(things = Array("one", "two"))

val json = caseClass.asJson.spaces2

json shouldEqual
      """{
         | "things" : [
         |   "one",
         |   "two"
         | ]
         |}""".stripMargin

However, this is failing (json to case class test)

import io.circe.parser.decode
import io.circe.syntax._
import org.scalatest._

val json =
      """{
         | "things" : [
         |   "one",
         |   "two"
         | ]
         |}""".stripMargin

val caseClass = Right(decode[Stuff](json))

caseClass shouldEqual Stuff(things = Array("one", "two"))

Stepping through it in a debugger, it seems that the array doesn not get decoded as I would expect, it seems to be the object identity/memory address, which is always different, and so my test is failing:

[Ljava.lang.String;@2fa7ae9

Note this just seems to happen for Arrays, there is lots more stuff in my json blob that I have left out for this example - Maps and nested case-classes all get decoded and can be compared ok, its only when Arrays are added that the comparison fails - am I missing something?


Solution

  • This is more a Scala issue (or a ScalaTest issue) than a circe one. Scala's == method on arrays uses reference equality, and while ScalaTest's shouldEqual will work "correctly" on arrays (i.e. it'll compare contents rather than references), it will still use == for array members when comparing two case class instances.

    There are lots of ways you could work around this: by writing your own Equality instance for Stuff, by comparing caseClass.things shouldEqual Array("one", "two"), etc. Having a mutable collection (like Array) as a case class member is not idiomatic Scala and is almost certainly a bad idea, though, and I'd strongly suggest fixing this issue by changing it to something like List or Vector.