Skip to content

Commit

Permalink
Merge pull request #423 from ezimanyi/add-optional-support
Browse files Browse the repository at this point in the history
Add support for proto3 optional fields
  • Loading branch information
pseudomuto authored Sep 10, 2020
2 parents e3c1529 + f042560 commit f06de7a
Show file tree
Hide file tree
Showing 8 changed files with 121 additions and 5 deletions.
12 changes: 12 additions & 0 deletions fixtures/Cookie.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
syntax = "proto3";

package com.example;

/**
* Represents a cookie.
*/
message Cookie {
string id = 1; // The id of the cookie.
optional string name = 2; // The name of the cookie.
repeated string ingredients = 3; // Ingredients in the cookie.
}
Binary file added fixtures/cookie.pb
Binary file not shown.
6 changes: 6 additions & 0 deletions fixtures/generate.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
package fixtures

//go:generate protoc --descriptor_set_out=fileset.pb --include_imports --include_source_info -I. -I../thirdparty Booking.proto Vehicle.proto

// Compiling proto3 optional fields requires using protoc >=3.12.x and passing the --experimental_allow_proto3_optional flag.
// Rather than use this flag to compile all of the protocol buffers (which would eliminate test coverage for descriptors
// compiled without the flag), only pass this flag when compiling the one message explicitly testing proto3 optional fields.
// Once this feature is no longer behind an experimental flag, compilation of Cookie.proto can be moved to the above protoc command.
//go:generate protoc --experimental_allow_proto3_optional --descriptor_set_out=cookie.pb --include_imports --include_source_info -I. -I../thirdparty Cookie.proto
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ require (
github.com/davecgh/go-spew v0.0.0-20161028175848-04cdfd42973b // indirect
github.com/envoyproxy/protoc-gen-validate v0.3.0-java
github.com/gogo/protobuf v1.1.1 // indirect
github.com/golang/protobuf v1.1.0
github.com/golang/protobuf v1.4.2
github.com/google/uuid v0.0.0-20161128191214-064e2069ce9c // indirect
github.com/huandu/xstrings v1.0.0 // indirect
github.com/imdario/mergo v0.3.4 // indirect
Expand Down
18 changes: 18 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,16 @@ github.com/gogo/protobuf v1.1.1 h1:72R+M5VuhED/KujmZVcIquuo8mBgX4oVda//DQb3PXo=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/golang/protobuf v1.1.0 h1:0iH4Ffd/meGoXqF2lSAhZHt8X+cPgkfn/cb6Cce5Vpc=
github.com/golang/protobuf v1.1.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/uuid v0.0.0-20161128191214-064e2069ce9c h1:jWtZjFEUE/Bz0IeIhqCnyZ3HG6KRXSntXe4SjtuTH7c=
github.com/google/uuid v0.0.0-20161128191214-064e2069ce9c/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/huandu/xstrings v1.0.0 h1:pO2K/gKgKaat5LdpAhxhluX2GPQMaI3W5FUz/I/UnWk=
Expand All @@ -30,8 +40,16 @@ golang.org/x/crypto v0.0.0-20180501155221-613d6eafa307 h1:O5C+XK++apFo5B+Vq4ujc/
golang.org/x/crypto v0.0.0-20180501155221-613d6eafa307/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/sync v0.0.0-20190412183630-56d357773e84 h1:IqXQ59gzdXv58Jmm2xn0tSOR9i6HqroaOFRQ3wR/dJQ=
golang.org/x/sync v0.0.0-20190412183630-56d357773e84/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/genproto v0.0.0-20181107211654-5fc9ac540362 h1:b69RmkJsx8NyRJsKF2mQ/AF8s4BNxwNsT4rQ3wON1U0=
google.golang.org/genproto v0.0.0-20181107211654-5fc9ac540362/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
google.golang.org/protobuf v1.23.0 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
Expand Down
3 changes: 3 additions & 0 deletions plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ type PluginOptions struct {
ExcludePatterns []*regexp.Regexp
}

var SupportedFeatures = uint64(plugin_go.CodeGeneratorResponse_FEATURE_PROTO3_OPTIONAL)

// Plugin describes a protoc code generate plugin. It's an implementation of Plugin from github.com/pseudomuto/protokit
type Plugin struct{}

Expand Down Expand Up @@ -56,6 +58,7 @@ func (p *Plugin) Generate(r *plugin_go.CodeGeneratorRequest) (*plugin_go.CodeGen
Name: proto.String(options.OutputFile),
Content: proto.String(string(output)),
})
resp.SupportedFeatures = proto.Uint64(SupportedFeatures)

