Skip to content

Commit

Permalink
Support enums with unknown value.
Browse files Browse the repository at this point in the history
Fixes #11
  • Loading branch information
thesamet committed Aug 23, 2015
1 parent 388c86f commit e3cd8b1
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ class ProtobufGenerator(val params: GeneratorParams) extends DescriptorPimps {
case (v, p) => p.add(
s"def is${v.objectName}: Boolean = false")
}
.add(s"def isUnrecognized: Boolean = false")
.add(s"def companion: com.trueaccord.scalapb.GeneratedEnumCompanion[$name] = $name")
.outdent
.add("}")
Expand All @@ -35,11 +36,20 @@ class ProtobufGenerator(val params: GeneratorParams) extends DescriptorPimps {
|}
|""")
}
.addM(
s"""@SerialVersionUID(0L)
|case class Unrecognized(value: Int) extends $name {
| val name = "UNRECOGNIZED"
| val index = -1
| override def isUnrecognized: Boolean = true
|}
|""")
.add(s"lazy val values = Seq(${e.getValues.map(_.getName.asSymbol).mkString(", ")})")
.add(s"def fromValue(value: Int): $name = value match {")
.print(e.getValues) {
case (v, p) => p.add(s" case ${v.getNumber} => ${v.getName.asSymbol}")
}
.add(s" case __other => Unrecognized(__other)")
.add("}")
.when(e.isTopLevel)(_.add(s"def descriptor: com.google.protobuf.Descriptors.EnumDescriptor = ${e.getFile.fileDescriptorObjectName}.descriptor.getEnumTypes.get(${e.getIndex})"))
.when(!e.isTopLevel)(_.add(s"def descriptor: com.google.protobuf.Descriptors.EnumDescriptor = ${e.getContainingType.scalaTypeName}.descriptor.getEnumTypes.get(${e.getIndex})"))
Expand Down Expand Up @@ -177,7 +187,7 @@ class ProtobufGenerator(val params: GeneratorParams) extends DescriptorPimps {
s"${container}.get${field.upperScalaName}.map(__pv => (${unitConversion("__pv._1", field.mapType.keyField)}, ${unitConversion("__pv._2", field.mapType.valueField)})).toMap"
}

def scalaToJava(field: FieldDescriptor, boxPrimitives: Boolean): LiteralExpression = {
def scalaToJava(field: FieldDescriptor, boxPrimitives: Boolean): Expression = {
def maybeBox(name: String) = if (boxPrimitives) FunctionApplication(name) else Identity

field.getJavaType match {
Expand All @@ -190,17 +200,22 @@ class ProtobufGenerator(val params: GeneratorParams) extends DescriptorPimps {
case FieldDescriptor.JavaType.STRING => Identity
case FieldDescriptor.JavaType.MESSAGE => FunctionApplication(
field.getMessageType.scalaTypeName + ".toJavaProto")
case FieldDescriptor.JavaType.ENUM => FunctionApplication(
field.getEnumType.scalaTypeName + ".toJavaValue")
case FieldDescriptor.JavaType.ENUM => if (field.getFile.isProto3)
(MethodApplication("value") andThen maybeBox("Int.box"))
else
FunctionApplication(field.getEnumType.scalaTypeName + ".toJavaValue")
}
}

def assignScalaMapToJava(scalaObject: String, javaObject: String, field: FieldDescriptor): String = {
def valueConvert(v: String, field: FieldDescriptor) =
scalaToJava(field, boxPrimitives = true).apply(v, isCollection = false)

val getMutableMap = s"getMutable${field.upperScalaName}" + (
if (field.mapType.valueField.isEnum) "Value" else "")

s"""$javaObject
| .getMutable${field.upperScalaName}
| .$getMutableMap()
| .putAll(
| $scalaObject.${fieldAccessorSymbol(field)}.map {
| __kv => (${valueConvert("__kv._1", field.mapType.keyField)}, ${valueConvert("__kv._2", field.mapType.valueField)})
Expand All @@ -213,7 +228,8 @@ class ProtobufGenerator(val params: GeneratorParams) extends DescriptorPimps {
if (field.isMap) assignScalaMapToJava(scalaObject, javaObject, field) else {
val javaSetter = javaObject +
(if (field.isRepeated) ".addAll" else
".set") + field.upperScalaName
".set") + field.upperScalaName + (
if (field.isEnum && field.getFile.isProto3) "Value" else "")
val scalaGetter = scalaObject + "." + fieldAccessorSymbol(field)

val scalaExpr = (toBaseTypeExpr(field) andThen scalaToJava(field, boxPrimitives = field.isRepeated)).apply(
Expand Down
34 changes: 34 additions & 0 deletions e2e/src/test/scala/EnumSpec.scala
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import com.trueaccord.proto.e2e.enum._
import com.trueaccord.proto.e2e.enum3._
import org.scalatest._

class EnumSpec extends FlatSpec with MustMatchers {
val red = EnumTest(color = Some(Color.RED))
val green = EnumTest(color = Some(Color.GREEN))
val blue = EnumTest(color = Some(Color.BLUE))
val unrecognized = EnumTest(color = Some(Color.Unrecognized(37)))
val noColor = EnumTest()
val innerEnum = EnumTest(innerEnum = Some(EnumTest.InnerEnum.INNER_SUCCESS))
val otherCase = EnumTest(innerEnum = Some(EnumTest.InnerEnum.OtherCase))
Expand All @@ -22,14 +24,22 @@ class EnumSpec extends FlatSpec with MustMatchers {
red.color.get.isRed must be(true)
red.color.get.isGreen must be(false)
red.color.get.isBlue must be(false)
red.color.get.isUnrecognized must be(false)

green.color.get.isRed must be(false)
green.color.get.isGreen must be(true)
green.color.get.isBlue must be(false)
green.color.get.isUnrecognized must be(false)

blue.color.get.isRed must be(false)
blue.color.get.isGreen must be(false)
blue.color.get.isBlue must be(true)
blue.color.get.isUnrecognized must be(false)

unrecognized.color.get.isRed must be(false)
unrecognized.color.get.isGreen must be(false)
unrecognized.color.get.isBlue must be(false)
unrecognized.color.get.isUnrecognized must be(true)

innerEnum.getInnerEnum.isInnerSuccess must be(true)
innerEnum.getInnerEnum.isOtherCase must be(false)
Expand All @@ -42,12 +52,14 @@ class EnumSpec extends FlatSpec with MustMatchers {
case Some(Color.BLUE) => "blue"
case Some(Color.GREEN) => "green"
case Some(Color.RED) => "red"
case Some(Color.Unrecognized(x)) => s"unrecognized:$x"
case None => "none"
}

colorWord(blue.color) must be("blue")
colorWord(red.color) must be("red")
colorWord(green.color) must be("green")
colorWord(unrecognized.color) must be("unrecognized:37")
colorWord(noColor.color) must be("none")
}

Expand All @@ -60,6 +72,7 @@ class EnumSpec extends FlatSpec with MustMatchers {
red.getOtherColor must be(Color.BLUE)
green.getOtherColor must be(Color.BLUE)
blue.getOtherColor must be(Color.BLUE)
unrecognized.getOtherColor must be(Color.BLUE)
blue.getOtherColor.isBlue must be(true)
}

Expand All @@ -75,4 +88,25 @@ class EnumSpec extends FlatSpec with MustMatchers {
innerEnum = Some(EnumTest.InnerEnum.OtherCase)))
}

"missing enum values in proto3" should "be preserved in parsing" in {
val like = EnumTestLike(color = 18) // same field number as `color` in EnumTest3.
val e3 = EnumTest3.parseFrom(like.toByteArray)
e3.color must be (Color3.Unrecognized(18))
e3.color must not be (Color3.Unrecognized(19))
e3.toByteArray must be (like.toByteArray)
}

"missing enum values in proto3 seq" should "be preserved in parsing" in {
val e3 = EnumTest3(colorVector = Seq(Color3.C3_RED, Color3.Unrecognized(15), Color3.C3_BLUE))
EnumTest3.parseFrom(e3.toByteArray) must be (e3)
}

"missing enum values in proto2" should "be preserved in parsing" in {
val like = EnumTestLike(color = 18) // same field number as `color` in EnumTest3.
val e3 = EnumTest.parseFrom(like.toByteArray)
e3.getColor must be (Color.Unrecognized(18))
e3.getColor must not be (Color.Unrecognized(19))
e3.toByteArray must be (like.toByteArray)
}

}

0 comments on commit e3cd8b1

Please sign in to comment.