Repository: googleapis/gapic-generator-go
Pull request #21 (2018-10-02 00:45:07)

sample: properly write oneof fields

pongad: @hzyi-google PTAL

Patch:
diff --git a/cmd/gen-go-sample/inittree.go b/cmd/gen-go-sample/inittree.go
index 9cf3b2a..912cbc0 100644
--- a/cmd/gen-go-sample/inittree.go
+++ b/cmd/gen-go-sample/inittree.go
@@ -41,7 +41,7 @@ type initType struct {
 
 	// valFmt, if not nil, post-processes values to be included into init struct.
 	// NOTE(pongad): This func signature might seem too general. I think it is just general enough
-	// to deal with enums and oneofs. Time will tell.
+	// to deal with enums and bytes. Time will tell.
 	valFmt func(*generator, string) (string, error)
 }
 
@@ -166,7 +166,6 @@ func (t *initTree) Parse(txt string, info pbinfo.Info) error {
 	}
 
 	// TODO(pongad): handle resource names
-	// TODO(pongad): properly print oneof fields
 equal:
 	switch r := sc.Scan(); r {
 	case scanner.Int, scanner.Float, scanner.String, scanner.Ident:
@@ -195,7 +194,7 @@ equal:
 
 func (t *initTree) Print(w io.Writer, g *generator) error {
 	bw := bufio.NewWriter(w)
-	err := t.print(bw, g, 1)
+	err := t.print(bw, g, 0)
 	if err2 := bw.Flush(); err == nil {
 		err = err2
 	}
@@ -222,32 +221,64 @@ func (t *initTree) print(w *bufio.Writer, g *generator, ind int) error {
 	}
 	g.imports[impSpec] = true
 
+	// map field name to oneof name
+	var oneofs map[string]string
+	if msg, ok := desc.(*descriptor.DescriptorProto); ok {
+		oneofs = map[string]string{}
+		for _, f := range msg.Field {
+			if f.OneofIndex != nil {
+				oneofs[f.GetName()] = msg.OneofDecl[*f.OneofIndex].GetName()
+			}
+		}
+	}
+
+	indent := func(j int) {
+		for i := 0; i < j; i++ {
+			w.WriteByte('\t')
+		}
+	}
+
 	fmt.Fprintf(w, "&%s.%s{\n", impSpec.Name, desc.GetName())
 	for i, k := range t.keys {
-		for i := 0; i < ind; i++ {
-			w.WriteByte('\t')
+		indent(ind + 1)
+
+		var closeBrace bool
+		if oneof, ok := oneofs[k]; ok {
+			fmt.Fprintf(w, "%s: &%s.%s_%s{\n", snakeToCapCamel(oneof), impSpec.Name, desc.GetName(), snakeToCapCamel(k))
+			closeBrace = true
+			indent(ind + 2)
 		}
-		snakeToCapCamel(w, k)
+		w.WriteString(snakeToCapCamel(k))
+
 		w.WriteString(": ")
 		if err := t.vals[i].print(w, g, ind+1); err != nil {
 			return err
 		}
+
+		if closeBrace {
+			w.WriteString(",\n")
+			indent(ind + 1)
+			w.WriteByte('}')
+		}
 		w.WriteString(",\n")
 	}
+	indent(ind)
 	w.WriteString("}")
 	return nil
 }
 
-func snakeToCapCamel(w *bufio.Writer, s string) {
+func snakeToCapCamel(s string) string {
+	var sb strings.Builder
 	cap := true
 	for _, r := range s {
 		if r == '_' {
 			cap = true
 		} else if cap {
 			cap = false
-			w.WriteRune(unicode.ToUpper(r))
+			sb.WriteRune(unicode.ToUpper(r))
 		} else {
-			w.WriteRune(r)
+			sb.WriteRune(r)
 		}
 	}
+	return sb.String()
 }


Test patch:
diff --git a/cmd/gen-go-sample/main_test.go b/cmd/gen-go-sample/main_test.go
index 45c3c84..260bcd5 100644
--- a/cmd/gen-go-sample/main_test.go
+++ b/cmd/gen-go-sample/main_test.go
@@ -49,10 +49,14 @@ func diff(t *testing.T, name, got, goldenFile string) {
 func TestSample(t *testing.T) {
 	inType := &descriptor.DescriptorProto{
 		Name: proto.String("InputType"),
+		OneofDecl: []*descriptor.OneofDescriptorProto{
+			{Name: proto.String("Group")},
+		},
 		Field: []*descriptor.FieldDescriptorProto{
 			{Name: proto.String("a"), TypeName: proto.String("AType")},
 			{Name: proto.String("b"), Type: typep(descriptor.FieldDescriptorProto_TYPE_STRING)},
 			{Name: proto.String("e"), TypeName: proto.String("EType")},
+			{Name: proto.String("f"), Type: typep(descriptor.FieldDescriptorProto_TYPE_STRING), OneofIndex: proto.Int32(0)},
 		},
 	}
 	aType := &descriptor.DescriptorProto{
@@ -116,6 +120,7 @@ func TestSample(t *testing.T) {
 				`a.y = 3.14159`,
 				`b = "foobar"`,
 				`e = FOO`,
+				`f = "in a oneof"`,
 			},
 		},
 	}
diff --git a/cmd/gen-go-sample/testdata/sample.want b/cmd/gen-go-sample/testdata/sample.want
index 8cbabfb..270957a 100644
--- a/cmd/gen-go-sample/testdata/sample.want
+++ b/cmd/gen-go-sample/testdata/sample.want
@@ -31,9 +31,12 @@ req := &foopb.InputType{
 	A: &foopb.AType{
 		X: 42,
 		Y: 3.14159,
-},
+	},
 	B: "foobar",
 	E: foopb.AType_FOO,
+	Group: &foopb.InputType_F{
+		F: "in a oneof",
+	},
 }
 	resp, err := c.MyMethod(ctx, req)
 	if err != nil {