Source file src/cmd/go/internal/vcs/vcs_test.go

     1  // Copyright 2014 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  
     5  package vcs
     6  
     7  import (
     8  	"errors"
     9  	"fmt"
    10  	"internal/testenv"
    11  	"os"
    12  	"path/filepath"
    13  	"strings"
    14  	"testing"
    15  
    16  	"cmd/go/internal/web"
    17  )
    18  
    19  func init() {
    20  	// GOVCS defaults to public:git|hg,private:all,
    21  	// which breaks many tests here - they can't use non-git, non-hg VCS at all!
    22  	// Change to fully permissive.
    23  	// The tests of the GOVCS setting itself are in ../../testdata/script/govcs.txt.
    24  	os.Setenv("GOVCS", "*:all")
    25  }
    26  
    27  // Test that RepoRootForImportPath determines the correct RepoRoot for a given importPath.
    28  // TODO(cmang): Add tests for SVN and BZR.
    29  func TestRepoRootForImportPath(t *testing.T) {
    30  	testenv.MustHaveExternalNetwork(t)
    31  
    32  	tests := []struct {
    33  		path string
    34  		want *RepoRoot
    35  	}{
    36  		{
    37  			"github.com/golang/groupcache",
    38  			&RepoRoot{
    39  				VCS:  vcsGit,
    40  				Repo: "https://github.com/golang/groupcache",
    41  			},
    42  		},
    43  		// Unicode letters in directories are not valid.
    44  		{
    45  			"github.com/user/unicode/испытание",
    46  			nil,
    47  		},
    48  		// IBM DevOps Services tests
    49  		{
    50  			"hub.jazz.net/git/user1/pkgname",
    51  			&RepoRoot{
    52  				VCS:  vcsGit,
    53  				Repo: "https://hub.jazz.net/git/user1/pkgname",
    54  			},
    55  		},
    56  		{
    57  			"hub.jazz.net/git/user1/pkgname/submodule/submodule/submodule",
    58  			&RepoRoot{
    59  				VCS:  vcsGit,
    60  				Repo: "https://hub.jazz.net/git/user1/pkgname",
    61  			},
    62  		},
    63  		{
    64  			"hub.jazz.net",
    65  			nil,
    66  		},
    67  		{
    68  			"hubajazz.net",
    69  			nil,
    70  		},
    71  		{
    72  			"hub2.jazz.net",
    73  			nil,
    74  		},
    75  		{
    76  			"hub.jazz.net/someotherprefix",
    77  			nil,
    78  		},
    79  		{
    80  			"hub.jazz.net/someotherprefix/user1/pkgname",
    81  			nil,
    82  		},
    83  		// Spaces are not valid in user names or package names
    84  		{
    85  			"hub.jazz.net/git/User 1/pkgname",
    86  			nil,
    87  		},
    88  		{
    89  			"hub.jazz.net/git/user1/pkg name",
    90  			nil,
    91  		},
    92  		// Dots are not valid in user names
    93  		{
    94  			"hub.jazz.net/git/user.1/pkgname",
    95  			nil,
    96  		},
    97  		{
    98  			"hub.jazz.net/git/user/pkg.name",
    99  			&RepoRoot{
   100  				VCS:  vcsGit,
   101  				Repo: "https://hub.jazz.net/git/user/pkg.name",
   102  			},
   103  		},
   104  		// User names cannot have uppercase letters
   105  		{
   106  			"hub.jazz.net/git/USER/pkgname",
   107  			nil,
   108  		},
   109  		// OpenStack tests
   110  		{
   111  			"git.openstack.org/openstack/swift",
   112  			&RepoRoot{
   113  				VCS:  vcsGit,
   114  				Repo: "https://git.openstack.org/openstack/swift",
   115  			},
   116  		},
   117  		// Trailing .git is less preferred but included for
   118  		// compatibility purposes while the same source needs to
   119  		// be compilable on both old and new go
   120  		{
   121  			"git.openstack.org/openstack/swift.git",
   122  			&RepoRoot{
   123  				VCS:  vcsGit,
   124  				Repo: "https://git.openstack.org/openstack/swift.git",
   125  			},
   126  		},
   127  		{
   128  			"git.openstack.org/openstack/swift/go/hummingbird",
   129  			&RepoRoot{
   130  				VCS:  vcsGit,
   131  				Repo: "https://git.openstack.org/openstack/swift",
   132  			},
   133  		},
   134  		{
   135  			"git.openstack.org",
   136  			nil,
   137  		},
   138  		{
   139  			"git.openstack.org/openstack",
   140  			nil,
   141  		},
   142  		// Spaces are not valid in package name
   143  		{
   144  			"git.apache.org/package name/path/to/lib",
   145  			nil,
   146  		},
   147  		// Should have ".git" suffix
   148  		{
   149  			"git.apache.org/package-name/path/to/lib",
   150  			nil,
   151  		},
   152  		{
   153  			"gitbapache.org",
   154  			nil,
   155  		},
   156  		{
   157  			"git.apache.org/package-name.git",
   158  			&RepoRoot{
   159  				VCS:  vcsGit,
   160  				Repo: "https://git.apache.org/package-name.git",
   161  			},
   162  		},
   163  		{
   164  			"git.apache.org/package-name_2.x.git/path/to/lib",
   165  			&RepoRoot{
   166  				VCS:  vcsGit,
   167  				Repo: "https://git.apache.org/package-name_2.x.git",
   168  			},
   169  		},
   170  		{
   171  			"chiselapp.com/user/kyle/repository/fossilgg",
   172  			&RepoRoot{
   173  				VCS:  vcsFossil,
   174  				Repo: "https://chiselapp.com/user/kyle/repository/fossilgg",
   175  			},
   176  		},
   177  		{
   178  			// must have a user/$name/repository/$repo path
   179  			"chiselapp.com/kyle/repository/fossilgg",
   180  			nil,
   181  		},
   182  		{
   183  			"chiselapp.com/user/kyle/fossilgg",
   184  			nil,
   185  		},
   186  		{
   187  			"bitbucket.org/workspace/pkgname",
   188  			&RepoRoot{
   189  				VCS:  vcsGit,
   190  				Repo: "https://bitbucket.org/workspace/pkgname",
   191  			},
   192  		},
   193  	}
   194  
   195  	for _, test := range tests {
   196  		got, err := RepoRootForImportPath(test.path, IgnoreMod, web.SecureOnly)
   197  		want := test.want
   198  
   199  		if want == nil {
   200  			if err == nil {
   201  				t.Errorf("RepoRootForImportPath(%q): Error expected but not received", test.path)
   202  			}
   203  			continue
   204  		}
   205  		if err != nil {
   206  			t.Errorf("RepoRootForImportPath(%q): %v", test.path, err)
   207  			continue
   208  		}
   209  		if got.VCS.Name != want.VCS.Name || got.Repo != want.Repo {
   210  			t.Errorf("RepoRootForImportPath(%q) = VCS(%s) Repo(%s), want VCS(%s) Repo(%s)", test.path, got.VCS, got.Repo, want.VCS, want.Repo)
   211  		}
   212  	}
   213  }
   214  
   215  // Test that vcs.FromDir correctly inspects a given directory and returns the
   216  // right VCS and repo directory.
   217  func TestFromDir(t *testing.T) {
   218  	tempDir := t.TempDir()
   219  
   220  	for _, vcs := range vcsList {
   221  		for r, root := range vcs.RootNames {
   222  			vcsName := fmt.Sprint(vcs.Name, r)
   223  			dir := filepath.Join(tempDir, "example.com", vcsName, root.filename)
   224  			if root.isDir {
   225  				err := os.MkdirAll(dir, 0755)
   226  				if err != nil {
   227  					t.Fatal(err)
   228  				}
   229  			} else {
   230  				err := os.MkdirAll(filepath.Dir(dir), 0755)
   231  				if err != nil {
   232  					t.Fatal(err)
   233  				}
   234  				f, err := os.Create(dir)
   235  				if err != nil {
   236  					t.Fatal(err)
   237  				}
   238  				f.Close()
   239  			}
   240  
   241  			wantRepoDir := filepath.Dir(dir)
   242  			gotRepoDir, gotVCS, err := FromDir(dir, tempDir, false)
   243  			if err != nil {
   244  				t.Errorf("FromDir(%q, %q): %v", dir, tempDir, err)
   245  				continue
   246  			}
   247  			if gotRepoDir != wantRepoDir || gotVCS.Name != vcs.Name {
   248  				t.Errorf("FromDir(%q, %q) = RepoDir(%s), VCS(%s); want RepoDir(%s), VCS(%s)", dir, tempDir, gotRepoDir, gotVCS.Name, wantRepoDir, vcs.Name)
   249  			}
   250  		}
   251  	}
   252  }
   253  
   254  func TestIsSecure(t *testing.T) {
   255  	tests := []struct {
   256  		vcs    *Cmd
   257  		url    string
   258  		secure bool
   259  	}{
   260  		{vcsGit, "http://example.com/foo.git", false},
   261  		{vcsGit, "https://example.com/foo.git", true},
   262  		{vcsBzr, "http://example.com/foo.bzr", false},
   263  		{vcsBzr, "https://example.com/foo.bzr", true},
   264  		{vcsSvn, "http://example.com/svn", false},
   265  		{vcsSvn, "https://example.com/svn", true},
   266  		{vcsHg, "http://example.com/foo.hg", false},
   267  		{vcsHg, "https://example.com/foo.hg", true},
   268  		{vcsGit, "ssh://user@example.com/foo.git", true},
   269  		{vcsGit, "user@server:path/to/repo.git", false},
   270  		{vcsGit, "user@server:", false},
   271  		{vcsGit, "server:repo.git", false},
   272  		{vcsGit, "server:path/to/repo.git", false},
   273  		{vcsGit, "example.com:path/to/repo.git", false},
   274  		{vcsGit, "path/that/contains/a:colon/repo.git", false},
   275  		{vcsHg, "ssh://user@example.com/path/to/repo.hg", true},
   276  		{vcsFossil, "http://example.com/foo", false},
   277  		{vcsFossil, "https://example.com/foo", true},
   278  	}
   279  
   280  	for _, test := range tests {
   281  		secure := test.vcs.IsSecure(test.url)
   282  		if secure != test.secure {
   283  			t.Errorf("%s isSecure(%q) = %t; want %t", test.vcs, test.url, secure, test.secure)
   284  		}
   285  	}
   286  }
   287  
   288  func TestIsSecureGitAllowProtocol(t *testing.T) {
   289  	tests := []struct {
   290  		vcs    *Cmd
   291  		url    string
   292  		secure bool
   293  	}{
   294  		// Same as TestIsSecure to verify same behavior.
   295  		{vcsGit, "http://example.com/foo.git", false},
   296  		{vcsGit, "https://example.com/foo.git", true},
   297  		{vcsBzr, "http://example.com/foo.bzr", false},
   298  		{vcsBzr, "https://example.com/foo.bzr", true},
   299  		{vcsSvn, "http://example.com/svn", false},
   300  		{vcsSvn, "https://example.com/svn", true},
   301  		{vcsHg, "http://example.com/foo.hg", false},
   302  		{vcsHg, "https://example.com/foo.hg", true},
   303  		{vcsGit, "user@server:path/to/repo.git", false},
   304  		{vcsGit, "user@server:", false},
   305  		{vcsGit, "server:repo.git", false},
   306  		{vcsGit, "server:path/to/repo.git", false},
   307  		{vcsGit, "example.com:path/to/repo.git", false},
   308  		{vcsGit, "path/that/contains/a:colon/repo.git", false},
   309  		{vcsHg, "ssh://user@example.com/path/to/repo.hg", true},
   310  		// New behavior.
   311  		{vcsGit, "ssh://user@example.com/foo.git", false},
   312  		{vcsGit, "foo://example.com/bar.git", true},
   313  		{vcsHg, "foo://example.com/bar.hg", false},
   314  		{vcsSvn, "foo://example.com/svn", false},
   315  		{vcsBzr, "foo://example.com/bar.bzr", false},
   316  	}
   317  
   318  	defer os.Unsetenv("GIT_ALLOW_PROTOCOL")
   319  	os.Setenv("GIT_ALLOW_PROTOCOL", "https:foo")
   320  	for _, test := range tests {
   321  		secure := test.vcs.IsSecure(test.url)
   322  		if secure != test.secure {
   323  			t.Errorf("%s isSecure(%q) = %t; want %t", test.vcs, test.url, secure, test.secure)
   324  		}
   325  	}
   326  }
   327  
   328  func TestMatchGoImport(t *testing.T) {
   329  	tests := []struct {
   330  		imports []metaImport
   331  		path    string
   332  		mi      metaImport
   333  		err     error
   334  	}{
   335  		{
   336  			imports: []metaImport{
   337  				{Prefix: "example.com/user/foo", VCS: "git", RepoRoot: "https://example.com/repo/target"},
   338  			},
   339  			path: "example.com/user/foo",
   340  			mi:   metaImport{Prefix: "example.com/user/foo", VCS: "git", RepoRoot: "https://example.com/repo/target"},
   341  		},
   342  		{
   343  			imports: []metaImport{
   344  				{Prefix: "example.com/user/foo", VCS: "git", RepoRoot: "https://example.com/repo/target"},
   345  			},
   346  			path: "example.com/user/foo/",
   347  			mi:   metaImport{Prefix: "example.com/user/foo", VCS: "git", RepoRoot: "https://example.com/repo/target"},
   348  		},
   349  		{
   350  			imports: []metaImport{
   351  				{Prefix: "example.com/user/foo", VCS: "git", RepoRoot: "https://example.com/repo/target"},
   352  				{Prefix: "example.com/user/fooa", VCS: "git", RepoRoot: "https://example.com/repo/target"},
   353  			},
   354  			path: "example.com/user/foo",
   355  			mi:   metaImport{Prefix: "example.com/user/foo", VCS: "git", RepoRoot: "https://example.com/repo/target"},
   356  		},
   357  		{
   358  			imports: []metaImport{
   359  				{Prefix: "example.com/user/foo", VCS: "git", RepoRoot: "https://example.com/repo/target"},
   360  				{Prefix: "example.com/user/fooa", VCS: "git", RepoRoot: "https://example.com/repo/target"},
   361  			},
   362  			path: "example.com/user/fooa",
   363  			mi:   metaImport{Prefix: "example.com/user/fooa", VCS: "git", RepoRoot: "https://example.com/repo/target"},
   364  		},
   365  		{
   366  			imports: []metaImport{
   367  				{Prefix: "example.com/user/foo", VCS: "git", RepoRoot: "https://example.com/repo/target"},
   368  				{Prefix: "example.com/user/foo/bar", VCS: "git", RepoRoot: "https://example.com/repo/target"},
   369  			},
   370  			path: "example.com/user/foo/bar",
   371  			err:  errors.New("should not be allowed to create nested repo"),
   372  		},
   373  		{
   374  			imports: []metaImport{
   375  				{Prefix: "example.com/user/foo", VCS: "git", RepoRoot: "https://example.com/repo/target"},
   376  				{Prefix: "example.com/user/foo/bar", VCS: "git", RepoRoot: "https://example.com/repo/target"},
   377  			},
   378  			path: "example.com/user/foo/bar/baz",
   379  			err:  errors.New("should not be allowed to create nested repo"),
   380  		},
   381  		{
   382  			imports: []metaImport{
   383  				{Prefix: "example.com/user/foo", VCS: "git", RepoRoot: "https://example.com/repo/target"},
   384  				{Prefix: "example.com/user/foo/bar", VCS: "git", RepoRoot: "https://example.com/repo/target"},
   385  			},
   386  			path: "example.com/user/foo/bar/baz/qux",
   387  			err:  errors.New("should not be allowed to create nested repo"),
   388  		},
   389  		{
   390  			imports: []metaImport{
   391  				{Prefix: "example.com/user/foo", VCS: "git", RepoRoot: "https://example.com/repo/target"},
   392  				{Prefix: "example.com/user/foo/bar", VCS: "git", RepoRoot: "https://example.com/repo/target"},
   393  			},
   394  			path: "example.com/user/foo/bar/baz/",
   395  			err:  errors.New("should not be allowed to create nested repo"),
   396  		},
   397  		{
   398  			imports: []metaImport{
   399  				{Prefix: "example.com/user/foo", VCS: "git", RepoRoot: "https://example.com/repo/target"},
   400  				{Prefix: "example.com/user/foo/bar", VCS: "git", RepoRoot: "https://example.com/repo/target"},
   401  			},
   402  			path: "example.com",
   403  			err:  errors.New("pathologically short path"),
   404  		},
   405  		{
   406  			imports: []metaImport{
   407  				{Prefix: "example.com/user/foo", VCS: "git", RepoRoot: "https://example.com/repo/target"},
   408  			},
   409  			path: "different.example.com/user/foo",
   410  			err:  errors.New("meta tags do not match import path"),
   411  		},
   412  		{
   413  			imports: []metaImport{
   414  				{Prefix: "myitcv.io/blah2", VCS: "mod", RepoRoot: "https://raw.githubusercontent.com/myitcv/pubx/master"},
   415  				{Prefix: "myitcv.io", VCS: "git", RepoRoot: "https://github.com/myitcv/x"},
   416  			},
   417  			path: "myitcv.io/blah2/foo",
   418  			mi:   metaImport{Prefix: "myitcv.io/blah2", VCS: "mod", RepoRoot: "https://raw.githubusercontent.com/myitcv/pubx/master"},
   419  		},
   420  		{
   421  			imports: []metaImport{
   422  				{Prefix: "myitcv.io/blah2", VCS: "mod", RepoRoot: "https://raw.githubusercontent.com/myitcv/pubx/master"},
   423  				{Prefix: "myitcv.io", VCS: "git", RepoRoot: "https://github.com/myitcv/x"},
   424  			},
   425  			path: "myitcv.io/other",
   426  			mi:   metaImport{Prefix: "myitcv.io", VCS: "git", RepoRoot: "https://github.com/myitcv/x"},
   427  		},
   428  		{
   429  			imports: []metaImport{
   430  				{Prefix: "example.com/user/foo", VCS: "git", RepoRoot: "https://example.com/repo/target", SubDir: "subdir"},
   431  			},
   432  			path: "example.com/user/foo",
   433  			mi:   metaImport{Prefix: "example.com/user/foo", VCS: "git", RepoRoot: "https://example.com/repo/target", SubDir: "subdir"},
   434  		},
   435  		{
   436  			imports: []metaImport{
   437  				{Prefix: "example.com/user/foo", VCS: "git", RepoRoot: "https://example.com/repo/target", SubDir: "foo/subdir"},
   438  			},
   439  			path: "example.com/user/foo",
   440  			mi:   metaImport{Prefix: "example.com/user/foo", VCS: "git", RepoRoot: "https://example.com/repo/target", SubDir: "foo/subdir"},
   441  		},
   442  		{
   443  			imports: []metaImport{
   444  				{Prefix: "example.com/user/foo", VCS: "git", RepoRoot: "https://example.com/repo/target", SubDir: "subdir"},
   445  				{Prefix: "example.com/user/foo", VCS: "git", RepoRoot: "https://example.com/repo/target", SubDir: ""},
   446  			},
   447  			path: "example.com/user/foo",
   448  			err:  errors.New("multiple meta tags match import path"),
   449  		},
   450  	}
   451  
   452  	for _, test := range tests {
   453  		mi, err := matchGoImport(test.imports, test.path)
   454  		if mi != test.mi {
   455  			t.Errorf("unexpected metaImport; got %v, want %v", mi, test.mi)
   456  		}
   457  
   458  		got := err
   459  		want := test.err
   460  		if (got == nil) != (want == nil) {
   461  			t.Errorf("unexpected error; got %v, want %v", got, want)
   462  		}
   463  	}
   464  }
   465  
   466  func TestValidateRepoRoot(t *testing.T) {
   467  	tests := []struct {
   468  		root string
   469  		ok   bool
   470  	}{
   471  		{
   472  			root: "",
   473  			ok:   false,
   474  		},
   475  		{
   476  			root: "http://",
   477  			ok:   true,
   478  		},
   479  		{
   480  			root: "git+ssh://",
   481  			ok:   true,
   482  		},
   483  		{
   484  			root: "http#://",
   485  			ok:   false,
   486  		},
   487  		{
   488  			root: "-config",
   489  			ok:   false,
   490  		},
   491  		{
   492  			root: "-config://",
   493  			ok:   false,
   494  		},
   495  	}
   496  
   497  	for _, test := range tests {
   498  		err := validateRepoRoot(test.root)
   499  		ok := err == nil
   500  		if ok != test.ok {
   501  			want := "error"
   502  			if test.ok {
   503  				want = "nil"
   504  			}
   505  			t.Errorf("validateRepoRoot(%q) = %q, want %s", test.root, err, want)
   506  		}
   507  	}
   508  }
   509  
   510  var govcsTests = []struct {
   511  	govcs string
   512  	path  string
   513  	vcs   string
   514  	ok    bool
   515  }{
   516  	{"private:all", "is-public.com/foo", "zzz", false},
   517  	{"private:all", "is-private.com/foo", "zzz", true},
   518  	{"public:all", "is-public.com/foo", "zzz", true},
   519  	{"public:all", "is-private.com/foo", "zzz", false},
   520  	{"public:all,private:none", "is-public.com/foo", "zzz", true},
   521  	{"public:all,private:none", "is-private.com/foo", "zzz", false},
   522  	{"*:all", "is-public.com/foo", "zzz", true},
   523  	{"golang.org:git", "golang.org/x/text", "zzz", false},
   524  	{"golang.org:git", "golang.org/x/text", "git", true},
   525  	{"golang.org:zzz", "golang.org/x/text", "zzz", true},
   526  	{"golang.org:zzz", "golang.org/x/text", "git", false},
   527  	{"golang.org:zzz", "golang.org/x/text", "zzz", true},
   528  	{"golang.org:zzz", "golang.org/x/text", "git", false},
   529  	{"golang.org:git|hg", "golang.org/x/text", "hg", true},
   530  	{"golang.org:git|hg", "golang.org/x/text", "git", true},
   531  	{"golang.org:git|hg", "golang.org/x/text", "zzz", false},
   532  	{"golang.org:all", "golang.org/x/text", "hg", true},
   533  	{"golang.org:all", "golang.org/x/text", "git", true},
   534  	{"golang.org:all", "golang.org/x/text", "zzz", true},
   535  	{"other.xyz/p:none,golang.org/x:git", "other.xyz/p/x", "git", false},
   536  	{"other.xyz/p:none,golang.org/x:git", "unexpected.com", "git", false},
   537  	{"other.xyz/p:none,golang.org/x:git", "golang.org/x/text", "zzz", false},
   538  	{"other.xyz/p:none,golang.org/x:git", "golang.org/x/text", "git", true},
   539  	{"other.xyz/p:none,golang.org/x:zzz", "golang.org/x/text", "zzz", true},
   540  	{"other.xyz/p:none,golang.org/x:zzz", "golang.org/x/text", "git", false},
   541  	{"other.xyz/p:none,golang.org/x:git|hg", "golang.org/x/text", "hg", true},
   542  	{"other.xyz/p:none,golang.org/x:git|hg", "golang.org/x/text", "git", true},
   543  	{"other.xyz/p:none,golang.org/x:git|hg", "golang.org/x/text", "zzz", false},
   544  	{"other.xyz/p:none,golang.org/x:all", "golang.org/x/text", "hg", true},
   545  	{"other.xyz/p:none,golang.org/x:all", "golang.org/x/text", "git", true},
   546  	{"other.xyz/p:none,golang.org/x:all", "golang.org/x/text", "zzz", true},
   547  	{"other.xyz/p:none,golang.org/x:git", "golang.org/y/text", "zzz", false},
   548  	{"other.xyz/p:none,golang.org/x:git", "golang.org/y/text", "git", false},
   549  	{"other.xyz/p:none,golang.org/x:zzz", "golang.org/y/text", "zzz", false},
   550  	{"other.xyz/p:none,golang.org/x:zzz", "golang.org/y/text", "git", false},
   551  	{"other.xyz/p:none,golang.org/x:git|hg", "golang.org/y/text", "hg", false},
   552  	{"other.xyz/p:none,golang.org/x:git|hg", "golang.org/y/text", "git", false},
   553  	{"other.xyz/p:none,golang.org/x:git|hg", "golang.org/y/text", "zzz", false},
   554  	{"other.xyz/p:none,golang.org/x:all", "golang.org/y/text", "hg", false},
   555  	{"other.xyz/p:none,golang.org/x:all", "golang.org/y/text", "git", false},
   556  	{"other.xyz/p:none,golang.org/x:all", "golang.org/y/text", "zzz", false},
   557  }
   558  
   559  func TestGOVCS(t *testing.T) {
   560  	for _, tt := range govcsTests {
   561  		cfg, err := parseGOVCS(tt.govcs)
   562  		if err != nil {
   563  			t.Errorf("parseGOVCS(%q): %v", tt.govcs, err)
   564  			continue
   565  		}
   566  		private := strings.HasPrefix(tt.path, "is-private")
   567  		ok := cfg.allow(tt.path, private, tt.vcs)
   568  		if ok != tt.ok {
   569  			t.Errorf("parseGOVCS(%q).allow(%q, %v, %q) = %v, want %v",
   570  				tt.govcs, tt.path, private, tt.vcs, ok, tt.ok)
   571  		}
   572  	}
   573  }
   574  
   575  var govcsErrors = []struct {
   576  	s   string
   577  	err string
   578  }{
   579  	{`,`, `empty entry in GOVCS`},
   580  	{`,x`, `empty entry in GOVCS`},
   581  	{`x,`, `malformed entry in GOVCS (missing colon): "x"`},
   582  	{`x:y,`, `empty entry in GOVCS`},
   583  	{`x`, `malformed entry in GOVCS (missing colon): "x"`},
   584  	{`x:`, `empty VCS list in GOVCS: "x:"`},
   585  	{`x:|`, `empty VCS name in GOVCS: "x:|"`},
   586  	{`x:y|`, `empty VCS name in GOVCS: "x:y|"`},
   587  	{`x:|y`, `empty VCS name in GOVCS: "x:|y"`},
   588  	{`x:y,z:`, `empty VCS list in GOVCS: "z:"`},
   589  	{`x:y,z:|`, `empty VCS name in GOVCS: "z:|"`},
   590  	{`x:y,z:|w`, `empty VCS name in GOVCS: "z:|w"`},
   591  	{`x:y,z:w|`, `empty VCS name in GOVCS: "z:w|"`},
   592  	{`x:y,z:w||v`, `empty VCS name in GOVCS: "z:w||v"`},
   593  	{`x:y,x:z`, `unreachable pattern in GOVCS: "x:z" after "x:y"`},
   594  }
   595  
   596  func TestGOVCSErrors(t *testing.T) {
   597  	for _, tt := range govcsErrors {
   598  		_, err := parseGOVCS(tt.s)
   599  		if err == nil || !strings.Contains(err.Error(), tt.err) {
   600  			t.Errorf("parseGOVCS(%s): err=%v, want %v", tt.s, err, tt.err)
   601  		}
   602  	}
   603  }
   604  

View as plain text