blob: f3852d7055db79d0ae9568505f20052396b8ba54 [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 Tsai009e0672018-11-27 18:45:07 -080012 "github.com/golang/protobuf/v2/internal/scalar"
Joe Tsai94a85102019-03-12 21:28:30 -070013 "github.com/golang/protobuf/v2/reflect/protoreflect"
14 "github.com/google/go-cmp/cmp"
Joe Tsaie1f8d502018-11-26 18:55:29 -080015
16 descriptorpb "github.com/golang/protobuf/v2/types/descriptor"
17 pluginpb "github.com/golang/protobuf/v2/types/plugin"
Damien Neil220c2022018-08-15 11:24:18 -070018)
19
Damien Neil3cf6e622018-09-11 13:53:14 -070020func TestPluginParameters(t *testing.T) {
21 var flags flag.FlagSet
22 value := flags.Int("integer", 0, "")
23 opts := &Options{
24 ParamFunc: flags.Set,
25 }
26 const params = "integer=2"
27 _, err := New(&pluginpb.CodeGeneratorRequest{
Joe Tsai009e0672018-11-27 18:45:07 -080028 Parameter: scalar.String(params),
Damien Neil3cf6e622018-09-11 13:53:14 -070029 }, opts)
30 if err != nil {
31 t.Errorf("New(generator parameters %q): %v", params, err)
32 }
33 if *value != 2 {
34 t.Errorf("New(generator parameters %q): integer=%v, want 2", params, *value)
35 }
36}
37
38func TestPluginParameterErrors(t *testing.T) {
39 for _, parameter := range []string{
40 "unknown=1",
41 "boolean=error",
42 } {
43 var flags flag.FlagSet
44 flags.Bool("boolean", false, "")
45 opts := &Options{
46 ParamFunc: flags.Set,
47 }
48 _, err := New(&pluginpb.CodeGeneratorRequest{
Joe Tsai009e0672018-11-27 18:45:07 -080049 Parameter: scalar.String(parameter),
Damien Neil3cf6e622018-09-11 13:53:14 -070050 }, opts)
51 if err == nil {
52 t.Errorf("New(generator parameters %q): want error, got nil", parameter)
53 }
54 }
55}
56
Joe Tsai94a85102019-03-12 21:28:30 -070057func TestNoGoPackage(t *testing.T) {
58 gen, err := New(&pluginpb.CodeGeneratorRequest{
59 ProtoFile: []*descriptorpb.FileDescriptorProto{
60 {
61 Name: scalar.String("testdata/go_package/no_go_package.proto"),
62 Syntax: scalar.String(protoreflect.Proto3.String()),
63 Package: scalar.String("goproto.testdata"),
64 },
65 {
66 Name: scalar.String("testdata/go_package/no_go_package_import.proto"),
67 Syntax: scalar.String(protoreflect.Proto3.String()),
68 Package: scalar.String("goproto.testdata"),
69 Dependency: []string{"go_package/no_go_package.proto"},
70 },
71 },
72 }, nil)
Damien Neil220c2022018-08-15 11:24:18 -070073 if err != nil {
74 t.Fatal(err)
75 }
Joe Tsai94a85102019-03-12 21:28:30 -070076
77 for i, f := range gen.Files {
78 if got, want := string(f.GoPackageName), "goproto_testdata"; got != want {
79 t.Errorf("gen.Files[%d].GoPackageName = %v, want %v", i, got, want)
Damien Neil220c2022018-08-15 11:24:18 -070080 }
Joe Tsai94a85102019-03-12 21:28:30 -070081 if got, want := string(f.GoImportPath), "testdata/go_package"; got != want {
82 t.Errorf("gen.Files[%d].GoImportPath = %v, want %v", i, got, want)
Damien Neil220c2022018-08-15 11:24:18 -070083 }
84 }
85}
86
Damien Neil082ce922018-09-06 10:23:53 -070087func TestPackageNamesAndPaths(t *testing.T) {
88 const (
89 filename = "dir/filename.proto"
90 protoPackageName = "proto.package"
91 )
92 for _, test := range []struct {
93 desc string
94 parameter string
95 goPackageOption string
96 generate bool
97 wantPackageName GoPackageName
98 wantImportPath GoImportPath
99 wantFilenamePrefix string
100 }{
101 {
102 desc: "no parameters, no go_package option",
103 generate: true,
104 wantPackageName: "proto_package",
105 wantImportPath: "dir",
106 wantFilenamePrefix: "dir/filename",
107 },
108 {
109 desc: "go_package option sets import path",
110 goPackageOption: "golang.org/x/foo",
111 generate: true,
112 wantPackageName: "foo",
113 wantImportPath: "golang.org/x/foo",
114 wantFilenamePrefix: "golang.org/x/foo/filename",
115 },
116 {
117 desc: "go_package option sets import path and package",
118 goPackageOption: "golang.org/x/foo;bar",
119 generate: true,
120 wantPackageName: "bar",
121 wantImportPath: "golang.org/x/foo",
122 wantFilenamePrefix: "golang.org/x/foo/filename",
123 },
124 {
125 desc: "go_package option sets package",
126 goPackageOption: "foo",
127 generate: true,
128 wantPackageName: "foo",
129 wantImportPath: "dir",
130 wantFilenamePrefix: "dir/filename",
131 },
132 {
133 desc: "command line sets import path for a file",
134 parameter: "Mdir/filename.proto=golang.org/x/bar",
135 goPackageOption: "golang.org/x/foo",
136 generate: true,
137 wantPackageName: "foo",
138 wantImportPath: "golang.org/x/bar",
139 wantFilenamePrefix: "golang.org/x/foo/filename",
140 },
141 {
142 desc: "import_path parameter sets import path of generated files",
143 parameter: "import_path=golang.org/x/bar",
144 goPackageOption: "golang.org/x/foo",
145 generate: true,
146 wantPackageName: "foo",
147 wantImportPath: "golang.org/x/bar",
148 wantFilenamePrefix: "golang.org/x/foo/filename",
149 },
150 {
151 desc: "import_path parameter does not set import path of dependencies",
152 parameter: "import_path=golang.org/x/bar",
153 goPackageOption: "golang.org/x/foo",
154 generate: false,
155 wantPackageName: "foo",
156 wantImportPath: "golang.org/x/foo",
157 wantFilenamePrefix: "golang.org/x/foo/filename",
158 },
159 } {
160 context := fmt.Sprintf(`
161TEST: %v
162 --go_out=%v:.
163 file %q: generate=%v
164 option go_package = %q;
165
166 `,
167 test.desc, test.parameter, filename, test.generate, test.goPackageOption)
168
169 req := &pluginpb.CodeGeneratorRequest{
Joe Tsai009e0672018-11-27 18:45:07 -0800170 Parameter: scalar.String(test.parameter),
Joe Tsaie1f8d502018-11-26 18:55:29 -0800171 ProtoFile: []*descriptorpb.FileDescriptorProto{
Damien Neil082ce922018-09-06 10:23:53 -0700172 {
Joe Tsai009e0672018-11-27 18:45:07 -0800173 Name: scalar.String(filename),
174 Package: scalar.String(protoPackageName),
Joe Tsaie1f8d502018-11-26 18:55:29 -0800175 Options: &descriptorpb.FileOptions{
Joe Tsai009e0672018-11-27 18:45:07 -0800176 GoPackage: scalar.String(test.goPackageOption),
Damien Neil082ce922018-09-06 10:23:53 -0700177 },
178 },
179 },
180 }
181 if test.generate {
182 req.FileToGenerate = []string{filename}
183 }
Damien Neil3cf6e622018-09-11 13:53:14 -0700184 gen, err := New(req, nil)
Damien Neil082ce922018-09-06 10:23:53 -0700185 if err != nil {
186 t.Errorf("%vNew(req) = %v", context, err)
187 continue
188 }
189 gotFile, ok := gen.FileByName(filename)
190 if !ok {
191 t.Errorf("%v%v: missing file info", context, filename)
192 continue
193 }
194 if got, want := gotFile.GoPackageName, test.wantPackageName; got != want {
195 t.Errorf("%vGoPackageName=%v, want %v", context, got, want)
196 }
197 if got, want := gotFile.GoImportPath, test.wantImportPath; got != want {
198 t.Errorf("%vGoImportPath=%v, want %v", context, got, want)
199 }
200 if got, want := gotFile.GeneratedFilenamePrefix, test.wantFilenamePrefix; got != want {
201 t.Errorf("%vGeneratedFilenamePrefix=%v, want %v", context, got, want)
202 }
203 }
204}
205
206func TestPackageNameInference(t *testing.T) {
207 gen, err := New(&pluginpb.CodeGeneratorRequest{
Joe Tsaie1f8d502018-11-26 18:55:29 -0800208 ProtoFile: []*descriptorpb.FileDescriptorProto{
Damien Neil082ce922018-09-06 10:23:53 -0700209 {
Joe Tsai009e0672018-11-27 18:45:07 -0800210 Name: scalar.String("dir/file1.proto"),
211 Package: scalar.String("proto.package"),
Damien Neil082ce922018-09-06 10:23:53 -0700212 },
213 {
Joe Tsai009e0672018-11-27 18:45:07 -0800214 Name: scalar.String("dir/file2.proto"),
215 Package: scalar.String("proto.package"),
Joe Tsaie1f8d502018-11-26 18:55:29 -0800216 Options: &descriptorpb.FileOptions{
Joe Tsai009e0672018-11-27 18:45:07 -0800217 GoPackage: scalar.String("foo"),
Damien Neil082ce922018-09-06 10:23:53 -0700218 },
219 },
220 },
221 FileToGenerate: []string{"dir/file1.proto", "dir/file2.proto"},
Damien Neil3cf6e622018-09-11 13:53:14 -0700222 }, nil)
Damien Neil082ce922018-09-06 10:23:53 -0700223 if err != nil {
224 t.Fatalf("New(req) = %v", err)
225 }
226 if f1, ok := gen.FileByName("dir/file1.proto"); !ok {
227 t.Errorf("missing file info for dir/file1.proto")
228 } else if f1.GoPackageName != "foo" {
229 t.Errorf("dir/file1.proto: GoPackageName=%v, want foo; package name should be derived from dir/file2.proto", f1.GoPackageName)
230 }
231}
232
233func TestInconsistentPackageNames(t *testing.T) {
234 _, err := New(&pluginpb.CodeGeneratorRequest{
Joe Tsaie1f8d502018-11-26 18:55:29 -0800235 ProtoFile: []*descriptorpb.FileDescriptorProto{
Damien Neil082ce922018-09-06 10:23:53 -0700236 {
Joe Tsai009e0672018-11-27 18:45:07 -0800237 Name: scalar.String("dir/file1.proto"),
238 Package: scalar.String("proto.package"),
Joe Tsaie1f8d502018-11-26 18:55:29 -0800239 Options: &descriptorpb.FileOptions{
Joe Tsai009e0672018-11-27 18:45:07 -0800240 GoPackage: scalar.String("golang.org/x/foo"),
Damien Neil082ce922018-09-06 10:23:53 -0700241 },
242 },
243 {
Joe Tsai009e0672018-11-27 18:45:07 -0800244 Name: scalar.String("dir/file2.proto"),
245 Package: scalar.String("proto.package"),
Joe Tsaie1f8d502018-11-26 18:55:29 -0800246 Options: &descriptorpb.FileOptions{
Joe Tsai009e0672018-11-27 18:45:07 -0800247 GoPackage: scalar.String("golang.org/x/foo;bar"),
Damien Neil082ce922018-09-06 10:23:53 -0700248 },
249 },
250 },
251 FileToGenerate: []string{"dir/file1.proto", "dir/file2.proto"},
Damien Neil3cf6e622018-09-11 13:53:14 -0700252 }, nil)
Damien Neil082ce922018-09-06 10:23:53 -0700253 if err == nil {
254 t.Fatalf("inconsistent package names for the same import path: New(req) = nil, want error")
255 }
256}
257
Damien Neild9016772018-08-23 14:39:30 -0700258func TestImports(t *testing.T) {
Damien Neil3cf6e622018-09-11 13:53:14 -0700259 gen, err := New(&pluginpb.CodeGeneratorRequest{}, nil)
Damien Neild9016772018-08-23 14:39:30 -0700260 if err != nil {
261 t.Fatal(err)
262 }
263 g := gen.NewGeneratedFile("foo.go", "golang.org/x/foo")
264 g.P("package foo")
265 g.P()
266 for _, importPath := range []GoImportPath{
267 "golang.org/x/foo",
268 // Multiple references to the same package.
269 "golang.org/x/bar",
270 "golang.org/x/bar",
271 // Reference to a different package with the same basename.
272 "golang.org/y/bar",
273 "golang.org/x/baz",
Damien Neil87214662018-10-05 11:23:35 -0700274 // Reference to a package conflicting with a predeclared identifier.
275 "golang.org/z/string",
Damien Neild9016772018-08-23 14:39:30 -0700276 } {
277 g.P("var _ = ", GoIdent{GoName: "X", GoImportPath: importPath}, " // ", importPath)
278 }
279 want := `package foo
280
281import (
282 bar "golang.org/x/bar"
Damien Neild9016772018-08-23 14:39:30 -0700283 baz "golang.org/x/baz"
Damien Neil1ec33152018-09-13 13:12:36 -0700284 bar1 "golang.org/y/bar"
Damien Neil87214662018-10-05 11:23:35 -0700285 string1 "golang.org/z/string"
Damien Neild9016772018-08-23 14:39:30 -0700286)
287
Damien Neil87214662018-10-05 11:23:35 -0700288var _ = X // "golang.org/x/foo"
289var _ = bar.X // "golang.org/x/bar"
290var _ = bar.X // "golang.org/x/bar"
291var _ = bar1.X // "golang.org/y/bar"
292var _ = baz.X // "golang.org/x/baz"
293var _ = string1.X // "golang.org/z/string"
Damien Neild9016772018-08-23 14:39:30 -0700294`
Damien Neil7bf3ce22018-12-21 15:54:06 -0800295 got, err := g.Content()
Damien Neild9016772018-08-23 14:39:30 -0700296 if err != nil {
Damien Neil7bf3ce22018-12-21 15:54:06 -0800297 t.Fatalf("g.Content() = %v", err)
Damien Neild9016772018-08-23 14:39:30 -0700298 }
Joe Tsai94a85102019-03-12 21:28:30 -0700299 if diff := cmp.Diff(string(want), string(got)); diff != "" {
300 t.Fatalf("content mismatch (-want +got):\n%s", diff)
Damien Neild9016772018-08-23 14:39:30 -0700301 }
302}
303
Damien Neil1fa8ab02018-09-27 15:51:05 -0700304func TestImportRewrites(t *testing.T) {
305 gen, err := New(&pluginpb.CodeGeneratorRequest{}, &Options{
306 ImportRewriteFunc: func(i GoImportPath) GoImportPath {
307 return "prefix/" + i
308 },
309 })
310 if err != nil {
311 t.Fatal(err)
312 }
313 g := gen.NewGeneratedFile("foo.go", "golang.org/x/foo")
314 g.P("package foo")
315 g.P("var _ = ", GoIdent{GoName: "X", GoImportPath: "golang.org/x/bar"})
316 want := `package foo
317
Joe Tsai94a85102019-03-12 21:28:30 -0700318import (
319 bar "prefix/golang.org/x/bar"
320)
Damien Neil1fa8ab02018-09-27 15:51:05 -0700321
322var _ = bar.X
323`
Damien Neil7bf3ce22018-12-21 15:54:06 -0800324 got, err := g.Content()
Damien Neil1fa8ab02018-09-27 15:51:05 -0700325 if err != nil {
Damien Neil7bf3ce22018-12-21 15:54:06 -0800326 t.Fatalf("g.Content() = %v", err)
Damien Neil1fa8ab02018-09-27 15:51:05 -0700327 }
Joe Tsai94a85102019-03-12 21:28:30 -0700328 if diff := cmp.Diff(string(want), string(got)); diff != "" {
329 t.Fatalf("content mismatch (-want +got):\n%s", diff)
Damien Neil220c2022018-08-15 11:24:18 -0700330 }
331}