diff --git a/src/main/scala/higherkindness/skeuomorph/mu/codegen.scala b/src/main/scala/higherkindness/skeuomorph/mu/codegen.scala index 0fed913a..d8ec379d 100644 --- a/src/main/scala/higherkindness/skeuomorph/mu/codegen.scala +++ b/src/main/scala/higherkindness/skeuomorph/mu/codegen.scala @@ -23,6 +23,7 @@ import higherkindness.droste._ import higherkindness.skeuomorph.mu.MuF._ import higherkindness.skeuomorph.mu.Optimize._ import higherkindness.skeuomorph.{protobuf => pb} +import higherkindness.skeuomorph.Printer.toValidIdentifier import scala.reflect.ClassTag import cats.syntax.either._ import cats.syntax.traverse._ @@ -47,6 +48,7 @@ object codegen { )(implicit T: Basis[MuF, T]): Either[String, Pkg] = { val packageName = protocol.pkg + .map(_.split('.').toList.map(toValidIdentifier).mkString(".")) .getOrElse("proto") .parse[Term] .toEither diff --git a/src/test/scala/higherkindness/skeuomorph/protobuf/ProtobufProtocolSpec.scala b/src/test/scala/higherkindness/skeuomorph/protobuf/ProtobufProtocolSpec.scala index 9de0b14f..57ea4f97 100644 --- a/src/test/scala/higherkindness/skeuomorph/protobuf/ProtobufProtocolSpec.scala +++ b/src/test/scala/higherkindness/skeuomorph/protobuf/ProtobufProtocolSpec.scala @@ -52,6 +52,8 @@ class ProtobufProtocolSpec extends Specification with ScalaCheck { It should generate correct Scala code for a subset of the opencensus Protobuf protocol's models. $codegenOpencensus The generated Scala code should include appropriately tagged integer types. $codegenTaggedIntegers + + The generated Scala code should escape 'type' keyword in package (directory) names. $codegenGoogleApi """ def codegenProtobufProtocol = @@ -368,4 +370,21 @@ class ProtobufProtocolSpec extends Specification with ScalaCheck { | ) |} |""".stripMargin + + def codegenGoogleApi = { + val googleApiProtocol: Protocol[Mu[ProtobufF]] = { + val path = workingDirectory + s"$testDirectory/models/type" + val source = ProtoSource(s"date.proto", path, importRoot) + parseProto[IO, Mu[ProtobufF]].parse(source).unsafeRunSync() + } + + check(googleApiProtocol, googleApiExpectation) + } + + val googleApiExpectation = s""" + |package google.`type` + |import _root_.higherkindness.mu.rpc.protocol._ + |object date { final case class Date(@_root_.pbdirect.pbIndex(1) year: _root_.scala.Int, @_root_.pbdirect.pbIndex(2) month: _root_.scala.Int, @_root_.pbdirect.pbIndex(3) day: _root_.scala.Int) } + |""".stripMargin + } diff --git a/src/test/scala/higherkindness/skeuomorph/protobuf/models/type/date.proto b/src/test/scala/higherkindness/skeuomorph/protobuf/models/type/date.proto new file mode 100644 index 00000000..b958feeb --- /dev/null +++ b/src/test/scala/higherkindness/skeuomorph/protobuf/models/type/date.proto @@ -0,0 +1,50 @@ +// Copyright 2019 Google LLC. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +syntax = "proto3"; + +package google.type; + +option cc_enable_arenas = true; +option go_package = "google.golang.org/genproto/googleapis/type/date;date"; +option java_multiple_files = true; +option java_outer_classname = "DateProto"; +option java_package = "com.google.type"; +option objc_class_prefix = "GTP"; + +// Represents a whole or partial calendar date, e.g. a birthday. The time of day +// and time zone are either specified elsewhere or are not significant. The date +// is relative to the Proleptic Gregorian Calendar. This can represent: +// +// * A full date, with non-zero year, month and day values +// * A month and day value, with a zero year, e.g. an anniversary +// * A year on its own, with zero month and day values +// * A year and month value, with a zero day, e.g. a credit card expiration date +// +// Related types are [google.type.TimeOfDay][google.type.TimeOfDay] and `google.protobuf.Timestamp`. +message Date { + // Year of date. Must be from 1 to 9999, or 0 if specifying a date without + // a year. + int32 year = 1; + + // Month of year. Must be from 1 to 12, or 0 if specifying a year without a + // month and day. + int32 month = 2; + + // Day of month. Must be from 1 to 31 and valid for the year and month, or 0 + // if specifying a year by itself or a year and month where the day is not + // significant. + int32 day = 3; +}