From 8efd138e000d1cf162a88d1f55e496490bd664f8 Mon Sep 17 00:00:00 2001 From: Michel Davit Date: Fri, 31 May 2024 17:20:59 +0200 Subject: [PATCH 1/4] Use dedicated macro for scala 3 enum type --- build.sbt | 2 +- .../magnolify/shared/EnumTypeDerivation.scala | 10 ++- .../magnolify/shared/EnumTypeMacros.scala | 16 ++-- .../magnolify/shared/EnumTypeDerivation.scala | 79 +++++++------------ .../magnolify/shared/EnumTypeMacros.scala | 8 +- .../magnolify/shared/EnumTypeSuite.scala | 52 ++++++++---- test/src/test/scala/magnolify/test/ADT.scala | 16 +++- 7 files changed, 96 insertions(+), 87 deletions(-) diff --git a/build.sbt b/build.sbt index 89808ea1c..bafdfbce2 100644 --- a/build.sbt +++ b/build.sbt @@ -267,7 +267,7 @@ val commonSettings = Seq( "-Yretain-trees", // tolerate some nested macro expansion "-Xmax-inlines", - "64" + "128" ) case Some((2, 13)) => Seq( diff --git a/shared/src/main/scala-2/magnolify/shared/EnumTypeDerivation.scala b/shared/src/main/scala-2/magnolify/shared/EnumTypeDerivation.scala index 249030ccf..1aa483111 100644 --- a/shared/src/main/scala-2/magnolify/shared/EnumTypeDerivation.scala +++ b/shared/src/main/scala-2/magnolify/shared/EnumTypeDerivation.scala @@ -16,11 +16,15 @@ package magnolify.shared -import magnolia1.{CaseClass, SealedTrait} +import magnolia1._ import scala.annotation.implicitNotFound trait EnumTypeDerivation { + implicit def gen[T]: EnumType[T] = macro EnumTypeMacros.derivationEnumTypeMacro[T] +} + +object EnumTypeDerivation { type Typeclass[T] = EnumType[T] // EnumType can only be split into objects with fixed name @@ -49,7 +53,7 @@ trait EnumTypeDerivation { val ns = sealedTrait.typeName.owner val subs = sealedTrait.subtypes.map(_.typeclass) val values = subs.flatMap(_.values).sorted.toList - val annotations = (sealedTrait.annotations ++ subs.flatMap(_.annotations)).toList + val annotations = sealedTrait.inheritedAnnotations.toList ++ sealedTrait.annotations.toList EnumType.create( n, ns, @@ -60,4 +64,6 @@ trait EnumTypeDerivation { v => subs.find(_.name == v).get.from(v) ) } + + def gen[T]: EnumType[T] = macro Magnolia.gen[T] } diff --git a/shared/src/main/scala-2/magnolify/shared/EnumTypeMacros.scala b/shared/src/main/scala-2/magnolify/shared/EnumTypeMacros.scala index 7a9f4f3bf..29755baaa 100644 --- a/shared/src/main/scala-2/magnolify/shared/EnumTypeMacros.scala +++ b/shared/src/main/scala-2/magnolify/shared/EnumTypeMacros.scala @@ -16,10 +16,10 @@ package magnolify.shared -import magnolia1.Magnolia import scala.reflect.macros.whitebox object EnumTypeMacros { + def scalaEnumTypeMacro[T: c.WeakTypeTag]( c: whitebox.Context )(annotations: c.Expr[AnnotationType[T]]): c.Tree = { @@ -44,18 +44,20 @@ object EnumTypeMacros { val tpe = weakTypeOf[T] val symbol = tpe.typeSymbol if (symbol.isModuleClass) { - q"new _root_.magnolify.shared.EnumType.EnumValue[$tpe]{}" + q"new _root_.magnolify.shared.EnumTypeDerivation.EnumValue[$tpe]{}" } else { c.abort(c.enclosingPosition, "EnumType value must be an object") } } + + def derivationEnumTypeMacro[T: c.WeakTypeTag](c: whitebox.Context): c.Tree = { + import c.universe._ + val tpe = weakTypeOf[T] + q"_root_.magnolify.shared.EnumTypeDerivation.gen[$tpe]" + } } -trait EnumTypeCompanionMacros extends EnumTypeCompanionLowPrioMacros { +trait EnumTypeCompanionMacros extends EnumTypeDerivation { implicit def scalaEnumType[T <: Enumeration#Value: AnnotationType]: EnumType[T] = macro EnumTypeMacros.scalaEnumTypeMacro[T] } - -trait EnumTypeCompanionLowPrioMacros extends EnumTypeDerivation { - implicit def gen[T]: EnumType[T] = macro Magnolia.gen[T] -} diff --git a/shared/src/main/scala-3/magnolify/shared/EnumTypeDerivation.scala b/shared/src/main/scala-3/magnolify/shared/EnumTypeDerivation.scala index 784ff722d..d81dc8277 100644 --- a/shared/src/main/scala-3/magnolify/shared/EnumTypeDerivation.scala +++ b/shared/src/main/scala-3/magnolify/shared/EnumTypeDerivation.scala @@ -16,62 +16,41 @@ package magnolify.shared -import magnolia1.{CaseClass, CommonDerivation, SealedTrait, SealedTraitDerivation} +import magnolia1.* import scala.compiletime.* import scala.deriving.Mirror -// Do not extend Derivation so we can add an extra check when deriving the sum type -trait EnumTypeDerivation extends CommonDerivation[EnumType] with SealedTraitDerivation: - - transparent inline def subtypes[T, SubtypeTuple <: Tuple]( - m: Mirror.SumOf[T], - idx: Int = 0 // no longer used, kept for bincompat - ): List[SealedTrait.Subtype[Typeclass, T, _]] = - subtypesFromMirror[T, SubtypeTuple](m, idx) - - inline def derivedMirrorSum[A](sum: Mirror.SumOf[A]): EnumType[A] = - summonAll[Tuple.Map[sum.MirroredElemTypes, [S] =>> S <:< Singleton]] // assert all singleton - split(sealedTraitFromMirror(sum)) - - inline def derivedMirror[A](using mirror: Mirror.Of[A]): EnumType[A] = - inline mirror match - case sum: Mirror.SumOf[A] => derivedMirrorSum[A](sum) - case product: Mirror.ProductOf[A] => derivedMirrorProduct[A](product) - - inline def derived[A](using Mirror.Of[A]): EnumType[A] = derivedMirror[A] +trait EnumTypeDerivation: + implicit inline def gen[T](using mirror: Mirror.Of[T]): EnumType[T] = EnumTypeDerivation.gen[T] - protected override inline def deriveSubtype[s](m: Mirror.Of[s]): EnumType[s] = - derivedMirror[s](using m) - - def join[T](caseClass: CaseClass[EnumType, T]): EnumType[T] = - // fail at runtime since we can't prevent derivation - // see https://github.com/softwaremill/magnolia/issues/267 - require(caseClass.isObject, s"Cannot derive EnumType[T] for case class ${caseClass.typeInfo}") - val n = caseClass.typeInfo.short - val ns = caseClass.typeInfo.owner - EnumType.create( - n, - ns, - List(n), - caseClass.annotations.toList, - _ => caseClass.rawConstruct(Nil) - ) - end join +// Do not extend Derivation so we can add an extra check when deriving the sum type +object EnumTypeDerivation: + + private transparent inline def values[A, S <: Tuple](m: Mirror.Of[A]): List[A] = + inline erasedValue[S] match + case _: EmptyTuple => + Nil + case _: (s *: tail) => + val infos = summonFrom { + case mm: Mirror.SumOf[`s`] => + values[A, mm.MirroredElemTypes](mm.asInstanceOf[m.type]) + case mm: Mirror.ProductOf[`s`] if Macro.isObject[`s`] => + List(mm.fromProduct(EmptyTuple).asInstanceOf[A]) + case _ => + error("Cannot derive EnumType for non singleton sum type") + } + infos ::: values[A, tail](m) + + inline implicit def gen[T](using mirror: Mirror.Of[T]): EnumType[T] = + val s = values[T, T *: EmptyTuple](mirror).sortBy(_.toString) + val it = Macro.typeInfo[T] + val annotations = Macro.inheritedAnns[T] ++ Macro.anns[T] - def split[T](sealedTrait: SealedTrait[EnumType, T]): EnumType[T] = - val n = sealedTrait.typeInfo.short - val ns = sealedTrait.typeInfo.owner - val subs = sealedTrait.subtypes.map(_.typeclass) - val values = subs.flatMap(_.values).sorted.toList - val annotations = (sealedTrait.annotations ++ subs.flatMap(_.annotations)).toList EnumType.create( - n, - ns, - values, + it.short, + it.owner, + s.map(_.toString), annotations, - // it is ok to use the inefficient find here because it will be called only once - // and cached inside an instance of EnumType - v => subs.find(_.name == v).get.from(v) + name => s.find(_.toString == name).get ) - end split diff --git a/shared/src/main/scala-3/magnolify/shared/EnumTypeMacros.scala b/shared/src/main/scala-3/magnolify/shared/EnumTypeMacros.scala index ffbf59ecd..5d6aa62ec 100644 --- a/shared/src/main/scala-3/magnolify/shared/EnumTypeMacros.scala +++ b/shared/src/main/scala-3/magnolify/shared/EnumTypeMacros.scala @@ -17,7 +17,6 @@ package magnolify.shared import scala.quoted.* -import scala.deriving.Mirror object EnumTypeMacros: def scalaEnumTypeMacro[T: Type](annotations: Expr[AnnotationType[T]])(using @@ -35,13 +34,8 @@ object EnumTypeMacros: val map = '{ $e.values.iterator.map(x => x.toString -> x.asInstanceOf[T]).toMap.apply(_) } '{ EnumType.create[T]($n, $ns, $vs, $as, $map) } -trait EnumTypeCompanionMacros extends EnumTypeCompanionMacros0 - -trait EnumTypeCompanionMacros0 extends EnumTypeCompanionMacros1: +trait EnumTypeCompanionMacros extends EnumTypeDerivation: inline implicit def scalaEnumType[T <: Enumeration#Value](using annotations: AnnotationType[T] ): EnumType[T] = ${ EnumTypeMacros.scalaEnumTypeMacro[T]('annotations) } - -trait EnumTypeCompanionMacros1 extends EnumTypeDerivation: - inline implicit def gen[T](using Mirror.Of[T]): EnumType[T] = derivedMirror[T] diff --git a/test/src/test/scala/magnolify/shared/EnumTypeSuite.scala b/test/src/test/scala/magnolify/shared/EnumTypeSuite.scala index ab6e7a77e..bcec9161a 100644 --- a/test/src/test/scala/magnolify/shared/EnumTypeSuite.scala +++ b/test/src/test/scala/magnolify/shared/EnumTypeSuite.scala @@ -47,15 +47,31 @@ class EnumTypeSuite extends MagnolifySuite { } test("ADT") { - val et = ensureSerializable(EnumType[ADT.Color]) - assertEquals(et.name, "Color") - assertEquals(et.namespace, "magnolify.test.ADT") - assertEquals(et.values, List("Blue", "Green", "Red")) // ADTs are ordered alphabetically - assertEquals(et.from("Red"), ADT.Red) - assertEquals(et.to(ADT.Red), "Red") + val etPrimaryColor = ensureSerializable(EnumType[ADT.PrimaryColor]) + assertEquals(etPrimaryColor.name, "PrimaryColor") + assertEquals(etPrimaryColor.namespace, "magnolify.test.ADT") + assertEquals( + etPrimaryColor.values, + List("Blue", "Green", "Red") + ) // ADTs are ordered alphabetically + assertEquals(etPrimaryColor.from("Red"), ADT.Red) + assertEquals(etPrimaryColor.to(ADT.Red), "Red") + // Magnolia does not capture Java annotations + val annPrimaryColor = etPrimaryColor.annotations.collect { case a: ScalaAnnotation => a.value } + assertEquals(annPrimaryColor, List("Color", "PrimaryColor")) + + val etColor = ensureSerializable(EnumType[ADT.Color]) + assertEquals(etColor.name, "Color") + assertEquals(etColor.namespace, "magnolify.test.ADT") + assertEquals( + etColor.values, + List("Blue", "Cyan", "Green", "Magenta", "Red", "Yellow") + ) // ADTs are ordered alphabetically + assertEquals(etColor.from("Magenta"), ADT.Magenta) + assertEquals(etColor.to(ADT.Magenta), "Magenta") // Magnolia does not capture Java annotations - val as = et.annotations.collect { case a: ScalaAnnotation => a.value } - assertEquals(as, List("Color", "Red")) + val as = etColor.annotations.collect { case a: ScalaAnnotation => a.value } + assertEquals(as, List("Color")) } test("ADT No Default Constructor") { @@ -72,14 +88,18 @@ class EnumTypeSuite extends MagnolifySuite { { val error = compileErrors("EnumType.gen[Option[ADT.Color]]") val scala2Error = - """|error: Cannot derive EnumType.EnumValue. EnumType only works for sum types + """|error: + |magnolia: could not find EnumType.Typeclass for type magnolify.test.ADT.Color + | in parameter 'value' of product type Some[magnolify.test.ADT.Color] + | in coproduct type Option[magnolify.test.ADT.Color] + | |EnumType.gen[Option[ADT.Color]] | ^ |""".stripMargin val scala3Error = - """|error: Cannot prove that Some[magnolify.test.ADT.Color] <:< Singleton. - | - | ^ + """|error: Cannot derive EnumType for non singleton sum type + | val error = compileErrors("EnumType.gen[Option[ADT.Color]]") + | ^ |""".stripMargin if (Properties.versionNumberString.startsWith("2.12")) { assertNoDiff(error, scala2Error) @@ -101,9 +121,9 @@ class EnumTypeSuite extends MagnolifySuite { |""".stripMargin val scala3Error = - """|error: Cannot prove that Some[magnolify.test.ADT.Color] <:< Singleton. - | - | ^ + """|error: Cannot derive EnumType for non singleton sum type + | val error = compileErrors("EnumType[Option[ADT.Color]]") + | ^ |""".stripMargin if (Properties.versionNumberString.startsWith("2.12")) { @@ -132,7 +152,7 @@ class EnumTypeSuite extends MagnolifySuite { } test("ADT CaseMapper") { - val et = ensureSerializable(EnumType[ADT.Color](CaseMapper(_.toLowerCase))) + val et = ensureSerializable(EnumType[ADT.PrimaryColor](CaseMapper(_.toLowerCase))) assertEquals(et.values, List("blue", "green", "red")) // ADTs are ordered alphabetically assertEquals(et.from("red"), ADT.Red) assertEquals(et.to(ADT.Red), "red") diff --git a/test/src/test/scala/magnolify/test/ADT.scala b/test/src/test/scala/magnolify/test/ADT.scala index 084b54db7..3de88f338 100644 --- a/test/src/test/scala/magnolify/test/ADT.scala +++ b/test/src/test/scala/magnolify/test/ADT.scala @@ -34,10 +34,18 @@ object ADT { @ScalaAnnotation("Color") sealed trait Color - @ScalaAnnotation("Red") - case object Red extends Color - case object Green extends Color - case object Blue extends Color + @ScalaAnnotation("PrimaryColor") + sealed trait PrimaryColor extends Color + case object Red extends PrimaryColor + case object Green extends PrimaryColor + case object Blue extends PrimaryColor + @ScalaAnnotation("SecondaryColor") + sealed abstract class SecondaryColor(p1: PrimaryColor, p2: PrimaryColor) extends Color { + def primaryColors: Set[PrimaryColor] = Set(p1, p2) + } + case object Yellow extends SecondaryColor(Red, Green) + case object Cyan extends SecondaryColor(Green, Blue) + case object Magenta extends SecondaryColor(Red, Blue) // This is needed to simulate an error with "no valid constructor" // exception on attempt to deserialize a case object implementing an abstract class without From db31d71b8503f314e757709e8a6a0dde59978449 Mon Sep 17 00:00:00 2001 From: Michel Davit Date: Fri, 31 May 2024 18:42:45 +0200 Subject: [PATCH 2/4] Fix protobuf test suite for scala 2.13 --- .../magnolify/protobuf/ProtobufType.scala | 4 +- protobuf/src/test/protobuf/Proto2.proto | 95 ++++++++-------- protobuf/src/test/protobuf/Proto3.proto | 85 +++++++------- .../protobuf/ProtobufTypeSuite.scala | 106 +++++++++--------- 4 files changed, 150 insertions(+), 140 deletions(-) diff --git a/protobuf/src/main/scala/magnolify/protobuf/ProtobufType.scala b/protobuf/src/main/scala/magnolify/protobuf/ProtobufType.scala index e83572813..281615273 100644 --- a/protobuf/src/main/scala/magnolify/protobuf/ProtobufType.scala +++ b/protobuf/src/main/scala/magnolify/protobuf/ProtobufType.scala @@ -27,6 +27,7 @@ import magnolify.shims.FactoryCompat import scala.annotation.implicitNotFound import scala.collection.concurrent import scala.reflect.ClassTag +import scala.util.Try import scala.jdk.CollectionConverters.* import scala.collection.compat.* @@ -241,7 +242,8 @@ object ProtobufField { .asInstanceOf[Array[E]] .map(e => e.name() -> e) .toMap - val default = et.from(map.values.find(_.getNumber == 0).get.name()) + + val default = et.from(map.values.find(e => Try(e.getNumber).getOrElse(-1) == 0).get.name()) aux2[T, EnumValueDescriptor](default)(e => et.from(e.getName))(e => map(et.to(e)).getValueDescriptor ) diff --git a/protobuf/src/test/protobuf/Proto2.proto b/protobuf/src/test/protobuf/Proto2.proto index af4f12d1e..919612262 100644 --- a/protobuf/src/test/protobuf/Proto2.proto +++ b/protobuf/src/test/protobuf/Proto2.proto @@ -1,82 +1,87 @@ syntax = "proto2"; -package magnolify.protobuf; +package magnolify.protobuf.v2; option java_package = "magnolify.protobuf"; -message IntegersP2 { +message Integers { required int32 i = 1; required int64 l = 2; } -message FloatsP2 { +message Floats { required float f = 1; required double d = 2; } -message RequiredP2 { +message Required { required bool b = 1; required string s = 2; required int32 i = 3; } -message NullableP2 { +message Nullable { optional bool b = 1; optional string s = 2; optional int32 i = 3; } -message RepeatedP2 { +message Repeated { repeated bool b = 1; repeated string s = 2; repeated int32 i = 3; } -message NestedP2 { +message Nested { required bool b = 1; required string s = 2; required int32 i = 3; - required RequiredP2 r = 4; - optional RequiredP2 o = 5; - repeated RequiredP2 l = 6; + required Required r = 4; + optional Required o = 5; + repeated Required l = 6; } -message CollectionP2 { +message Collection { repeated int32 a = 1; repeated int32 l = 2; repeated int32 v = 3; repeated int32 s = 4; } -message MoreCollectionP2 { +message MoreCollection { repeated int32 i = 1; repeated int32 s = 2; repeated int32 is = 3; } -message EnumsP2 { - enum JavaEnums { - RED = 0; - GREEN = 1; - BLUE = 2; - } - enum ScalaEnums { - Red = 0; - Green = 1; - Blue = 2; - } - required JavaEnums j = 1; - required ScalaEnums s = 2; // Enumeration - required ScalaEnums a = 3; // ADT - optional JavaEnums jo = 4; - optional ScalaEnums so = 5; // Enumeration - optional ScalaEnums ao = 6; // ADT - repeated JavaEnums jr = 7; - repeated ScalaEnums sr = 8; // Enumeration - repeated ScalaEnums ar = 9; // ADT -} - -message UnsafeEnumsP2 { +enum UpperCaseColor { + RED = 0; + GREEN = 1; + BLUE = 2; +} + +enum CamelCaseColor { + Red = 0; + Green = 1; + Blue = 2; + Yellow = 3; + Cyan = 4; + Magenta = 5; +} + +message Enums { + required UpperCaseColor j = 1; + required CamelCaseColor s = 2; // Enumeration + required CamelCaseColor a = 3; // ADT + optional UpperCaseColor jo = 4; + optional CamelCaseColor so = 5; // Enumeration + optional CamelCaseColor ao = 6; // ADT + repeated UpperCaseColor jr = 7; + repeated CamelCaseColor sr = 8; // Enumeration + repeated CamelCaseColor ar = 9; // ADT +} + +message UnsafeEnums { required string j = 1; required string s = 2; required string a = 3; @@ -88,16 +93,16 @@ message UnsafeEnumsP2 { repeated string ar = 9; } -message CustomP2 { +message Custom { required string u = 1; required int64 d = 2; } -message BytesP2 { +message Bytes { required bytes b = 1; } -message DefaultRequiredP2 { +message DefaultRequired { required int32 i = 1 [default = 123]; required int64 l = 2 [default = 456]; required float f = 3 [default = 1.23]; @@ -105,12 +110,12 @@ message DefaultRequiredP2 { required bool b = 5 [default = true]; required string s = 6 [default = "abc"]; required bytes bs = 7 [default = "def"]; - required EnumsP2.JavaEnums je = 8 [default = GREEN]; - required EnumsP2.ScalaEnums se = 9 [default = Green]; // Enumeration - required EnumsP2.ScalaEnums ae = 10 [default = Green]; // ADT + required UpperCaseColor je = 8 [default = GREEN]; + required CamelCaseColor se = 9 [default = Green]; // Enumeration + required CamelCaseColor ae = 10 [default = Cyan]; // ADT } -message DefaultNullableP2 { +message DefaultNullable { optional int32 i = 1 [default = 123]; optional int64 l = 2 [default = 456]; optional float f = 3 [default = 1.23]; @@ -118,7 +123,7 @@ message DefaultNullableP2 { optional bool b = 5 [default = true]; optional string s = 6 [default = "abc"]; optional bytes bs = 7 [default = "def"]; - optional EnumsP2.JavaEnums je = 8 [default = GREEN]; - optional EnumsP2.ScalaEnums se = 9 [default = Green]; // Enumeration - optional EnumsP2.ScalaEnums ae = 10 [default = Green]; // ADT + optional UpperCaseColor je = 8 [default = GREEN]; + optional CamelCaseColor se = 9 [default = Green]; // Enumeration + optional CamelCaseColor ae = 10 [default = Cyan]; // ADT } diff --git a/protobuf/src/test/protobuf/Proto3.proto b/protobuf/src/test/protobuf/Proto3.proto index 1fe02fc6f..da9affb2d 100644 --- a/protobuf/src/test/protobuf/Proto3.proto +++ b/protobuf/src/test/protobuf/Proto3.proto @@ -1,82 +1,87 @@ syntax = "proto3"; -package magnolify.protobuf; +package magnolify.protobuf.v3; option java_package = "magnolify.protobuf"; -message IntegersP3 { +message Integers { int32 i = 1; int64 l = 2; } -message FloatsP3 { +message Floats { float f = 1; double d = 2; } -message RequiredP3 { +message Required { bool b = 1; string s = 2; int32 i = 3; } -message NullableP3 { +message Nullable { optional bool b = 1; optional string s = 2; optional int32 i = 3; } -message RepeatedP3 { +message Repeated { repeated bool b = 1; repeated string s = 2; repeated int32 i = 3; } -message NestedP3 { +message Nested { bool b = 1; string s = 2; int32 i = 3; - RequiredP3 r = 4; - optional RequiredP3 o = 5; - repeated RequiredP3 l = 6; + Required r = 4; + optional Required o = 5; + repeated Required l = 6; } -message CollectionP3 { +message Collection { repeated int32 a = 1; repeated int32 l = 2; repeated int32 v = 3; repeated int32 s = 4; } -message MoreCollectionP3 { +message MoreCollection { repeated int32 i = 1; repeated int32 s = 2; repeated int32 is = 3; } -message EnumsP3 { - enum JavaEnums { - RED = 0; - GREEN = 1; - BLUE = 2; - } - enum ScalaEnums { - Red = 0; - Green = 1; - Blue = 2; - } - JavaEnums j = 1; - ScalaEnums s = 2; // Enumeration - ScalaEnums a = 3; // ADT - optional JavaEnums jo = 4; - optional ScalaEnums so = 5; // Enumeration - optional ScalaEnums ao = 6; // ADT - repeated JavaEnums jr = 7; - repeated ScalaEnums sr = 8; // Enumeration - repeated ScalaEnums ar = 9; // ADT -} - -message UnsafeEnumsP3 { +enum UpperCaseColor { + RED = 0; + GREEN = 1; + BLUE = 2; +} + +enum CamelCaseColor { + Red = 0; + Green = 1; + Blue = 2; + Yellow = 3; + Cyan = 4; + Magenta = 5; +} + +message Enums { + UpperCaseColor j = 1; + CamelCaseColor s = 2; // Enumeration + CamelCaseColor a = 3; // ADT + optional UpperCaseColor jo = 4; + optional CamelCaseColor so = 5; // Enumeration + optional CamelCaseColor ao = 6; // ADT + repeated UpperCaseColor jr = 7; + repeated CamelCaseColor sr = 8; // Enumeration + repeated CamelCaseColor ar = 9; // ADT +} + +message UnsafeEnums { string j = 1; string s = 2; string a = 3; @@ -88,21 +93,21 @@ message UnsafeEnumsP3 { repeated string ar = 9; } -message CustomP3 { +message Custom { string u = 1; int64 d = 2; } -message BytesP3 { +message Bytes { bytes b = 1; } -message UpperCaseP3 { +message UpperCase { string FIRSTFIELD = 1; string SECONDFIELD = 2; - UpperCaseInnerP3 INNERFIELD = 3; + UpperCaseInner INNERFIELD = 3; } -message UpperCaseInnerP3 { +message UpperCaseInner { string INNERFIRST = 1; } diff --git a/protobuf/src/test/scala/magnolify/protobuf/ProtobufTypeSuite.scala b/protobuf/src/test/scala/magnolify/protobuf/ProtobufTypeSuite.scala index c6cb11637..b91abb81d 100644 --- a/protobuf/src/test/scala/magnolify/protobuf/ProtobufTypeSuite.scala +++ b/protobuf/src/test/scala/magnolify/protobuf/ProtobufTypeSuite.scala @@ -24,8 +24,6 @@ import com.google.protobuf.{ByteString, Message} import magnolify.cats.auto._ import magnolify.scalacheck.auto._ import magnolify.protobuf._ -import magnolify.protobuf.Proto2._ -import magnolify.protobuf.Proto3._ import magnolify.protobuf.unsafe._ import magnolify.shared._ import magnolify.test.Simple._ @@ -55,31 +53,31 @@ trait BaseProtobufTypeSuite extends MagnolifySuite { class ProtobufTypeSuite extends BaseProtobufTypeSuite { - test[Integers, IntegersP2] - test[Integers, IntegersP3] - test[Floats, FloatsP2] - test[Floats, FloatsP3] - test[Required, RequiredP2] - test[Required, RequiredP3] - test[Nullable, NullableP2] - test[Nullable, NullableP3] - - test[Repeated, RepeatedP2] - test[Repeated, RepeatedP3] - test[Nested, NestedP2] - test[Nested, NestedP3] - test[UnsafeByte, IntegersP2] - test[UnsafeChar, IntegersP2] - test[UnsafeShort, IntegersP2] - - test[Collections, CollectionP2] - test[Collections, CollectionP3] - test[MoreCollections, MoreCollectionP2] - test[MoreCollections, MoreCollectionP3] + test[Integers, Proto2.Integers] + test[Integers, Proto3.Integers] + test[Floats, Proto2.Floats] + test[Floats, Proto3.Floats] + test[Required, Proto2.Required] + test[Required, Proto3.Required] + test[Nullable, Proto2.Nullable] + test[Nullable, Proto3.Nullable] + + test[Repeated, Proto2.Repeated] + test[Repeated, Proto3.Repeated] + test[Nested, Proto2.Nested] + test[Nested, Proto3.Nested] + test[UnsafeByte, Proto2.Integers] + test[UnsafeChar, Proto2.Integers] + test[UnsafeShort, Proto2.Integers] + + test[Collections, Proto2.Collection] + test[Collections, Proto3.Collection] + test[MoreCollections, Proto2.MoreCollection] + test[MoreCollections, Proto3.MoreCollection] test("AnyVal") { - test[ProtoHasValueClass, IntegersP2] - test[ProtoHasValueClass, IntegersP3] + test[ProtoHasValueClass, Proto2.Integers] + test[ProtoHasValueClass, Proto3.Integers] } } @@ -93,55 +91,55 @@ class MoreProtobufTypeSuite extends BaseProtobufTypeSuite { implicit val pfDuration: ProtobufField[Duration] = ProtobufField.from[Long](Duration.ofMillis)(_.toMillis) - test[BytesA, BytesP2] - test[BytesB, BytesP3] + test[BytesA, Proto2.Bytes] + test[BytesB, Proto3.Bytes] { import Proto2Enums._ - test[Enums, EnumsP2] - test[UnsafeEnums, UnsafeEnumsP2] + test[Enums, Proto2.Enums] + test[UnsafeEnums, Proto2.UnsafeEnums] } { import Proto3Enums._ - test[Enums, EnumsP3] - test[UnsafeEnums, UnsafeEnumsP3] + test[Enums, Proto3.Enums] + test[UnsafeEnums, Proto3.UnsafeEnums] } - test[Custom, CustomP2] - test[Custom, CustomP3] + test[Custom, Proto2.Custom] + test[Custom, Proto3.Custom] { - implicit val pt: ProtobufType[LowerCamel, UpperCaseP3] = - ProtobufType[LowerCamel, UpperCaseP3](CaseMapper(_.toUpperCase)) - test[LowerCamel, UpperCaseP3] + implicit val pt: ProtobufType[LowerCamel, Proto3.UpperCase] = + ProtobufType[LowerCamel, Proto3.UpperCase](CaseMapper(_.toUpperCase)) + test[LowerCamel, Proto3.UpperCase] } { import Proto2Enums._ - test[DefaultsRequired2, DefaultRequiredP2] - test[DefaultsNullable2, DefaultNullableP2] + test[DefaultsRequired2, Proto2.DefaultRequired] + test[DefaultsNullable2, Proto2.DefaultNullable] } { import Proto3Enums._ - test[DefaultIntegers3, IntegersP3] - test[DefaultFloats3, FloatsP3] - test[DefaultRequired3, RequiredP3] - test[DefaultEnums3, EnumsP3] + test[DefaultIntegers3, Proto3.Integers] + test[DefaultFloats3, Proto3.Floats] + test[DefaultRequired3, Proto3.Required] + test[DefaultEnums3, Proto3.Enums] } { - test[DefaultNullable3, NullableP3] + test[DefaultNullable3, Proto3.Nullable] } { import Proto2Enums._ type F[T] = ProtobufType[T, _] - testFail[F, DefaultMismatch2](ProtobufType[DefaultMismatch2, DefaultRequiredP2])( + testFail[F, DefaultMismatch2](ProtobufType[DefaultMismatch2, Proto2.DefaultRequired])( "Default mismatch magnolify.protobuf.DefaultMismatch2#i: 321 != 123" ) - testFail[F, DefaultMismatch3](ProtobufType[DefaultMismatch3, RequiredP3])( + testFail[F, DefaultMismatch3](ProtobufType[DefaultMismatch3, Proto3.Required])( "Default mismatch magnolify.protobuf.DefaultMismatch3#i: 321 != 0" ) } @@ -149,20 +147,20 @@ class MoreProtobufTypeSuite extends BaseProtobufTypeSuite { object Proto2Enums { implicit val efJavaEnum2: ProtobufField[JavaEnums.Color] = - ProtobufField.enum[JavaEnums.Color, EnumsP2.JavaEnums] + ProtobufField.enum[JavaEnums.Color, Proto2.UpperCaseColor] implicit val efScalaEnum2: ProtobufField[ScalaEnums.Color.Type] = - ProtobufField.enum[ScalaEnums.Color.Type, EnumsP2.ScalaEnums] + ProtobufField.enum[ScalaEnums.Color.Type, Proto2.CamelCaseColor] implicit val efAdtEnum2: ProtobufField[ADT.Color] = - ProtobufField.enum[ADT.Color, EnumsP2.ScalaEnums] + ProtobufField.enum[ADT.Color, Proto2.CamelCaseColor] } object Proto3Enums { implicit val efJavaEnum3: ProtobufField[JavaEnums.Color] = - ProtobufField.enum[JavaEnums.Color, EnumsP3.JavaEnums] + ProtobufField.enum[JavaEnums.Color, Proto3.UpperCaseColor] implicit val efScalaEnum3: ProtobufField[ScalaEnums.Color.Type] = - ProtobufField.enum[ScalaEnums.Color.Type, EnumsP3.ScalaEnums] + ProtobufField.enum[ScalaEnums.Color.Type, Proto3.CamelCaseColor] implicit val efAdtEnum3: ProtobufField[ADT.Color] = - ProtobufField.enum[ADT.Color, EnumsP3.ScalaEnums] + ProtobufField.enum[ADT.Color, Proto3.CamelCaseColor] } case class ProtoValueClass(value: Long) extends AnyVal @@ -183,7 +181,7 @@ case class DefaultsRequired2( bs: ByteString = ByteString.copyFromUtf8("def"), je: JavaEnums.Color = JavaEnums.Color.GREEN, se: ScalaEnums.Color.Type = ScalaEnums.Color.Green, - ae: ADT.Color = ADT.Green + ae: ADT.Color = ADT.Cyan ) case class DefaultsNullable2( @@ -196,7 +194,7 @@ case class DefaultsNullable2( bs: Option[ByteString] = Some(ByteString.copyFromUtf8("def")), je: Option[JavaEnums.Color] = Some(JavaEnums.Color.GREEN), se: Option[ScalaEnums.Color.Type] = Some(ScalaEnums.Color.Green), - ae: Option[ADT.Color] = Some(ADT.Green) + ae: Option[ADT.Color] = Some(ADT.Cyan) ) case class DefaultIntegers3(i: Int = 0, l: Long = 0) @@ -223,6 +221,6 @@ case class DefaultMismatch2( bs: ByteString = ByteString.copyFromUtf8("def"), je: JavaEnums.Color = JavaEnums.Color.GREEN, se: ScalaEnums.Color.Type = ScalaEnums.Color.Green, - ae: ADT.Color = ADT.Green + ae: ADT.Color = ADT.Cyan ) case class DefaultMismatch3(i: Int = 321, l: Long = 0) From 42e7aef0610a8ae78741d4658e993a0b267cf251 Mon Sep 17 00:00:00 2001 From: Michel Davit Date: Tue, 4 Jun 2024 10:41:54 +0200 Subject: [PATCH 3/4] Fix refined tests --- .../src/test/scala/magnolify/refined/RefinedSuite.scala | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/refined/src/test/scala/magnolify/refined/RefinedSuite.scala b/refined/src/test/scala/magnolify/refined/RefinedSuite.scala index 6eff3de7c..c2259b34a 100644 --- a/refined/src/test/scala/magnolify/refined/RefinedSuite.scala +++ b/refined/src/test/scala/magnolify/refined/RefinedSuite.scala @@ -59,6 +59,7 @@ object RefinedSuite { case class ProtoNullable(b: Option[Boolean], i: Option[Percent], s: Option[ProtoUrl]) case class ProtoRepeated(b: List[Boolean], i: List[Percent], s: List[ProtoCountry]) } + class RefinedSuite extends MagnolifySuite { import RefinedSuite._ @@ -157,7 +158,7 @@ class RefinedSuite extends MagnolifySuite { import magnolify.protobuf._ import magnolify.protobuf.Proto3._ import magnolify.refined.protobuf._ - val tpe1 = ensureSerializable(ProtobufType[ProtoRequired, RequiredP3]) + val tpe1 = ensureSerializable(ProtobufType[ProtoRequired, Required]) val required = ProtoRequired( b = true, i = record.pct, @@ -165,7 +166,7 @@ class RefinedSuite extends MagnolifySuite { ) assertEquals(tpe1(tpe1(required)), required) - val tpe2 = ensureSerializable(ProtobufType[ProtoNullable, NullableP3]) + val tpe2 = ensureSerializable(ProtobufType[ProtoNullable, Nullable]) val nullable = ProtoNullable( b = Some(true), i = Some(record.pct), @@ -173,7 +174,7 @@ class RefinedSuite extends MagnolifySuite { ) assertEquals(tpe2(tpe2(nullable)), nullable) - val tpe3 = ensureSerializable(ProtobufType[ProtoRepeated, RepeatedP3]) + val tpe3 = ensureSerializable(ProtobufType[ProtoRepeated, Repeated]) val repeated = ProtoRepeated( b = List(true), i = List(record.pct), @@ -181,7 +182,7 @@ class RefinedSuite extends MagnolifySuite { ) assertEquals(tpe3(tpe3(repeated)), repeated) - val bad = NullableP3.newBuilder().setB(true).setI(42).setS("foo").build() + val bad = Nullable.newBuilder().setB(true).setI(42).setS("foo").build() val msg = """Both predicates of (isValidUrl("foo") || "foo".matches("^$")) failed. """ + """Left: Url predicate failed: URI is not absolute """ + """Right: Predicate failed: "foo".matches("^$").""" From 8a84b29668e019e3bb35269667aa579a9b46a37f Mon Sep 17 00:00:00 2001 From: Michel Davit Date: Wed, 5 Jun 2024 14:49:29 +0200 Subject: [PATCH 4/4] Fix 2.12 serialization issue --- test/src/test/scala/magnolify/test/ADT.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/src/test/scala/magnolify/test/ADT.scala b/test/src/test/scala/magnolify/test/ADT.scala index 3de88f338..053835bbe 100644 --- a/test/src/test/scala/magnolify/test/ADT.scala +++ b/test/src/test/scala/magnolify/test/ADT.scala @@ -33,7 +33,7 @@ object ADT { case class Circle(r: Int) extends Shape @ScalaAnnotation("Color") - sealed trait Color + sealed trait Color extends Serializable // Serializable needed for 2.12 @ScalaAnnotation("PrimaryColor") sealed trait PrimaryColor extends Color case object Red extends PrimaryColor