...

Source file src/google.golang.org/api/google-api-go-generator/gen_test.go

Documentation: google.golang.org/api/google-api-go-generator

     1  // Copyright 2017 Google LLC.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  //go:build go1.19
     6  // +build go1.19
     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", // appengine/v1/appengine-api.json
    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  				// compare panic message received vs. desired
    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  				// NOTE: update golden files with `go test -update_golden`
   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  	// newBytes > oldBytes
   274  	if err := isNewerRevision(olderBytes, newerBytes); err != nil {
   275  		t.Fatalf("isNewerRevision(%q, %q) = %v; want nil", string(olderBytes), string(newerBytes), err)
   276  	}
   277  	// newBytes == newBytes
   278  	if err := isNewerRevision(newerBytes, newerBytes); err != nil {
   279  		t.Fatalf("isNewerRevision(%q, %q) = %v; want nil", string(newerBytes), string(newerBytes), err)
   280  	}
   281  	// newBytes < newBytes
   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  	//input := "The specification of cohorts for a cohort report. Cohort reports create a time series of user retention for the cohort. For example, you could select the cohort of users that were acquired in the first week of September and follow that cohort for the next six weeks. Selecting the users acquired in the first week of September cohort is specified in the `cohort` object. Following that cohort for the next six weeks is specified in the `cohortsRange` object. For examples, see [Cohort Report Examples](https://developers.google.com/analytics/devguides/reporting/data/v1/advanced#cohort_report_examples). The report response could show a weekly time series where say your app has retained 60% of this cohort after three weeks and 25% of this cohort after six weeks. These two percentages can be calculated by the metric `cohortActiveUsers/cohortTotalUsers` and will be separate rows in the report."
   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