1
2
3
4
5
6
7
8 package main
9
10 import (
11 "bytes"
12 "flag"
13 "fmt"
14 "os"
15 "path/filepath"
16 "strings"
17 "testing"
18
19 "github.com/google/go-cmp/cmp"
20 "google.golang.org/api/google-api-go-generator/internal/disco"
21 "google.golang.org/api/internal"
22 )
23
24 var updateGolden = flag.Bool("update_golden", false, "If true, causes TestAPIs to update golden files")
25
26 func TestAPIs(t *testing.T) {
27 *copyrightYear = "YEAR"
28
29 names := []string{
30 "any",
31 "arrayofarray-1",
32 "arrayofenum",
33 "arrayofmapofobjects",
34 "arrayofmapofstrings",
35 "blogger-3",
36 "floats",
37 "getwithoutbody",
38 "http-body",
39 "json-body",
40 "mapofany",
41 "mapofarrayofobjects",
42 "mapofint64strings",
43 "mapofobjects",
44 "mapofstrings-1",
45 "param-rename",
46 "quotednum",
47 "repeated",
48 "repeated_any_query_error",
49 "required-query",
50 "resource-named-service",
51 "unfortunatedefaults",
52 "variants",
53 "wrapnewlines",
54 }
55 for _, name := range names {
56 t.Run(name, func(t *testing.T) {
57 defer func() {
58 r := recover()
59 wantPanic := strings.HasSuffix(name, "_error")
60 if r != nil && !wantPanic {
61 t.Fatal("unexpected panic", r)
62 }
63 if r == nil && !wantPanic {
64 return
65 }
66 if r == nil && wantPanic {
67 t.Fatal("wanted test to panic, but it didn't")
68 }
69
70
71 got, ok := r.(string)
72 if !ok {
73 gotE, okE := r.(error)
74 if !okE {
75 t.Fatalf("panic with non-string/error input: %v", r)
76 }
77 got = gotE.Error()
78 }
79 want, err := readOrUpdate(name, got)
80 if err != nil {
81 t.Fatal(err)
82 }
83 if diff := cmp.Diff(got, string(want)); diff != "" {
84 t.Errorf("got(-),want(+):\n %s", diff)
85 }
86 }()
87 api, err := apiFromFile(filepath.Join("testdata", name+".json"))
88 if err != nil {
89 t.Fatalf("Error loading API testdata/%s.json: %v", name, err)
90 }
91 clean, err := api.GenerateCode()
92 if err != nil {
93 t.Fatalf("Error generating code for %s: %v", name, err)
94 }
95
96 want, err := readOrUpdate(name, string(clean))
97 if err != nil {
98 t.Fatal(err)
99 }
100
101 wantStr := strings.Replace(string(want), "gdcl/00000000", fmt.Sprintf("gdcl/%s", internal.Version), -1)
102 if !bytes.Equal([]byte(wantStr), clean) {
103 tf, _ := os.CreateTemp("", "api-"+name+"-got-json.")
104 if _, err := tf.Write(clean); err != nil {
105 t.Fatal(err)
106 }
107 if err := tf.Close(); err != nil {
108 t.Fatal(err)
109 }
110
111 t.Errorf("Output for API %s differs: diff -u %s %s", name, goldenFileName(name), tf.Name())
112 }
113 })
114 }
115 }
116
117 func readOrUpdate(name, clean string) ([]byte, error) {
118 goldenFile := goldenFileName(name)
119 if *updateGolden {
120 clean := strings.Replace(string(clean), fmt.Sprintf("gdcl/%s", internal.Version), "gdcl/00000000", -1)
121 if err := os.WriteFile(goldenFile, []byte(clean), 0644); err != nil {
122 return nil, err
123 }
124 }
125 return os.ReadFile(goldenFile)
126 }
127
128 func goldenFileName(name string) string {
129 return filepath.Join("testdata", name+".want")
130 }
131
132 func TestScope(t *testing.T) {
133 tests := [][]string{
134 {
135 "https://www.googleapis.com/auth/somescope",
136 "SomescopeScope",
137 },
138 {
139 "https://mail.google.com/somescope",
140 "MailGoogleComSomescopeScope",
141 },
142 {
143 "https://mail.google.com/",
144 "MailGoogleComScope",
145 },
146 }
147 for _, test := range tests {
148 if got := scopeIdentifier(disco.Scope{ID: test[0]}); got != test[1] {
149 t.Errorf("scopeIdentifier(%q) got %q, want %q", test[0], got, test[1])
150 }
151 }
152 }
153
154 func TestDepunct(t *testing.T) {
155 tests := []struct {
156 needCap bool
157 in, want string
158 }{
159 {
160 needCap: true,
161 in: "part__description",
162 want: "Part__description",
163 },
164 {
165 needCap: true,
166 in: "Part_description",
167 want: "PartDescription",
168 },
169 {
170 needCap: false,
171 in: "part_description",
172 want: "partDescription",
173 },
174 {
175 needCap: false,
176 in: "part-description",
177 want: "partDescription",
178 },
179 {
180 needCap: false,
181 in: "part.description",
182 want: "partDescription",
183 },
184 {
185 needCap: false,
186 in: "part$description",
187 want: "partDescription",
188 },
189 {
190 needCap: false,
191 in: "part/description",
192 want: "partDescription",
193 },
194 {
195 needCap: true,
196 in: "Part__description_name",
197 want: "Part__descriptionName",
198 },
199 {
200 needCap: true,
201 in: "Part_description_name",
202 want: "PartDescriptionName",
203 },
204 {
205 needCap: true,
206 in: "Part__description__name",
207 want: "Part__description__name",
208 },
209 {
210 needCap: true,
211 in: "Part_description__name",
212 want: "PartDescription__name",
213 },
214 }
215 for _, test := range tests {
216 if got := depunct(test.in, test.needCap); got != test.want {
217 t.Errorf("depunct(%q,%v) = %q; want %q", test.in, test.needCap, got, test.want)
218 }
219 }
220 }
221
222 func TestRenameVersion(t *testing.T) {
223 tests := []struct {
224 version, want string
225 }{
226 {
227 version: "directory_v1",
228 want: "directory/v1",
229 },
230 {
231 version: "email_migration_v1",
232 want: "email_migration/v1",
233 },
234 {
235 version: "my_api_v1.2",
236 want: "my_api/v1.2",
237 },
238 }
239 for _, test := range tests {
240 if got := renameVersion(test.version); got != test.want {
241 t.Errorf("renameVersion(%q) = %q; want %q", test.version, got, test.want)
242 }
243 }
244 }
245
246 func TestSupportsPaging(t *testing.T) {
247 api, err := apiFromFile(filepath.Join("testdata", "paging.json"))
248 if err != nil {
249 t.Fatalf("Error loading API testdata/paging.json: %v", err)
250 }
251 api.PopulateSchemas()
252 res := api.doc.Resources[0]
253 for _, meth := range api.resourceMethods(res) {
254 _, _, got := meth.supportsPaging()
255 want := strings.HasPrefix(meth.m.Name, "yes")
256 if got != want {
257 t.Errorf("method %s supports paging: got %t, want %t", meth.m.Name, got, want)
258 }
259 }
260 }
261
262 func TestIsNewerRevision(t *testing.T) {
263 olderBytesPath, newerBytesPath := filepath.Join("testdata", "rev20200415.json"), filepath.Join("testdata", "rev20200416.json")
264 olderBytes, err := os.ReadFile(olderBytesPath)
265 if err != nil {
266 t.Fatalf("os.ReadFile(%q) = %v; want nil", olderBytesPath, err)
267 }
268 newerBytes, err := os.ReadFile(newerBytesPath)
269 if err != nil {
270 t.Fatalf("os.ReadFile(%q) = %v; want nil", newerBytesPath, err)
271 }
272
273
274 if err := isNewerRevision(olderBytes, newerBytes); err != nil {
275 t.Fatalf("isNewerRevision(%q, %q) = %v; want nil", string(olderBytes), string(newerBytes), err)
276 }
277
278 if err := isNewerRevision(newerBytes, newerBytes); err != nil {
279 t.Fatalf("isNewerRevision(%q, %q) = %v; want nil", string(newerBytes), string(newerBytes), err)
280 }
281
282 err = isNewerRevision(newerBytes, olderBytes)
283 if err == nil {
284 t.Fatalf("isNewerRevision(%q, %q) = nil; want %v", string(newerBytes), string(olderBytes), errOldRevision)
285 }
286 if err != errOldRevision {
287 t.Fatalf("got %v, want %v", err, errOldRevision)
288 }
289 }
290
291 func TestRemoveMarkdownLinks(t *testing.T) {
292 tests := []struct {
293 name string
294 input string
295 want string
296 }{
297 {name: "basic", input: "[name](link)", want: "name (link)"},
298 {name: "no link", input: "name", want: "name"},
299 {name: "empty string", input: "", want: ""},
300 {name: "sentence", input: "This [is](link) a test.", want: "This is (link) a test."},
301 {name: "two links", input: "This [is](link) a [test](link).", want: "This is (link) a test (link)."},
302 {name: "first incomplete link", input: "This [is] a [test](link).", want: "This [is] a test (link)."},
303 {name: "second incomplete link", input: "This [is](link) a (test).", want: "This is (link) a (test)."},
304 {name: "seperated", input: "This [is] (a) test.", want: "This [is] (a) test."},
305 {name: "don't process code blocks", input: "This is `[a](link)` test.", want: "This is `[a](link)` test."},
306 {name: "At start", input: "[This](link) is a test.", want: "This (link) is a test."},
307 {name: "At end ", input: "This is a [test.](link)", want: "This is a test. (link)"},
308 }
309 for _, tc := range tests {
310 t.Run(tc.name, func(t *testing.T) {
311 if got := removeMarkdownLinks(tc.input); got != tc.want {
312 t.Errorf("removeMarkdownLinks(%q) = %q, want %q", tc.input, got, tc.want)
313 }
314 })
315 }
316 }
317
318 func TestAsComment_LongLink(t *testing.T) {
319
320 input := "This make sure we don't split long links (http://example.com/really/really/really/really/really/really/really/really/really/really/really/long). We want them to show up well in godoc."
321 want := `// This make sure we don't split long links
322 // (http://example.com/really/really/really/really/really/really/really/really/really/really/really/long).
323 // We want them to show up well in godoc.
324 `
325 got := asComment("", input)
326 if got != want {
327 t.Errorf("got %q, want %q", got, want)
328 }
329 }
330
331 func TestApiBaseURLTemplate(t *testing.T) {
332 tests := []struct {
333 name, want string
334 }{
335 {
336 name: "any.json",
337 want: "https://logging.UNIVERSE_DOMAIN/",
338 },
339 {
340 name: "blogger-3.json",
341 want: "https://www.UNIVERSE_DOMAIN/blogger/v3/",
342 },
343 {
344 name: "required-query.json",
345 want: "https://www.UNIVERSE_DOMAIN/_ah/api/tshealth/v1/",
346 },
347 }
348 for _, tt := range tests {
349 api, err := apiFromFile(filepath.Join("testdata", tt.name))
350 if err != nil {
351 t.Fatalf("Error loading API testdata/%s: %v", tt.name, err)
352 }
353 got, err := api.apiBaseURLTemplate()
354 if err != nil {
355 t.Fatalf("%s: apiBaseURLTemplate(): %v", tt.name, err)
356 }
357 if got != tt.want {
358 t.Errorf("%s: apiBaseURLTemplate() = %q; want %q", tt.name, got, tt.want)
359 }
360 }
361 }
362
View as plain text