diff --git a/build.sbt b/build.sbt index ed12c155..0679691c 100644 --- a/build.sbt +++ b/build.sbt @@ -11,15 +11,16 @@ val compilerOptions = Seq( "-language:higherKinds", "-unchecked", "-Ywarn-dead-code", - "-Ywarn-numeric-widen" + "-Ywarn-numeric-widen", + "-Yrangepos" ) val circeVersion = "0.13.0" val paradiseVersion = "2.1.1" val jawnVersion = "1.0.0" -val scalaTestVersion = "3.2.3" -val scalaTestPlusVersion = "3.2.2.0" +val munitVersion = "0.7.20" +val disciplineMunitVersion = "1.0.4" val previousCirceGenericExtrasVersion = "0.12.2" @@ -84,10 +85,12 @@ lazy val genericExtras = crossProject(JSPlatform, JVMPlatform) "io.circe" %%% "circe-generic" % circeVersion, "io.circe" %%% "circe-literal" % circeVersion % Test, "io.circe" %%% "circe-testing" % circeVersion % Test, - "org.scalatest" %%% "scalatest" % scalaTestVersion % Test, - "org.scalatestplus" %%% "scalacheck-1-14" % scalaTestPlusVersion % Test, + "org.scalameta" %%% "munit" % munitVersion % Test, + "org.scalameta" %%% "munit-scalacheck" % munitVersion % Test, + "org.typelevel" %% "discipline-munit" % disciplineMunitVersion % Test, "org.typelevel" %% "jawn-parser" % jawnVersion % Test ), + testFrameworks := List(new TestFramework("munit.Framework")), // Override setting so Scalatest is disabled ghpagesNoJekyll := true, docMappingsApiDir := "api", addMappingsToSiteDir(mappings in (Compile, packageDoc), docMappingsApiDir) diff --git a/generic-extras/src/test/scala/io/circe/generic/extras/CirceSuite.scala b/generic-extras/src/test/scala/io/circe/generic/extras/CirceSuite.scala index c6559785..2872b95b 100644 --- a/generic-extras/src/test/scala/io/circe/generic/extras/CirceSuite.scala +++ b/generic-extras/src/test/scala/io/circe/generic/extras/CirceSuite.scala @@ -3,17 +3,16 @@ package io.circe.generic.extras import cats.instances._ import cats.syntax._ import io.circe.testing.{ ArbitraryInstances, EqInstances } -import org.scalatest.flatspec.AnyFlatSpec -import org.scalatestplus.scalacheck.{ Checkers, ScalaCheckDrivenPropertyChecks } import org.typelevel.discipline.Laws + import scala.language.implicitConversions +import munit.{ DisciplineSuite, Location, ScalaCheckSuite } /** * An opinionated stack of traits to improve consistency and reduce boilerplate in circe tests. */ trait CirceSuite - extends AnyFlatSpec - with ScalaCheckDrivenPropertyChecks + extends DisciplineSuite with AllInstances with AllInstancesBinCompat0 with AllInstancesBinCompat1 @@ -33,13 +32,5 @@ trait CirceSuite with ArbitraryInstances with EqInstances { - override def convertToEqualizer[T](left: T): Equalizer[T] = - sys.error("Intentionally ambiguous implicit for Equalizer") - implicit def prioritizedCatsSyntaxEither[A, B](eab: Either[A, B]): EitherOps[A, B] = new EitherOps(eab) - - def checkLaws(name: String, ruleSet: Laws#RuleSet): Unit = ruleSet.all.properties.zipWithIndex.foreach { - case ((id, prop), 0) => name should s"obey $id" in Checkers.check(prop) - case ((id, prop), _) => it should s"obey $id" in Checkers.check(prop) - } } diff --git a/generic-extras/src/test/scala/io/circe/generic/extras/ConfiguredAutoDerivedSuite.scala b/generic-extras/src/test/scala/io/circe/generic/extras/ConfiguredAutoDerivedSuite.scala index 0fa3c3e0..e447df51 100644 --- a/generic-extras/src/test/scala/io/circe/generic/extras/ConfiguredAutoDerivedSuite.scala +++ b/generic-extras/src/test/scala/io/circe/generic/extras/ConfiguredAutoDerivedSuite.scala @@ -9,6 +9,7 @@ import io.circe.literal._ import io.circe.testing.CodecTests import org.scalacheck.{ Arbitrary, Gen } import org.scalacheck.Arbitrary.arbitrary +import org.scalacheck.Prop.forAll import examples._ @@ -49,11 +50,11 @@ class ConfiguredAutoDerivedSuite extends CirceSuite { { implicit val config: Configuration = Configuration.default - checkLaws("Codec[ConfigExampleBase] (default configuration)", CodecTests[ConfigExampleBase].codec) + checkAll("Codec[ConfigExampleBase] (default configuration)", CodecTests[ConfigExampleBase].codec) } - "Configuration#transformMemberNames" should "support member name transformation using snake_case" in forAll { - foo: ConfigExampleFoo => + property("Configuration#transformMemberNames should support member name transformation using snake_case") { + forAll { foo: ConfigExampleFoo => implicit val snakeCaseConfig: Configuration = Configuration.default.withSnakeCaseMemberNames import foo._ @@ -61,10 +62,11 @@ class ConfiguredAutoDerivedSuite extends CirceSuite { assert(Encoder[ConfigExampleFoo].apply(foo) === json) assert(Decoder[ConfigExampleFoo].decodeJson(json) === Right(foo)) + } } - "Configuration#transformMemberNames" should "support member name transformation using SCREAMING_SNAKE_CASE" in forAll { - foo: ConfigExampleFoo => + property("Configuration#transformMemberNames should support member name transformation using SCREAMING_SNAKE_CASE") { + forAll { foo: ConfigExampleFoo => implicit val snakeCaseConfig: Configuration = Configuration.default.withScreamingSnakeCaseMemberNames import foo._ @@ -72,10 +74,11 @@ class ConfiguredAutoDerivedSuite extends CirceSuite { assert(Encoder[ConfigExampleFoo].apply(foo) === json) assert(Decoder[ConfigExampleFoo].decodeJson(json) === Right(foo)) + } } - "Configuration#transformMemberNames" should "support member name transformation using kebab-case" in forAll { - foo: ConfigExampleFoo => + property("Configuration#transformMemberNames should support member name transformation using kebab-case") { + forAll { foo: ConfigExampleFoo => implicit val kebabCaseConfig: Configuration = Configuration.default.withKebabCaseMemberNames import foo._ @@ -83,9 +86,10 @@ class ConfiguredAutoDerivedSuite extends CirceSuite { assert(Encoder[ConfigExampleFoo].apply(foo) === json) assert(Decoder[ConfigExampleFoo].decodeJson(json) === Right(foo)) + } } - "Configuration#useDefaults" should "support using default values during decoding" in { + property("Configuration#useDefaults should support using default values during decoding") { forAll { (f: String, b: Double) => implicit val withDefaultsConfig: Configuration = Configuration.default.withDefaults @@ -111,34 +115,34 @@ class ConfiguredAutoDerivedSuite extends CirceSuite { implicit val customConfig: Configuration = Configuration.default.withDefaults - "Option[T] without default" should "be None if null decoded" in { + test("Option[T] without default should be None if null decoded") { val json = json"""{ "a": null }""" assert(Decoder[FooNoDefault].decodeJson(json) === Right(FooNoDefault(None, "b"))) } - "Option[T] without default" should "be None if missing key decoded" in { + test("Option[T] without default should be None if missing key decoded") { val json = json"""{}""" assert(Decoder[FooNoDefault].decodeJson(json) === Right(FooNoDefault(None, "b"))) } - "Option[T] with default" should "be None if null decoded" in { + test("Option[T] with default should be None if null decoded") { val json = json"""{ "a": null }""" assert(Decoder[FooWithDefault].decodeJson(json) === Right(FooWithDefault(None, "b"))) } - "Option[T] with default" should "be default value if missing key decoded" in { + test("Option[T] with default should be default value if missing key decoded") { val json = json"""{}""" assert(Decoder[FooWithDefault].decodeJson(json) === Right(FooWithDefault(Some(0), "b"))) assert(Decoder[FooWithDefault].decodeAccumulating(json.hcursor) === Validated.valid(FooWithDefault(Some(0), "b"))) } - "Value with default" should "be default value if value is null" in { + test("Value with default should be default value if value is null") { val json = json"""{"b": null}""" assert(Decoder[FooWithDefault].decodeJson(json) === Right(FooWithDefault(Some(0), "b"))) assert(Decoder[FooWithDefault].decodeAccumulating(json.hcursor) === Validated.valid(FooWithDefault(Some(0), "b"))) } - "Option[T] with default" should "fail to decode if type in json is not correct" in { + test("Option[T] with default should fail to decode if type in json is not correct") { val json = json"""{"a": "NotAnInt"}""" assert(Decoder[FooWithDefault].decodeJson(json) === Left(DecodingFailure("Int", List(DownField("a"))))) assert( @@ -147,7 +151,7 @@ class ConfiguredAutoDerivedSuite extends CirceSuite { ) } - "Field with default" should "fail to decode it type in json is not correct" in { + test("Field with default should fail to decode it type in json is not correct") { val json = json"""{"b": 1}""" assert(Decoder[FooWithDefault].decodeJson(json) === Left(DecodingFailure("String", List(DownField("b"))))) assert( @@ -158,7 +162,7 @@ class ConfiguredAutoDerivedSuite extends CirceSuite { } } - "Configuration#discriminator" should "support a field indicating constructor" in { + property("Configuration#discriminator should support a field indicating constructor") { forAll { foo: ConfigExampleFoo => implicit val withDefaultsConfig: Configuration = Configuration.default.withDiscriminator("type") @@ -170,8 +174,8 @@ class ConfiguredAutoDerivedSuite extends CirceSuite { } } - "Configuration#transformConstructorNames" should "support constructor name transformation with snake_case" in forAll { - foo: ConfigExampleFoo => + property("Configuration#transformConstructorNames should support constructor name transformation with snake_case") { + forAll { foo: ConfigExampleFoo => implicit val snakeCaseConfig: Configuration = Configuration.default.withDiscriminator("type").withSnakeCaseConstructorNames @@ -180,10 +184,13 @@ class ConfiguredAutoDerivedSuite extends CirceSuite { assert(Encoder[ConfigExampleBase].apply(foo) === json) assert(Decoder[ConfigExampleBase].decodeJson(json) === Right(foo)) + } } - "Configuration#transformConstructorNames" should "support constructor name transformation with SCREAMING_SNAKE_CASE" in forAll { - foo: ConfigExampleFoo => + property( + "Configuration#transformConstructorNames should support constructor name transformation with SCREAMING_SNAKE_CASE" + ) { + forAll { foo: ConfigExampleFoo => implicit val snakeCaseConfig: Configuration = Configuration.default.withDiscriminator("type").withScreamingSnakeCaseConstructorNames @@ -192,10 +199,11 @@ class ConfiguredAutoDerivedSuite extends CirceSuite { assert(Encoder[ConfigExampleBase].apply(foo) === json) assert(Decoder[ConfigExampleBase].decodeJson(json) === Right(foo)) + } } - "Configuration#transformConstructorNames" should "support constructor name transformation with kebab-case" in forAll { - foo: ConfigExampleFoo => + property("Configuration#transformConstructorNames should support constructor name transformation with kebab-case") { + forAll { foo: ConfigExampleFoo => implicit val kebabCaseConfig: Configuration = Configuration.default.withDiscriminator("type").withKebabCaseConstructorNames @@ -204,29 +212,32 @@ class ConfiguredAutoDerivedSuite extends CirceSuite { assert(Encoder[ConfigExampleBase].apply(foo) === json) assert(Decoder[ConfigExampleBase].decodeJson(json) === Right(foo)) + } } - "Configuration options" should "work together" in forAll { (f: String, b: Double) => - implicit val customConfig: Configuration = - Configuration.default.withSnakeCaseMemberNames.withDefaults.withDiscriminator("type") + property("Configuration options should work together") { + forAll { (f: String, b: Double) => + implicit val customConfig: Configuration = + Configuration.default.withSnakeCaseMemberNames.withDefaults.withDiscriminator("type") - val foo: ConfigExampleBase = ConfigExampleFoo(f, 0, b) - val json = json"""{ "type": "ConfigExampleFoo", "this_is_a_field": $f, "b": $b}""" - val expected = json"""{ "type": "ConfigExampleFoo", "this_is_a_field": $f, "a": 0, "b": $b}""" + val foo: ConfigExampleBase = ConfigExampleFoo(f, 0, b) + val json = json"""{ "type": "ConfigExampleFoo", "this_is_a_field": $f, "b": $b}""" + val expected = json"""{ "type": "ConfigExampleFoo", "this_is_a_field": $f, "a": 0, "b": $b}""" - assert(Encoder[ConfigExampleBase].apply(foo) === expected) - assert(Decoder[ConfigExampleBase].decodeJson(json) === Right(foo)) + assert(Encoder[ConfigExampleBase].apply(foo) === expected) + assert(Decoder[ConfigExampleBase].decodeJson(json) === Right(foo)) + } } { import defaults._ - checkLaws("Codec[Tuple1[Int]]", CodecTests[Tuple1[Int]].codec) - checkLaws("Codec[(Int, Int, Foo)]", CodecTests[(Int, Int, Foo)].codec) - checkLaws("Codec[Qux[Int]]", CodecTests[Qux[Int]].codec) - checkLaws("Codec[Foo]", CodecTests[Foo].codec) + checkAll("Codec[Tuple1[Int]]", CodecTests[Tuple1[Int]].codec) + checkAll("Codec[(Int, Int, Foo)]", CodecTests[(Int, Int, Foo)].codec) + checkAll("Codec[Qux[Int]]", CodecTests[Qux[Int]].codec) + checkAll("Codec[Foo]", CodecTests[Foo].codec) - "Decoder[Int => Qux[String]]" should "decode partial JSON representations" in forAll { - (i: Int, s: String, j: Int) => + property("Decoder[Int => Qux[String]] should decode partial JSON representations") { + forAll { (i: Int, s: String, j: Int) => val result = Json .obj( "a" -> Json.fromString(s), @@ -236,6 +247,7 @@ class ConfiguredAutoDerivedSuite extends CirceSuite { .map(_(i)) assert(result === Right(Qux(i, s, j))) + } } } } diff --git a/generic-extras/src/test/scala/io/circe/generic/extras/ConfiguredJsonCodecSuite.scala b/generic-extras/src/test/scala/io/circe/generic/extras/ConfiguredJsonCodecSuite.scala index 0ee90b2f..a8092741 100644 --- a/generic-extras/src/test/scala/io/circe/generic/extras/ConfiguredJsonCodecSuite.scala +++ b/generic-extras/src/test/scala/io/circe/generic/extras/ConfiguredJsonCodecSuite.scala @@ -4,8 +4,11 @@ import cats.kernel.Eq import io.circe.{ Decoder, Encoder } import io.circe.literal._ import io.circe.testing.CodecTests +import org.scalacheck.Prop.forAll import org.scalacheck.{ Arbitrary, Gen } +import scala.Console.in + object ConfiguredJsonCodecSuite { implicit val customConfig: Configuration = Configuration.default.withSnakeCaseMemberNames.withDefaults.withDiscriminator("type").withSnakeCaseConstructorNames @@ -63,51 +66,93 @@ object ConfiguredJsonCodecSuite { class ConfiguredJsonCodecSuite extends CirceSuite { import ConfiguredJsonCodecSuite._ - checkLaws("Codec[ConfigExampleBase]", CodecTests[ConfigExampleBase].codec) - checkLaws("Codec[AccessModifier]", CodecTests[AccessModifier].codec) - checkLaws("Codec[GenericExample[Int]]", CodecTests[GenericExample[Int]].codec) + checkAll("Codec[ConfigExampleBase]", CodecTests[ConfigExampleBase].codec) + checkAll("Codec[AccessModifier]", CodecTests[AccessModifier].codec) + checkAll("Codec[GenericExample[Int]]", CodecTests[GenericExample[Int]].codec) - "ConfiguredJsonCodec" should "support configuration" in forAll { (f: String, b: Double) => - val foo: ConfigExampleBase = ConfigExampleFoo(f, 0, b) - val json = json"""{ "type": "config_example_foo", "this_is_a_field": $f, "b": $b}""" - val expected = json"""{ "type": "config_example_foo", "this_is_a_field": $f, "a": 0, "b": $b}""" + test("ConfiguredJsonCodec should support configuration") { + forAll { (f: String, b: Double) => + val foo: ConfigExampleBase = ConfigExampleFoo(f, 0, b) + val json = json"""{ "type": "config_example_foo", "this_is_a_field": $f, "b": $b}""" + val expected = json"""{ "type": "config_example_foo", "this_is_a_field": $f, "a": 0, "b": $b}""" - assert(Encoder[ConfigExampleBase].apply(foo) === expected) - assert(Decoder[ConfigExampleBase].decodeJson(json) === Right(foo)) + assert(Encoder[ConfigExampleBase].apply(foo) === expected) + assert(Decoder[ConfigExampleBase].decodeJson(json) === Right(foo)) + } } - it should "allow only one, named argument set to true" in { + test("it should allow only one, named argument set to true") { // Can't supply both - assertDoesNotCompile("@ConfiguredJsonCodec(encodeOnly = true, decodeOnly = true) case class X(a: Int)") + assertNoDiff( + compileErrors("@ConfiguredJsonCodec(encodeOnly = true, decodeOnly = true) case class X(a: Int)"), + """error: Unsupported arguments supplied to @ConfiguredJsonCodec + |@ConfiguredJsonCodec(encodeOnly = true, decodeOnly = true) case class X(a: Int) + | ^""".stripMargin + ) + // Must specify the argument name - assertDoesNotCompile("@ConfiguredJsonCodec(true) case class X(a: Int)") + assertNoDiff( + compileErrors("@ConfiguredJsonCodec(true) case class X(a: Int)"), + """error: Unsupported arguments supplied to @ConfiguredJsonCodec + |@ConfiguredJsonCodec(true) case class X(a: Int) + | ^""".stripMargin + ) // Can't specify false - assertDoesNotCompile("@ConfiguredJsonCodec(encodeOnly = false) case class X(a: Int)") + assertNoDiff( + compileErrors("@ConfiguredJsonCodec(encodeOnly = false) case class X(a: Int)"), + """error: Unsupported arguments supplied to @ConfiguredJsonCodec + |@ConfiguredJsonCodec(encodeOnly = false) case class X(a: Int) + | ^""".stripMargin + ) } - "@ConfiguredJsonCodec(encodeOnly = true)" should "only provide Encoder instances" in { + test("@ConfiguredJsonCodec(encodeOnly = true) should only provide Encoder instances") { @ConfiguredJsonCodec(encodeOnly = true) case class CaseClassEncodeOnly(foo: String, bar: Int) Encoder[CaseClassEncodeOnly] Encoder.AsObject[CaseClassEncodeOnly] - assertDoesNotCompile("Decoder[CaseClassEncodeOnly]") + + assertNoDiff( + compileErrors("Decoder[CaseClassEncodeOnly]"), + """error: could not find implicit value for parameter instance: io.circe.Decoder[CaseClassEncodeOnly] + |Decoder[CaseClassEncodeOnly] + | ^""".stripMargin + ) } - "@ConfiguredJsonCodec(decodeOnly = true)" should "provide Decoder instances" in { + test("@ConfiguredJsonCodec(decodeOnly = true) should provide Decoder instances") { @ConfiguredJsonCodec(decodeOnly = true) case class CaseClassDecodeOnly(foo: String, bar: Int) Decoder[CaseClassDecodeOnly] - assertDoesNotCompile("Encoder[CaseClassDecodeOnly]") + + assertNoDiff( + compileErrors("Encoder[CaseClassDecodeOnly]"), + """error: could not find implicit value for parameter instance: io.circe.Encoder[CaseClassDecodeOnly] + |Encoder[CaseClassDecodeOnly] + | ^""".stripMargin + ) } - "@ConfiguredJsonCodec(encodeOnly = true)" should "only provide Encoder instances for generic case classes" in { + test("@ConfiguredJsonCodec(encodeOnly = true) should only provide Encoder instances for generic case classes") { @ConfiguredJsonCodec(encodeOnly = true) case class CaseClassEncodeOnly[A](foo: A, bar: Int) Encoder[CaseClassEncodeOnly[Int]] Encoder.AsObject[CaseClassEncodeOnly[Int]] - assertDoesNotCompile("Decoder[CaseClassEncodeOnly[Int]]") + + assertNoDiff( + compileErrors("Decoder[CaseClassEncodeOnly[Int]]"), + """error: could not find implicit value for parameter instance: io.circe.Decoder[CaseClassEncodeOnly[Int]] + |Decoder[CaseClassEncodeOnly[Int]] + | ^""".stripMargin + ) } - "@ConfiguredJsonCodec(decodeOnly = true)" should "provide Decoder instances for generic case classes" in { + test("@ConfiguredJsonCodec(decodeOnly = true) should provide Decoder instances for generic case classes") { @ConfiguredJsonCodec(decodeOnly = true) case class CaseClassDecodeOnly[A](foo: A, bar: Int) Decoder[CaseClassDecodeOnly[Int]] - assertDoesNotCompile("Encoder[CaseClassDecodeOnly[Int]]") + + assertNoDiff( + compileErrors("Encoder[CaseClassDecodeOnly[Int]]"), + """error: could not find implicit value for parameter instance: io.circe.Encoder[CaseClassDecodeOnly[Int]] + |Encoder[CaseClassDecodeOnly[Int]] + | ^""".stripMargin + ) } } diff --git a/generic-extras/src/test/scala/io/circe/generic/extras/ConfiguredJsonCodecWithKeySuite.scala b/generic-extras/src/test/scala/io/circe/generic/extras/ConfiguredJsonCodecWithKeySuite.scala index 4f3c5745..abc1d811 100644 --- a/generic-extras/src/test/scala/io/circe/generic/extras/ConfiguredJsonCodecWithKeySuite.scala +++ b/generic-extras/src/test/scala/io/circe/generic/extras/ConfiguredJsonCodecWithKeySuite.scala @@ -6,6 +6,7 @@ import io.circe.literal._ import io.circe.testing.CodecTests import org.scalacheck.{ Arbitrary, Gen } import org.scalacheck.Arbitrary.arbitrary +import org.scalacheck.Prop.forAll object ConfiguredJsonCodecWithKeySuite { implicit val customConfig: Configuration = @@ -36,14 +37,16 @@ object ConfiguredJsonCodecWithKeySuite { class ConfiguredJsonCodecWithKeySuite extends CirceSuite { import ConfiguredJsonCodecWithKeySuite._ - checkLaws("Codec[ConfigExampleBase]", CodecTests[ConfigExampleBase].codec) + checkAll("Codec[ConfigExampleBase]", CodecTests[ConfigExampleBase].codec) - "ConfiguredJsonCodec" should "support key annotation and configuration" in forAll { (f: String, b: Double) => - val foo: ConfigExampleBase = ConfigExampleFoo(f, 0, b) - val json = json"""{ "type": "config_example_foo", "this_is_a_field": $f, "myField": $b}""" - val expected = json"""{ "type": "config_example_foo", "this_is_a_field": $f, "a": 0, "myField": $b}""" + property("ConfiguredJsonCodec should support key annotation and configuration") { + forAll { (f: String, b: Double) => + val foo: ConfigExampleBase = ConfigExampleFoo(f, 0, b) + val json = json"""{ "type": "config_example_foo", "this_is_a_field": $f, "myField": $b}""" + val expected = json"""{ "type": "config_example_foo", "this_is_a_field": $f, "a": 0, "myField": $b}""" - assert(Encoder[ConfigExampleBase].apply(foo) === expected) - assert(Decoder[ConfigExampleBase].decodeJson(json) === Right(foo)) + assert(Encoder[ConfigExampleBase].apply(foo) === expected) + assert(Decoder[ConfigExampleBase].decodeJson(json) === Right(foo)) + } } } diff --git a/generic-extras/src/test/scala/io/circe/generic/extras/ConfiguredSemiautoDerivedSuite.scala b/generic-extras/src/test/scala/io/circe/generic/extras/ConfiguredSemiautoDerivedSuite.scala index 3edd9e73..b6ebed03 100644 --- a/generic-extras/src/test/scala/io/circe/generic/extras/ConfiguredSemiautoDerivedSuite.scala +++ b/generic-extras/src/test/scala/io/circe/generic/extras/ConfiguredSemiautoDerivedSuite.scala @@ -9,6 +9,7 @@ import org.scalacheck.{ Arbitrary, Gen } import org.scalacheck.Arbitrary.arbitrary import shapeless.Witness import shapeless.labelled.{ FieldType, field } +import org.scalacheck.Prop.forAll import examples._ @@ -53,30 +54,32 @@ object ConfiguredSemiautoDerivedSuite { class ConfiguredSemiautoDerivedSuite extends CirceSuite { import ConfiguredSemiautoDerivedSuite._ - checkLaws("Codec[ConfigExampleBase]", CodecTests[ConfigExampleBase].codec) - checkLaws( + checkAll("Codec[ConfigExampleBase]", CodecTests[ConfigExampleBase].codec) + checkAll( "Codec[ConfigExampleBase] via Codec", CodecTests[ConfigExampleBase](codecForConfigExampleBase, codecForConfigExampleBase).codec ) - checkLaws( + checkAll( "Codec[ConfigExampleBase] via Decoder and Codec", CodecTests[ConfigExampleBase](implicitly, codecForConfigExampleBase).codec ) - checkLaws( + checkAll( "Codec[ConfigExampleBase] via Encoder and Codec", CodecTests[ConfigExampleBase](codecForConfigExampleBase, implicitly).codec ) - "Semi-automatic derivation" should "support configuration" in forAll { (f: String, b: Double) => - val foo: ConfigExampleBase = ConfigExampleFoo(f, 0, b) - val json = json"""{ "type": "config_example_foo", "this_is_a_field": $f, "b": $b}""" - val expected = json"""{ "type": "config_example_foo", "this_is_a_field": $f, "a": 0, "b": $b}""" + property("Semi-automatic derivation should support configuration") { + forAll { (f: String, b: Double) => + val foo: ConfigExampleBase = ConfigExampleFoo(f, 0, b) + val json = json"""{ "type": "config_example_foo", "this_is_a_field": $f, "b": $b}""" + val expected = json"""{ "type": "config_example_foo", "this_is_a_field": $f, "a": 0, "b": $b}""" - assert(Encoder[ConfigExampleBase].apply(foo) === expected) - assert(Decoder[ConfigExampleBase].decodeJson(json) === Right(foo)) + assert(Encoder[ConfigExampleBase].apply(foo) === expected) + assert(Decoder[ConfigExampleBase].decodeJson(json) === Right(foo)) + } } - it should "call field modification times equal to field count" in { + test("it should call field modification times equal to field count") { var transformMemberNamesCallCount, transformConstructorCallCount = 0 implicit val customConfig: Configuration = Configuration.default.copy( @@ -108,39 +111,43 @@ class ConfiguredSemiautoDerivedSuite extends CirceSuite { } } - it should "support configured strict decoding" in forAll { (f: String, b: Double) => - implicit val customConfig: Configuration = - Configuration.default.withSnakeCaseMemberNames.withDefaults - .withDiscriminator("type_field") - .withSnakeCaseConstructorNames - .withStrictDecoding + property("it should support configured strict decoding") { + forAll { (f: String, b: Double) => + implicit val customConfig: Configuration = + Configuration.default.withSnakeCaseMemberNames.withDefaults + .withDiscriminator("type_field") + .withSnakeCaseConstructorNames + .withStrictDecoding - implicit val decodeConfigExampleBase: Decoder[ConfigExampleBase] = deriveConfiguredDecoder + implicit val decodeConfigExampleBase: Decoder[ConfigExampleBase] = deriveConfiguredDecoder - val json = - json""" + val json = + json""" {"type_field": "config_example_foo", "this_is_a_field": $f, "b": $b, "stowaway_field": "I should not be here"} """ - val expectedError = - DecodingFailure("Unexpected field: [stowaway_field]; valid fields: this_is_a_field, a, b, type_field", Nil) + val expectedError = + DecodingFailure("Unexpected field: [stowaway_field]; valid fields: this_is_a_field, a, b, type_field", Nil) - assert(Decoder[ConfigExampleBase].decodeJson(json) === Left(expectedError)) + assert(Decoder[ConfigExampleBase].decodeJson(json) === Left(expectedError)) + } } - "Decoder[Int => Qux[String]]" should "decode partial JSON representations" in forAll { (i: Int, s: String, j: Int) => - val result = Json - .obj( - "a" -> Json.fromString(s), - "j" -> Json.fromInt(j) - ) - .as[Int => Qux[String]] - .map(_(i)) + property("Decoder[Int => Qux[String]] should decode partial JSON representations") { + forAll { (i: Int, s: String, j: Int) => + val result = Json + .obj( + "a" -> Json.fromString(s), + "j" -> Json.fromInt(j) + ) + .as[Int => Qux[String]] + .map(_(i)) - assert(result === Right(Qux(i, s, j))) + assert(result === Right(Qux(i, s, j))) + } } - "Decoder[FieldType[Witness.`'j`.T, Int] => Qux[String]]" should "decode partial JSON representations" in { + property("Decoder[FieldType[Witness.`'j`.T, Int] => Qux[String]] should decode partial JSON representations") { forAll { (i: Int, s: String, j: Int) => val result = Json .obj( @@ -156,7 +163,7 @@ class ConfiguredSemiautoDerivedSuite extends CirceSuite { } } - "Decoder[Qux[String] => Qux[String]]" should "decode patch JSON representations" in { + property("Decoder[Qux[String] => Qux[String]] should decode patch JSON representations") { forAll { (q: Qux[String], i: Option[Int], a: Option[String], j: Option[Int]) => val json = Json.obj( "i" -> Encoder[Option[Int]].apply(i), @@ -170,10 +177,12 @@ class ConfiguredSemiautoDerivedSuite extends CirceSuite { } } - "A generically derived codec for an empty case class" should "not accept non-objects" in forAll { (j: Json) => - case class EmptyCc() + property("A generically derived codec for an empty case class should not accept non-objects") { + forAll { (j: Json) => + case class EmptyCc() - assert(deriveConfiguredDecoder[EmptyCc].decodeJson(j).isRight == j.isObject) - assert(deriveConfiguredCodec[EmptyCc].decodeJson(j).isRight == j.isObject) + assert(deriveConfiguredDecoder[EmptyCc].decodeJson(j).isRight == j.isObject) + assert(deriveConfiguredCodec[EmptyCc].decodeJson(j).isRight == j.isObject) + } } } diff --git a/generic-extras/src/test/scala/io/circe/generic/extras/EnumerationSemiautoDerivedSuite.scala b/generic-extras/src/test/scala/io/circe/generic/extras/EnumerationSemiautoDerivedSuite.scala index e689fc0c..aff5773c 100644 --- a/generic-extras/src/test/scala/io/circe/generic/extras/EnumerationSemiautoDerivedSuite.scala +++ b/generic-extras/src/test/scala/io/circe/generic/extras/EnumerationSemiautoDerivedSuite.scala @@ -13,38 +13,38 @@ class EnumerationSemiautoDerivedSuite extends CirceSuite { implicit val encodeCardinalDirection: Encoder[CardinalDirection] = deriveEnumerationEncoder val codecForCardinalDirection: Codec[CardinalDirection] = deriveEnumerationCodec - checkLaws("Codec[CardinalDirection]", CodecTests[CardinalDirection].codec) - checkLaws( + checkAll("Codec[CardinalDirection]", CodecTests[CardinalDirection].codec) + checkAll( "Codec[CardinalDirection] via Codec", CodecTests[CardinalDirection](codecForCardinalDirection, codecForCardinalDirection).codec ) - checkLaws( + checkAll( "Codec[CardinalDirection] via Decoder and Codec", CodecTests[CardinalDirection](implicitly, codecForCardinalDirection).codec ) - checkLaws( + checkAll( "Codec[CardinalDirection] via Encoder and Codec", CodecTests[CardinalDirection](codecForCardinalDirection, implicitly).codec ) - "deriveEnumerationDecoder" should "not compile on an ADT with case classes" in { + test("deriveEnumerationDecoder should not compile on an ADT with case classes") { implicit val config: Configuration = Configuration.default illTyped("deriveEnumerationDecoder[ExtendedCardinalDirection]") } - it should "respect Configuration" in { + test("it should respect Configuration") { implicit val config: Configuration = Configuration.default.withSnakeCaseConstructorNames val decodeMary = deriveEnumerationDecoder[Mary] val expected = json""""little_lamb"""" assert(decodeMary.decodeJson(expected) === Right(LittleLamb)) } - "deriveEnumerationEncoder" should "not compile on an ADT with case classes" in { + test("deriveEnumerationEncoder should not compile on an ADT with case classes") { implicit val config: Configuration = Configuration.default illTyped("deriveEnumerationEncoder[ExtendedCardinalDirection]") } - it should "respect Configuration" in { + test("it should respect Configuration") { implicit val config: Configuration = Configuration.default.withSnakeCaseConstructorNames val encodeMary = deriveEnumerationEncoder[Mary] val expected = json""""little_lamb"""" diff --git a/generic-extras/src/test/scala/io/circe/generic/extras/UnwrappedSemiautoDerivedSuite.scala b/generic-extras/src/test/scala/io/circe/generic/extras/UnwrappedSemiautoDerivedSuite.scala index e8fbef42..dc8f80fe 100644 --- a/generic-extras/src/test/scala/io/circe/generic/extras/UnwrappedSemiautoDerivedSuite.scala +++ b/generic-extras/src/test/scala/io/circe/generic/extras/UnwrappedSemiautoDerivedSuite.scala @@ -6,6 +6,7 @@ import io.circe.generic.extras.semiauto._ import io.circe.testing.CodecTests import org.scalacheck.{ Arbitrary, Gen } import org.scalacheck.Arbitrary.arbitrary +import org.scalacheck.Prop.forAll object UnwrappedSemiautoDerivedSuite { case class Foo(value: String) @@ -24,30 +25,35 @@ object UnwrappedSemiautoDerivedSuite { class UnwrappedSemiautoDerivedSuite extends CirceSuite { import UnwrappedSemiautoDerivedSuite._ - checkLaws("Codec[Foo]", CodecTests[Foo].codec) - checkLaws("Codec[Foo] via Codec", CodecTests[Foo](Foo.codec, Foo.codec).codec) - checkLaws("Codec[Foo] via Decoder and Codec", CodecTests[Foo](implicitly, Foo.codec).codec) - checkLaws("Codec[Foo] via Encoder and Codec", CodecTests[Foo](Foo.codec, implicitly).codec) + checkAll("Codec[Foo]", CodecTests[Foo].codec) + checkAll("Codec[Foo] via Codec", CodecTests[Foo](Foo.codec, Foo.codec).codec) + checkAll("Codec[Foo] via Decoder and Codec", CodecTests[Foo](implicitly, Foo.codec).codec) + checkAll("Codec[Foo] via Encoder and Codec", CodecTests[Foo](Foo.codec, implicitly).codec) - "Semi-automatic derivation" should "encode value classes" in forAll { (s: String) => - val foo = Foo(s) - val expected = Json.fromString(s) + property("Semi-automatic derivation should encode value classes") { + forAll { (s: String) => + val foo = Foo(s) + val expected = Json.fromString(s) - assert(Encoder[Foo].apply(foo) === expected) + assert(Encoder[Foo].apply(foo) === expected) + } } - it should "decode value classes" in forAll { (s: String) => - val json = Json.fromString(s) - val expected = Right(Foo(s)) + property("it should decode value classes") { + forAll { (s: String) => + val json = Json.fromString(s) + val expected = Right(Foo(s)) - assert(Decoder[Foo].decodeJson(json) === expected) + assert(Decoder[Foo].decodeJson(json) === expected) + } } - it should "fail decoding incompatible JSON" in forAll { (i: Int, s: String) => - val json = Json.fromInt(i) - val expected = Left(DecodingFailure("String", List())) + property("it should fail decoding incompatible JSON") { + forAll { (i: Int, s: String) => + val json = Json.fromInt(i) + val expected = Left(DecodingFailure("String", List())) - assert(Decoder[Foo].decodeJson(json) === expected) + assert(Decoder[Foo].decodeJson(json) === expected) + } } - }