From 2de4f5a796be3bed63bfcea4c888137c9b8b9f91 Mon Sep 17 00:00:00 2001 From: Eli Kasik Date: Tue, 16 Jan 2024 11:37:29 -0500 Subject: [PATCH] Add comprehensive tests --- .gitignore | 3 +- .../vulcan/generic/AvroFieldDefaultSpec.scala | 99 ++++++++++++++++++- .../test/scala/vulcan/generic/CodecBase.scala | 4 + 3 files changed, 103 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index 0b4d3394..35140cfc 100644 --- a/.gitignore +++ b/.gitignore @@ -8,4 +8,5 @@ target/ .metals/ .vscode/ .bloop/ -metals.sbt \ No newline at end of file +metals.sbt +.idea/ \ No newline at end of file diff --git a/modules/generic/src/test/scala/vulcan/generic/AvroFieldDefaultSpec.scala b/modules/generic/src/test/scala/vulcan/generic/AvroFieldDefaultSpec.scala index 59d959bb..f44f6160 100644 --- a/modules/generic/src/test/scala/vulcan/generic/AvroFieldDefaultSpec.scala +++ b/modules/generic/src/test/scala/vulcan/generic/AvroFieldDefaultSpec.scala @@ -6,7 +6,39 @@ package vulcan.generic -import vulcan.Codec +import vulcan.{AvroError, Codec} + + +sealed trait Enum extends Product { + self => + def value: String = self.productPrefix +} + +object Enum { + case object A extends Enum + + case object B extends Enum + + implicit val codec: Codec[Enum] = deriveEnum( + symbols = List(A.value, B.value), + encode = _.value, + decode = { + case "A" => Right(A) + case "B" => Right(B) + case other => Left(AvroError(s"Invalid S: $other")) + } + ) +} + +sealed trait Union + +object Union { + case class A(a: Int) extends Union + + case class B(b: String) extends Union + + implicit val codec: Codec[Union] = Codec.derive +} case class Foo( a: Int = 1, @@ -17,12 +49,75 @@ object Foo { implicit val codec: Codec[Foo] = Codec.derive } +case class InvalidDefault2( + a: Option[String] = Some("foo") +) +object InvalidDefault2 { + implicit val codec: Codec[InvalidDefault2] = Codec.derive +} + +case class HasSFirst( + s: Enum = Enum.A +) +object HasSFirst { + implicit val codec: Codec[HasSFirst] = Codec.derive +} + +case class HasSSecond( + s: Enum = Enum.B +) +object HasSSecond { + implicit val codec: Codec[HasSSecond] = Codec.derive +} + +case class HasUnion( + u: Union = Union.A(1) +) +object HasUnion { + implicit val codec: Codec[HasUnion] = Codec.derive +} + +case class Empty() +object Empty { + implicit val codec: Codec[Empty] = Codec.derive +} + +case class HasUnionSecond( + u: Union = Union.B("foo") +) +object HasUnionSecond { + implicit val codec: Codec[HasUnionSecond] = Codec.derive +} + final class AvroFieldDefaultSpec extends CodecBase { describe("AvroFieldDefault") { it("should create a schema with a default for a field") { - assert(Foo.codec.schema.exists(_.getField("a").defaultVal() == 1)) assert(Foo.codec.schema.exists(_.getField("b").defaultVal() == "foo")) } + + it("should fail when annotating an Option") { + assertSchemaError[InvalidDefault2] + } + + it("should succeed when annotating an enum first element") { + assert(HasSFirst.codec.schema.exists(_.getField("s").defaultVal() == "A")) + } + + it("should succeed when annotating an enum second element") { + assert(HasSSecond.codec.schema.exists(_.getField("s").defaultVal() == "B")) + } + + it("should succeed with the first member of a union"){ + assertSchemaIs[HasUnion]( + """{"type":"record","name":"HasUnion","namespace":"vulcan.generic","fields":[{"name":"u","type":[{"type":"record","name":"A","namespace":"vulcan.generic.Union","fields":[{"name":"a","type":"int"}]},{"type":"record","name":"B","namespace":"vulcan.generic.Union","fields":[{"name":"b","type":"string"}]}],"default":{"a":1}}]}""" + ) + val result = unsafeDecode[HasUnion](unsafeEncode[Empty](Empty())) + assert(result == HasUnion(Union.A(1))) + } + + it("should fail with the second member of a union"){ + assertSchemaError[HasUnionSecond] + } } } diff --git a/modules/generic/src/test/scala/vulcan/generic/CodecBase.scala b/modules/generic/src/test/scala/vulcan/generic/CodecBase.scala index 3b66e529..1b4122ea 100644 --- a/modules/generic/src/test/scala/vulcan/generic/CodecBase.scala +++ b/modules/generic/src/test/scala/vulcan/generic/CodecBase.scala @@ -51,6 +51,10 @@ class CodecBase extends AnyFunSpec with ScalaCheckPropertyChecks with EitherValu )(implicit codec: Codec[A]): Assertion = assert(codec.schema.swap.value.message == expectedErrorMessage) + + def assertSchemaError[A](implicit codec: Codec[A]): Assertion = + assert(codec.schema.isLeft, codec.schema) + def assertDecodeError[A]( value: Any, schema: Schema,