blob: 36dbf72c8c90bea50c3e68f0744b48b6eea83a8c [file] [log] [blame]
Damien Neil220c2022018-08-15 11:24:18 -07001// Copyright 2018 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package protogen
6
7import (
Damien Neil3cf6e622018-09-11 13:53:14 -07008 "flag"
Damien Neil082ce922018-09-06 10:23:53 -07009 "fmt"
Damien Neil220c2022018-08-15 11:24:18 -070010 "testing"
11
Joe Tsai94a85102019-03-12 21:28:30 -070012 "github.com/google/go-cmp/cmp"
Joe Tsaie0daf312020-02-25 12:51:10 -080013
Damien Neila8a2cea2019-07-10 16:17:16 -070014 "google.golang.org/protobuf/proto"
Damien Neile89e6242019-05-13 23:55:40 -070015 "google.golang.org/protobuf/reflect/protoreflect"
Joe Tsaie1f8d502018-11-26 18:55:29 -080016
Joe Tsaia95b29f2019-05-16 12:47:20 -070017 "google.golang.org/protobuf/types/descriptorpb"
18 "google.golang.org/protobuf/types/pluginpb"
Damien Neil220c2022018-08-15 11:24:18 -070019)
20
Damien Neile358d432020-03-06 13:58:41 -080021func init() {
22 warnings = false // avoid spam in tests
23}
24
Damien Neil3cf6e622018-09-11 13:53:14 -070025func TestPluginParameters(t *testing.T) {
26 var flags flag.FlagSet
27 value := flags.Int("integer", 0, "")
Damien Neil3cf6e622018-09-11 13:53:14 -070028 const params = "integer=2"
Joe Tsaiab0ca4f2020-02-27 14:47:29 -080029 _, err := Options{
30 ParamFunc: flags.Set,
31 }.New(&pluginpb.CodeGeneratorRequest{
Damien Neila8a2cea2019-07-10 16:17:16 -070032 Parameter: proto.String(params),
Joe Tsaiab0ca4f2020-02-27 14:47:29 -080033 })
Damien Neil3cf6e622018-09-11 13:53:14 -070034 if err != nil {
35 t.Errorf("New(generator parameters %q): %v", params, err)
36 }
37 if *value != 2 {
38 t.Errorf("New(generator parameters %q): integer=%v, want 2", params, *value)
39 }
40}
41
42func TestPluginParameterErrors(t *testing.T) {
43 for _, parameter := range []string{
44 "unknown=1",
45 "boolean=error",
46 } {
47 var flags flag.FlagSet
48 flags.Bool("boolean", false, "")
Joe Tsaiab0ca4f2020-02-27 14:47:29 -080049 _, err := Options{
Damien Neil3cf6e622018-09-11 13:53:14 -070050 ParamFunc: flags.Set,
Joe Tsaiab0ca4f2020-02-27 14:47:29 -080051 }.New(&pluginpb.CodeGeneratorRequest{
Damien Neila8a2cea2019-07-10 16:17:16 -070052 Parameter: proto.String(parameter),
Joe Tsaiab0ca4f2020-02-27 14:47:29 -080053 })
Damien Neil3cf6e622018-09-11 13:53:14 -070054 if err == nil {
55 t.Errorf("New(generator parameters %q): want error, got nil", parameter)
56 }
57 }
58}
59
Joe Tsai94a85102019-03-12 21:28:30 -070060func TestNoGoPackage(t *testing.T) {
Joe Tsaiab0ca4f2020-02-27 14:47:29 -080061 gen, err := Options{}.New(&pluginpb.CodeGeneratorRequest{
Joe Tsai94a85102019-03-12 21:28:30 -070062 ProtoFile: []*descriptorpb.FileDescriptorProto{
63 {
Damien Neila8a2cea2019-07-10 16:17:16 -070064 Name: proto.String("testdata/go_package/no_go_package.proto"),
65 Syntax: proto.String(protoreflect.Proto3.String()),
66 Package: proto.String("goproto.testdata"),
Joe Tsai94a85102019-03-12 21:28:30 -070067 },
68 {
Damien Neila8a2cea2019-07-10 16:17:16 -070069 Name: proto.String("testdata/go_package/no_go_package_import.proto"),
70 Syntax: proto.String(protoreflect.Proto3.String()),
71 Package: proto.String("goproto.testdata"),
Joe Tsai25fc6fb2020-02-10 14:04:25 -080072 Dependency: []string{"testdata/go_package/no_go_package.proto"},
Joe Tsai94a85102019-03-12 21:28:30 -070073 },
74 },
Joe Tsaiab0ca4f2020-02-27 14:47:29 -080075 })
Damien Neil220c2022018-08-15 11:24:18 -070076 if err != nil {
77 t.Fatal(err)
78 }
Joe Tsai94a85102019-03-12 21:28:30 -070079
80 for i, f := range gen.Files {
81 if got, want := string(f.GoPackageName), "goproto_testdata"; got != want {
82 t.Errorf("gen.Files[%d].GoPackageName = %v, want %v", i, got, want)
Damien Neil220c2022018-08-15 11:24:18 -070083 }
Joe Tsai94a85102019-03-12 21:28:30 -070084 if got, want := string(f.GoImportPath), "testdata/go_package"; got != want {
85 t.Errorf("gen.Files[%d].GoImportPath = %v, want %v", i, got, want)
Damien Neil220c2022018-08-15 11:24:18 -070086 }
87 }
88}
89
Damien Neil082ce922018-09-06 10:23:53 -070090func TestPackageNamesAndPaths(t *testing.T) {
91 const (
92 filename = "dir/filename.proto"
93 protoPackageName = "proto.package"
94 )
95 for _, test := range []struct {
Damien Neilffbc5fd2020-02-12 23:38:30 -080096 desc string
97 parameter string
98 goPackageOption string
99 generate bool
100 wantPackageName GoPackageName
101 wantImportPath GoImportPath
102 wantFilename string
Damien Neil082ce922018-09-06 10:23:53 -0700103 }{
104 {
Damien Neilffbc5fd2020-02-12 23:38:30 -0800105 desc: "no parameters, no go_package option",
106 generate: true,
107 wantPackageName: "proto_package",
108 wantImportPath: "dir",
109 wantFilename: "dir/filename",
Damien Neil082ce922018-09-06 10:23:53 -0700110 },
111 {
Damien Neilffbc5fd2020-02-12 23:38:30 -0800112 desc: "go_package option sets import path",
113 goPackageOption: "golang.org/x/foo",
114 generate: true,
115 wantPackageName: "foo",
116 wantImportPath: "golang.org/x/foo",
117 wantFilename: "golang.org/x/foo/filename",
Damien Neil082ce922018-09-06 10:23:53 -0700118 },
119 {
Damien Neilffbc5fd2020-02-12 23:38:30 -0800120 desc: "go_package option sets import path and package",
121 goPackageOption: "golang.org/x/foo;bar",
122 generate: true,
123 wantPackageName: "bar",
124 wantImportPath: "golang.org/x/foo",
125 wantFilename: "golang.org/x/foo/filename",
Damien Neil082ce922018-09-06 10:23:53 -0700126 },
127 {
Damien Neilffbc5fd2020-02-12 23:38:30 -0800128 desc: "go_package option sets package",
129 goPackageOption: "foo",
130 generate: true,
131 wantPackageName: "foo",
132 wantImportPath: "dir",
133 wantFilename: "dir/filename",
Damien Neil082ce922018-09-06 10:23:53 -0700134 },
135 {
Damien Neilffbc5fd2020-02-12 23:38:30 -0800136 desc: "command line sets import path for a file",
137 parameter: "Mdir/filename.proto=golang.org/x/bar",
138 goPackageOption: "golang.org/x/foo",
139 generate: true,
140 wantPackageName: "foo",
141 wantImportPath: "golang.org/x/bar",
142 wantFilename: "golang.org/x/foo/filename",
Damien Neil082ce922018-09-06 10:23:53 -0700143 },
144 {
Damien Neilffbc5fd2020-02-12 23:38:30 -0800145 desc: "command line sets import path for a file with package name specified",
146 parameter: "Mdir/filename.proto=golang.org/x/bar;bar",
147 goPackageOption: "golang.org/x/foo",
148 generate: true,
149 wantPackageName: "bar",
150 wantImportPath: "golang.org/x/bar",
151 wantFilename: "golang.org/x/foo/filename",
Joe Tsai6ad8e632020-03-18 00:59:09 -0700152 },
153 {
Damien Neilffbc5fd2020-02-12 23:38:30 -0800154 desc: "import_path parameter sets import path of generated files",
155 parameter: "import_path=golang.org/x/bar",
156 goPackageOption: "golang.org/x/foo",
157 generate: true,
158 wantPackageName: "foo",
159 wantImportPath: "golang.org/x/bar",
160 wantFilename: "golang.org/x/foo/filename",
Damien Neil082ce922018-09-06 10:23:53 -0700161 },
162 {
Damien Neilffbc5fd2020-02-12 23:38:30 -0800163 desc: "import_path parameter does not set import path of dependencies",
164 parameter: "import_path=golang.org/x/bar",
165 goPackageOption: "golang.org/x/foo",
166 generate: false,
167 wantPackageName: "foo",
168 wantImportPath: "golang.org/x/foo",
169 wantFilename: "golang.org/x/foo/filename",
Damien Neil082ce922018-09-06 10:23:53 -0700170 },
Damien Neilaadba562020-02-15 14:28:51 -0800171 {
Damien Neilffbc5fd2020-02-12 23:38:30 -0800172 desc: "module option set",
173 parameter: "module=golang.org/x",
174 goPackageOption: "golang.org/x/foo",
175 generate: false,
176 wantPackageName: "foo",
177 wantImportPath: "golang.org/x/foo",
178 wantFilename: "foo/filename",
179 },
180 {
181 desc: "paths=import uses import path from command line",
182 parameter: "paths=import,Mdir/filename.proto=golang.org/x/bar",
183 goPackageOption: "golang.org/x/foo",
184 generate: true,
185 wantPackageName: "foo",
186 wantImportPath: "golang.org/x/bar",
187 wantFilename: "golang.org/x/bar/filename",
188 },
189 {
190 desc: "module option implies paths=import",
191 parameter: "module=golang.org/x,Mdir/filename.proto=golang.org/x/foo",
192 generate: false,
193 wantPackageName: "proto_package",
194 wantImportPath: "golang.org/x/foo",
195 wantFilename: "foo/filename",
Damien Neilaadba562020-02-15 14:28:51 -0800196 },
Damien Neil082ce922018-09-06 10:23:53 -0700197 } {
198 context := fmt.Sprintf(`
199TEST: %v
200 --go_out=%v:.
201 file %q: generate=%v
202 option go_package = %q;
203
204 `,
205 test.desc, test.parameter, filename, test.generate, test.goPackageOption)
206
207 req := &pluginpb.CodeGeneratorRequest{
Damien Neila8a2cea2019-07-10 16:17:16 -0700208 Parameter: proto.String(test.parameter),
Joe Tsaie1f8d502018-11-26 18:55:29 -0800209 ProtoFile: []*descriptorpb.FileDescriptorProto{
Damien Neil082ce922018-09-06 10:23:53 -0700210 {
Damien Neila8a2cea2019-07-10 16:17:16 -0700211 Name: proto.String(filename),
212 Package: proto.String(protoPackageName),
Joe Tsaie1f8d502018-11-26 18:55:29 -0800213 Options: &descriptorpb.FileOptions{
Damien Neila8a2cea2019-07-10 16:17:16 -0700214 GoPackage: proto.String(test.goPackageOption),
Damien Neil082ce922018-09-06 10:23:53 -0700215 },
216 },
217 },
218 }
219 if test.generate {
220 req.FileToGenerate = []string{filename}
221 }
Joe Tsaiab0ca4f2020-02-27 14:47:29 -0800222 gen, err := Options{}.New(req)
Damien Neil082ce922018-09-06 10:23:53 -0700223 if err != nil {
224 t.Errorf("%vNew(req) = %v", context, err)
225 continue
226 }
Joe Tsai2cec4842019-08-20 20:14:19 -0700227 gotFile, ok := gen.FilesByPath[filename]
Damien Neil082ce922018-09-06 10:23:53 -0700228 if !ok {
229 t.Errorf("%v%v: missing file info", context, filename)
230 continue
231 }
232 if got, want := gotFile.GoPackageName, test.wantPackageName; got != want {
233 t.Errorf("%vGoPackageName=%v, want %v", context, got, want)
234 }
235 if got, want := gotFile.GoImportPath, test.wantImportPath; got != want {
236 t.Errorf("%vGoImportPath=%v, want %v", context, got, want)
237 }
Damien Neilffbc5fd2020-02-12 23:38:30 -0800238 gen.NewGeneratedFile(gotFile.GeneratedFilenamePrefix, "")
239 resp := gen.Response()
240 if got, want := resp.File[0].GetName(), test.wantFilename; got != want {
241 t.Errorf("%vgenerated filename=%v, want %v", context, got, want)
Damien Neil082ce922018-09-06 10:23:53 -0700242 }
243 }
244}
245
246func TestPackageNameInference(t *testing.T) {
Joe Tsaiab0ca4f2020-02-27 14:47:29 -0800247 gen, err := Options{}.New(&pluginpb.CodeGeneratorRequest{
Joe Tsaie1f8d502018-11-26 18:55:29 -0800248 ProtoFile: []*descriptorpb.FileDescriptorProto{
Damien Neil082ce922018-09-06 10:23:53 -0700249 {
Damien Neila8a2cea2019-07-10 16:17:16 -0700250 Name: proto.String("dir/file1.proto"),
251 Package: proto.String("proto.package"),
Damien Neil082ce922018-09-06 10:23:53 -0700252 },
253 {
Damien Neila8a2cea2019-07-10 16:17:16 -0700254 Name: proto.String("dir/file2.proto"),
255 Package: proto.String("proto.package"),
Joe Tsaie1f8d502018-11-26 18:55:29 -0800256 Options: &descriptorpb.FileOptions{
Damien Neila8a2cea2019-07-10 16:17:16 -0700257 GoPackage: proto.String("foo"),
Damien Neil082ce922018-09-06 10:23:53 -0700258 },
259 },
260 },
261 FileToGenerate: []string{"dir/file1.proto", "dir/file2.proto"},
Joe Tsaiab0ca4f2020-02-27 14:47:29 -0800262 })
Damien Neil082ce922018-09-06 10:23:53 -0700263 if err != nil {
264 t.Fatalf("New(req) = %v", err)
265 }
Joe Tsai2cec4842019-08-20 20:14:19 -0700266 if f1, ok := gen.FilesByPath["dir/file1.proto"]; !ok {
Damien Neil082ce922018-09-06 10:23:53 -0700267 t.Errorf("missing file info for dir/file1.proto")
268 } else if f1.GoPackageName != "foo" {
269 t.Errorf("dir/file1.proto: GoPackageName=%v, want foo; package name should be derived from dir/file2.proto", f1.GoPackageName)
270 }
271}
272
273func TestInconsistentPackageNames(t *testing.T) {
Joe Tsaiab0ca4f2020-02-27 14:47:29 -0800274 _, err := Options{}.New(&pluginpb.CodeGeneratorRequest{
Joe Tsaie1f8d502018-11-26 18:55:29 -0800275 ProtoFile: []*descriptorpb.FileDescriptorProto{
Damien Neil082ce922018-09-06 10:23:53 -0700276 {
Damien Neila8a2cea2019-07-10 16:17:16 -0700277 Name: proto.String("dir/file1.proto"),
278 Package: proto.String("proto.package"),
Joe Tsaie1f8d502018-11-26 18:55:29 -0800279 Options: &descriptorpb.FileOptions{
Damien Neila8a2cea2019-07-10 16:17:16 -0700280 GoPackage: proto.String("golang.org/x/foo"),
Damien Neil082ce922018-09-06 10:23:53 -0700281 },
282 },
283 {
Damien Neila8a2cea2019-07-10 16:17:16 -0700284 Name: proto.String("dir/file2.proto"),
285 Package: proto.String("proto.package"),
Joe Tsaie1f8d502018-11-26 18:55:29 -0800286 Options: &descriptorpb.FileOptions{
Damien Neila8a2cea2019-07-10 16:17:16 -0700287 GoPackage: proto.String("golang.org/x/foo;bar"),
Damien Neil082ce922018-09-06 10:23:53 -0700288 },
289 },
290 },
291 FileToGenerate: []string{"dir/file1.proto", "dir/file2.proto"},
Joe Tsaiab0ca4f2020-02-27 14:47:29 -0800292 })
Damien Neil082ce922018-09-06 10:23:53 -0700293 if err == nil {
294 t.Fatalf("inconsistent package names for the same import path: New(req) = nil, want error")
295 }
296}
297
Damien Neild9016772018-08-23 14:39:30 -0700298func TestImports(t *testing.T) {
Joe Tsaiab0ca4f2020-02-27 14:47:29 -0800299 gen, err := Options{}.New(&pluginpb.CodeGeneratorRequest{})
Damien Neild9016772018-08-23 14:39:30 -0700300 if err != nil {
301 t.Fatal(err)
302 }
303 g := gen.NewGeneratedFile("foo.go", "golang.org/x/foo")
304 g.P("package foo")
305 g.P()
306 for _, importPath := range []GoImportPath{
307 "golang.org/x/foo",
308 // Multiple references to the same package.
309 "golang.org/x/bar",
310 "golang.org/x/bar",
311 // Reference to a different package with the same basename.
312 "golang.org/y/bar",
313 "golang.org/x/baz",
Damien Neil87214662018-10-05 11:23:35 -0700314 // Reference to a package conflicting with a predeclared identifier.
315 "golang.org/z/string",
Damien Neild9016772018-08-23 14:39:30 -0700316 } {
317 g.P("var _ = ", GoIdent{GoName: "X", GoImportPath: importPath}, " // ", importPath)
318 }
319 want := `package foo
320
321import (
322 bar "golang.org/x/bar"
Damien Neild9016772018-08-23 14:39:30 -0700323 baz "golang.org/x/baz"
Damien Neil1ec33152018-09-13 13:12:36 -0700324 bar1 "golang.org/y/bar"
Damien Neil87214662018-10-05 11:23:35 -0700325 string1 "golang.org/z/string"
Damien Neild9016772018-08-23 14:39:30 -0700326)
327
Damien Neil87214662018-10-05 11:23:35 -0700328var _ = X // "golang.org/x/foo"
329var _ = bar.X // "golang.org/x/bar"
330var _ = bar.X // "golang.org/x/bar"
331var _ = bar1.X // "golang.org/y/bar"
332var _ = baz.X // "golang.org/x/baz"
333var _ = string1.X // "golang.org/z/string"
Damien Neild9016772018-08-23 14:39:30 -0700334`
Damien Neil7bf3ce22018-12-21 15:54:06 -0800335 got, err := g.Content()
Damien Neild9016772018-08-23 14:39:30 -0700336 if err != nil {
Damien Neil7bf3ce22018-12-21 15:54:06 -0800337 t.Fatalf("g.Content() = %v", err)
Damien Neild9016772018-08-23 14:39:30 -0700338 }
Joe Tsai94a85102019-03-12 21:28:30 -0700339 if diff := cmp.Diff(string(want), string(got)); diff != "" {
340 t.Fatalf("content mismatch (-want +got):\n%s", diff)
Damien Neild9016772018-08-23 14:39:30 -0700341 }
342}
343
Damien Neil1fa8ab02018-09-27 15:51:05 -0700344func TestImportRewrites(t *testing.T) {
Joe Tsaiab0ca4f2020-02-27 14:47:29 -0800345 gen, err := Options{
Damien Neil1fa8ab02018-09-27 15:51:05 -0700346 ImportRewriteFunc: func(i GoImportPath) GoImportPath {
347 return "prefix/" + i
348 },
Joe Tsaiab0ca4f2020-02-27 14:47:29 -0800349 }.New(&pluginpb.CodeGeneratorRequest{})
Damien Neil1fa8ab02018-09-27 15:51:05 -0700350 if err != nil {
351 t.Fatal(err)
352 }
353 g := gen.NewGeneratedFile("foo.go", "golang.org/x/foo")
354 g.P("package foo")
355 g.P("var _ = ", GoIdent{GoName: "X", GoImportPath: "golang.org/x/bar"})
356 want := `package foo
357
Joe Tsai94a85102019-03-12 21:28:30 -0700358import (
359 bar "prefix/golang.org/x/bar"
360)
Damien Neil1fa8ab02018-09-27 15:51:05 -0700361
362var _ = bar.X
363`
Damien Neil7bf3ce22018-12-21 15:54:06 -0800364 got, err := g.Content()
Damien Neil1fa8ab02018-09-27 15:51:05 -0700365 if err != nil {
Damien Neil7bf3ce22018-12-21 15:54:06 -0800366 t.Fatalf("g.Content() = %v", err)
Damien Neil1fa8ab02018-09-27 15:51:05 -0700367 }
Joe Tsai94a85102019-03-12 21:28:30 -0700368 if diff := cmp.Diff(string(want), string(got)); diff != "" {
369 t.Fatalf("content mismatch (-want +got):\n%s", diff)
Damien Neil220c2022018-08-15 11:24:18 -0700370 }
371}