diff --git a/e2e/src/test/scala/ExtensionsSpec.scala b/e2e/src/test/scala/ExtensionsSpec.scala index 0a31925ad..efde89f09 100644 --- a/e2e/src/test/scala/ExtensionsSpec.scala +++ b/e2e/src/test/scala/ExtensionsSpec.scala @@ -1,7 +1,11 @@ +import com.google.protobuf.descriptor.FileDescriptorProto +import com.thesamet.proto.e2e.custom_options.CustomOptionsProto.{messageC, optName} +import com.thesamet.proto.e2e.custom_options_use.FooMessage import com.thesamet.proto.e2e.extensions._ import org.scalatest._ import org.scalatest.flatspec.AnyFlatSpec import org.scalatest.matchers.must.Matchers +import scalapb.descriptors.FileDescriptor class ExtensionsSpec extends AnyFlatSpec with Matchers with OptionValues { "BaseMessage.parseFrom" should "parse unknown fields" in { @@ -17,4 +21,26 @@ class ExtensionsSpec extends AnyFlatSpec with Matchers with OptionValues { extended.extension(Extension.optInt) must be(Some(12)) extended.extension(Extension.optString) must be(Some("bar")) } + + "BaseMessage.parseFrom" should "parse extensions after full serialization cycle" in { + //** Serializing side **// + val fooFile = FooMessage.scalaDescriptor.file + val serialized = com.google.protobuf.descriptor.FileDescriptorProto.toByteArray(fooFile.asProto) + + //** De-serializing side **/ + val javaFileDescriptorProto = com.google.protobuf.DescriptorProtos.FileDescriptorProto.parseFrom(serialized) + + // Prior to PR #1963 the scalaFileDescriptorProto did not contain the options/extensions... + val javaFileDescriptor = FileDescriptorProto.fromJavaProto(javaFileDescriptorProto) + + // ...and subsequently, the resulting fileDescriptor was also missing the options/extensions + val fileDescriptor = FileDescriptor.buildFrom(javaFileDescriptor, Nil) + + val revivedFieldDescriptor = fileDescriptor.messages.find(_.name == "FooMessage").get.fields.find(_.name == "myField1").get + + val messageCOption = revivedFieldDescriptor.asProto.getOptions.extension(messageC).get + val optNameOption = revivedFieldDescriptor.asProto.getOptions.extension(optName).get + messageCOption.c must be (Some("CCC")) + optNameOption.firstName must be ("John") + } } diff --git a/scalapb-runtime/src/main/scalajvm/com/google/protobuf/descriptor/FieldOptions.scala b/scalapb-runtime/src/main/scalajvm/com/google/protobuf/descriptor/FieldOptions.scala index c4d0f42ca..809b95eb1 100644 --- a/scalapb-runtime/src/main/scalajvm/com/google/protobuf/descriptor/FieldOptions.scala +++ b/scalapb-runtime/src/main/scalajvm/com/google/protobuf/descriptor/FieldOptions.scala @@ -358,7 +358,8 @@ object FieldOptions extends scalapb.GeneratedMessageCompanion[com.google.protobu editionDefaults = javaPbSource.getEditionDefaultsList.asScala.iterator.map(com.google.protobuf.descriptor.FieldOptions.EditionDefault.fromJavaProto(_)).toSeq, features = if (javaPbSource.hasFeatures) Some(com.google.protobuf.descriptor.FeatureSet.fromJavaProto(javaPbSource.getFeatures)) else _root_.scala.None, featureSupport = if (javaPbSource.hasFeatureSupport) Some(com.google.protobuf.descriptor.FieldOptions.FeatureSupport.fromJavaProto(javaPbSource.getFeatureSupport)) else _root_.scala.None, - uninterpretedOption = javaPbSource.getUninterpretedOptionList.asScala.iterator.map(com.google.protobuf.descriptor.UninterpretedOption.fromJavaProto(_)).toSeq + uninterpretedOption = javaPbSource.getUninterpretedOptionList.asScala.iterator.map(com.google.protobuf.descriptor.UninterpretedOption.fromJavaProto(_)).toSeq, + unknownFields = UnknownFieldSetProto.fromJavaProto(javaPbSource.getUnknownFields) ) def parseFrom(`_input__`: _root_.com.google.protobuf.CodedInputStream): com.google.protobuf.descriptor.FieldOptions = { var __ctype: _root_.scala.Option[com.google.protobuf.descriptor.FieldOptions.CType] = _root_.scala.None @@ -1235,4 +1236,19 @@ object FieldOptions extends scalapb.GeneratedMessageCompanion[com.google.protobu uninterpretedOption ) // @@protoc_insertion_point(GeneratedMessageCompanion[google.protobuf.FieldOptions]) + + object UnknownFieldSetProto { + def fromJavaProto(javaUnknownFieldSet: com.google.protobuf.UnknownFieldSet): _root_.scalapb.UnknownFieldSet = { + javaUnknownFieldSet.asMap.asScala.foldLeft(_root_.scalapb.UnknownFieldSet.empty) { + case (aggregator, (key, field)) => + aggregator.withField(key.toInt, new _root_.scalapb.UnknownFieldSet.Field( + varint = field.getVarintList.asScala.map(Long2long).toSeq, + fixed64 = field.getFixed64List.asScala.map(Long2long).toSeq, + fixed32 = field.getFixed32List.asScala.map(_.toInt).toSeq, + lengthDelimited = field.getLengthDelimitedList.asScala.toSeq, + ) + ) + } + } + } }