return resp, nil
}
Expand Down
8 changes: 4 additions & 4 deletions template.go
Original file line number Diff line number Diff line change
Expand Up @@ -422,7 +422,7 @@ func parseFileExtension(pe *protokit.ExtensionDescriptor) *FileExtension {
LongName: pe.GetLongName(),
FullName: pe.GetFullName(),
Description: description(pe.GetComments().String()),
Label: labelName(pe.GetLabel(), pe.IsProto3()),
Label: labelName(pe.GetLabel(), pe.IsProto3(), pe.GetProto3Optional()),
Type: t,
LongType: lt,
FullType: ft,
Expand Down Expand Up @@ -473,7 +473,7 @@ func parseMessageField(pf *protokit.FieldDescriptor) *MessageField {
m := &MessageField{
Name: pf.GetName(),
Description: description(pf.GetComments().String()),
Label: labelName(pf.GetLabel(), pf.IsProto3()),
Label: labelName(pf.GetLabel(), pf.IsProto3(), pf.GetProto3Optional()),
Type: t,
LongType: lt,
FullType: ft,
Expand Down Expand Up @@ -532,8 +532,8 @@ func baseName(name string) string {
return parts[len(parts)-1]
}

func labelName(lbl descriptor.FieldDescriptorProto_Label, proto3 bool) string {
if proto3 && lbl != descriptor.FieldDescriptorProto_LABEL_REPEATED {
func labelName(lbl descriptor.FieldDescriptorProto_Label, proto3 bool, proto3Opt bool) string {
if proto3 && !proto3Opt && lbl != descriptor.FieldDescriptorProto_LABEL_REPEATED {
return ""
}

Expand Down
77 changes: 77 additions & 0 deletions template_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ var (
template *Template
bookingFile *File
vehicleFile *File

cookieTemplate *Template
cookieFile *File
)

func TestMain(m *testing.M) {
Expand All @@ -30,6 +33,12 @@ func TestMain(m *testing.M) {
bookingFile = template.Files[0]
vehicleFile = template.Files[1]

set, _ = utils.LoadDescriptorSet("fixtures", "cookie.pb")
req = utils.CreateGenRequest(set, "Cookie.proto")
result = protokit.ParseCodeGenRequest(req)
cookieTemplate = NewTemplate(result)
cookieFile = cookieTemplate.Files[0]

os.Exit(m.Run())
}

Expand Down Expand Up @@ -281,6 +290,74 @@ func TestFieldProperties(t *testing.T) {
require.False(t, field.IsMap)
}

func TestFieldPropertiesProto3(t *testing.T) {
msg := findMessage("Model", vehicleFile)

field := findField("id", msg)
require.Equal(t, "id", field.Name)
require.Equal(t, "The unique model ID.", field.Description)
require.Equal(t, "", field.Label)
require.Equal(t, "string", field.Type)
require.Equal(t, "string", field.LongType)
require.Equal(t, "string", field.FullType)
require.Empty(t, field.DefaultValue)
require.Empty(t, field.Options)

field = findField("model_code", msg)
require.Equal(t, "model_code", field.Name)
require.Equal(t, "The car model code, e.g. \"PZ003\".", field.Description)
require.Equal(t, "", field.Label)
require.Equal(t, "string", field.Type)
require.Equal(t, "string", field.LongType)
require.Equal(t, "string", field.FullType)
require.Empty(t, field.DefaultValue)
require.Empty(t, field.Options)

field = findField("daily_hire_rate_dollars", msg)
require.Equal(t, "daily_hire_rate_dollars", field.Name)
require.Equal(t, "Dollars per day.", field.Description)
require.Equal(t, "", field.Label)
require.Equal(t, "sint32", field.Type)
require.Equal(t, "sint32", field.LongType)
require.Equal(t, "sint32", field.FullType)
require.Empty(t, field.DefaultValue)
require.Empty(t, field.Options)
}

func TestFieldPropertiesProto3Optional(t *testing.T) {
msg := findMessage("Cookie", cookieFile)

field := findField("id", msg)
require.Equal(t, "id", field.Name)
require.Equal(t, "The id of the cookie.", field.Description)
require.Equal(t, "", field.Label)
require.Equal(t, "string", field.Type)
require.Equal(t, "string", field.LongType)
require.Equal(t, "string", field.FullType)
require.Empty(t, field.DefaultValue)
require.Empty(t, field.Options)

field = findField("name", msg)
require.Equal(t, "name", field.Name)
require.Equal(t, "The name of the cookie.", field.Description)
require.Equal(t, "optional", field.Label)
require.Equal(t, "string", field.Type)
require.Equal(t, "string", field.LongType)
require.Equal(t, "string", field.FullType)
require.Empty(t, field.DefaultValue)
require.Empty(t, field.Options)

field = findField("ingredients", msg)
require.Equal(t, "ingredients", field.Name)
require.Equal(t, "Ingredients in the cookie.", field.Description)
require.Equal(t, "repeated", field.Label)
require.Equal(t, "string", field.Type)
require.Equal(t, "string", field.LongType)
require.Equal(t, "string", field.FullType)
require.Empty(t, field.DefaultValue)
require.Empty(t, field.Options)
}

func TestServiceProperties(t *testing.T) {
service := findService("VehicleService", vehicleFile)
require.Equal(t, "VehicleService", service.Name)
Expand Down

0 comments on commit f06de7a

Please sign in to comment.