github.com/golang/dep@v0.5.4/gps/deduce_test.go (about)

     1  // Copyright 2017 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 gps
     6  
     7  import (
     8  	"bytes"
     9  	"context"
    10  	"errors"
    11  	"fmt"
    12  	"net/url"
    13  	"reflect"
    14  	"testing"
    15  )
    16  
    17  type pathDeductionFixture struct {
    18  	in     string
    19  	root   string
    20  	rerr   error
    21  	mb     maybeSources
    22  	srcerr error
    23  }
    24  
    25  // helper func to generate testing *url.URLs, panicking on err
    26  func mkurl(s string) (u *url.URL) {
    27  	var err error
    28  	u, err = url.Parse(s)
    29  	if err != nil {
    30  		panic(fmt.Sprint("string is not a valid URL:", s))
    31  	}
    32  	return
    33  }
    34  
    35  var pathDeductionFixtures = map[string][]pathDeductionFixture{
    36  	"github": {
    37  		{
    38  			in:   "github.com/sdboyer/gps",
    39  			root: "github.com/sdboyer/gps",
    40  			mb: maybeSources{
    41  				maybeGitSource{url: mkurl("https://github.com/sdboyer/gps")},
    42  				maybeGitSource{url: mkurl("ssh://git@github.com/sdboyer/gps")},
    43  				maybeGitSource{url: mkurl("git://github.com/sdboyer/gps")},
    44  				maybeGitSource{url: mkurl("http://github.com/sdboyer/gps")},
    45  			},
    46  		},
    47  		{
    48  			in:   "github.com/sdboyer/gps/foo",
    49  			root: "github.com/sdboyer/gps",
    50  			mb: maybeSources{
    51  				maybeGitSource{url: mkurl("https://github.com/sdboyer/gps")},
    52  				maybeGitSource{url: mkurl("ssh://git@github.com/sdboyer/gps")},
    53  				maybeGitSource{url: mkurl("git://github.com/sdboyer/gps")},
    54  				maybeGitSource{url: mkurl("http://github.com/sdboyer/gps")},
    55  			},
    56  		},
    57  		{
    58  			// TODO(sdboyer) is this a problem for enforcing uniqueness? do we
    59  			// need to collapse these extensions?
    60  			in:   "github.com/sdboyer/gps.git/foo",
    61  			root: "github.com/sdboyer/gps.git",
    62  			mb: maybeSources{
    63  				maybeGitSource{url: mkurl("https://github.com/sdboyer/gps.git")},
    64  				maybeGitSource{url: mkurl("ssh://git@github.com/sdboyer/gps.git")},
    65  				maybeGitSource{url: mkurl("git://github.com/sdboyer/gps.git")},
    66  				maybeGitSource{url: mkurl("http://github.com/sdboyer/gps.git")},
    67  			},
    68  		},
    69  		{
    70  			in:   "git@github.com:sdboyer/gps",
    71  			root: "github.com/sdboyer/gps",
    72  			mb: maybeSources{
    73  				maybeGitSource{url: mkurl("ssh://git@github.com/sdboyer/gps")},
    74  			},
    75  		},
    76  		{
    77  			in:   "https://github.com/sdboyer/gps",
    78  			root: "github.com/sdboyer/gps",
    79  			mb: maybeSources{
    80  				maybeGitSource{url: mkurl("https://github.com/sdboyer/gps")},
    81  			},
    82  		},
    83  		{
    84  			in:   "https://github.com/sdboyer/gps/foo/bar",
    85  			root: "github.com/sdboyer/gps",
    86  			mb: maybeSources{
    87  				maybeGitSource{url: mkurl("https://github.com/sdboyer/gps")},
    88  			},
    89  		},
    90  		{
    91  			in:   "github.com/sdboyer-/gps/foo",
    92  			root: "github.com/sdboyer-/gps",
    93  			mb: maybeSources{
    94  				maybeGitSource{url: mkurl("https://github.com/sdboyer-/gps")},
    95  				maybeGitSource{url: mkurl("ssh://git@github.com/sdboyer-/gps")},
    96  				maybeGitSource{url: mkurl("git://github.com/sdboyer-/gps")},
    97  				maybeGitSource{url: mkurl("http://github.com/sdboyer-/gps")},
    98  			},
    99  		},
   100  		{
   101  			in:   "github.com/a/gps/foo",
   102  			root: "github.com/a/gps",
   103  			mb: maybeSources{
   104  				maybeGitSource{url: mkurl("https://github.com/a/gps")},
   105  				maybeGitSource{url: mkurl("ssh://git@github.com/a/gps")},
   106  				maybeGitSource{url: mkurl("git://github.com/a/gps")},
   107  				maybeGitSource{url: mkurl("http://github.com/a/gps")},
   108  			},
   109  		},
   110  		// some invalid github username patterns
   111  		{
   112  			in:   "github.com/-sdboyer/gps/foo",
   113  			rerr: errors.New("github.com/-sdboyer/gps/foo is not a valid path for a source on github.com"),
   114  		},
   115  		{
   116  			in:   "github.com/sdbo.yer/gps/foo",
   117  			rerr: errors.New("github.com/sdbo.yer/gps/foo is not a valid path for a source on github.com"),
   118  		},
   119  		{
   120  			in:   "github.com/sdbo_yer/gps/foo",
   121  			rerr: errors.New("github.com/sdbo_yer/gps/foo is not a valid path for a source on github.com"),
   122  		},
   123  		// Regression - gh does allow two-letter usernames
   124  		{
   125  			in:   "github.com/kr/pretty",
   126  			root: "github.com/kr/pretty",
   127  			mb: maybeSources{
   128  				maybeGitSource{url: mkurl("https://github.com/kr/pretty")},
   129  				maybeGitSource{url: mkurl("ssh://git@github.com/kr/pretty")},
   130  				maybeGitSource{url: mkurl("git://github.com/kr/pretty")},
   131  				maybeGitSource{url: mkurl("http://github.com/kr/pretty")},
   132  			},
   133  		},
   134  	},
   135  	"gopkg.in": {
   136  		{
   137  			in:   "gopkg.in/sdboyer/gps.v0",
   138  			root: "gopkg.in/sdboyer/gps.v0",
   139  			mb: maybeSources{
   140  				maybeGopkginSource{opath: "gopkg.in/sdboyer/gps.v0", url: mkurl("https://github.com/sdboyer/gps"), major: 0},
   141  				maybeGopkginSource{opath: "gopkg.in/sdboyer/gps.v0", url: mkurl("http://github.com/sdboyer/gps"), major: 0},
   142  			},
   143  		},
   144  		{
   145  			in:   "gopkg.in/sdboyer/gps.v0/foo",
   146  			root: "gopkg.in/sdboyer/gps.v0",
   147  			mb: maybeSources{
   148  				maybeGopkginSource{opath: "gopkg.in/sdboyer/gps.v0", url: mkurl("https://github.com/sdboyer/gps"), major: 0},
   149  				maybeGopkginSource{opath: "gopkg.in/sdboyer/gps.v0", url: mkurl("http://github.com/sdboyer/gps"), major: 0},
   150  			},
   151  		},
   152  		{
   153  			in:   "gopkg.in/sdboyer/gps.v1/foo/bar",
   154  			root: "gopkg.in/sdboyer/gps.v1",
   155  			mb: maybeSources{
   156  				maybeGopkginSource{opath: "gopkg.in/sdboyer/gps.v1", url: mkurl("https://github.com/sdboyer/gps"), major: 1},
   157  				maybeGopkginSource{opath: "gopkg.in/sdboyer/gps.v1", url: mkurl("http://github.com/sdboyer/gps"), major: 1},
   158  			},
   159  		},
   160  		{
   161  			in:   "gopkg.in/yaml.v1",
   162  			root: "gopkg.in/yaml.v1",
   163  			mb: maybeSources{
   164  				maybeGopkginSource{opath: "gopkg.in/yaml.v1", url: mkurl("https://github.com/go-yaml/yaml"), major: 1},
   165  				maybeGopkginSource{opath: "gopkg.in/yaml.v1", url: mkurl("http://github.com/go-yaml/yaml"), major: 1},
   166  			},
   167  		},
   168  		{
   169  			in:   "gopkg.in/yaml.v1/foo/bar",
   170  			root: "gopkg.in/yaml.v1",
   171  			mb: maybeSources{
   172  
   173  				maybeGopkginSource{opath: "gopkg.in/yaml.v1", url: mkurl("https://github.com/go-yaml/yaml"), major: 1},
   174  				maybeGopkginSource{opath: "gopkg.in/yaml.v1", url: mkurl("http://github.com/go-yaml/yaml"), major: 1},
   175  			},
   176  		},
   177  		{
   178  			in:   "gopkg.in/inf.v0",
   179  			root: "gopkg.in/inf.v0",
   180  			mb: maybeSources{
   181  				maybeGopkginSource{opath: "gopkg.in/inf.v0", url: mkurl("https://github.com/go-inf/inf"), major: 0},
   182  				maybeGopkginSource{opath: "gopkg.in/inf.v0", url: mkurl("http://github.com/go-inf/inf"), major: 0},
   183  			},
   184  		},
   185  		{
   186  			// gopkg.in only allows specifying major version in import path
   187  			in:   "gopkg.in/yaml.v1.2",
   188  			rerr: errors.New("gopkg.in/yaml.v1.2 is not a valid import path; gopkg.in only allows major versions (\"v1\" instead of \"v1.2\")"),
   189  		},
   190  	},
   191  	"jazz": {
   192  		// IBM hub devops services - fixtures borrowed from go get
   193  		{
   194  			in:   "hub.jazz.net/git/user1/pkgname",
   195  			root: "hub.jazz.net/git/user1/pkgname",
   196  			mb: maybeSources{
   197  				maybeGitSource{url: mkurl("https://hub.jazz.net/git/user1/pkgname")},
   198  			},
   199  		},
   200  		{
   201  			in:   "hub.jazz.net/git/user1/pkgname/submodule/submodule/submodule",
   202  			root: "hub.jazz.net/git/user1/pkgname",
   203  			mb: maybeSources{
   204  				maybeGitSource{url: mkurl("https://hub.jazz.net/git/user1/pkgname")},
   205  			},
   206  		},
   207  		{
   208  			in:   "hub.jazz.net/someotherprefix",
   209  			rerr: errors.New("hub.jazz.net/someotherprefix is not a valid path for a source on hub.jazz.net"),
   210  		},
   211  		{
   212  			in:   "hub.jazz.net/someotherprefix/user1/packagename",
   213  			rerr: errors.New("hub.jazz.net/someotherprefix/user1/packagename is not a valid path for a source on hub.jazz.net"),
   214  		},
   215  		// Spaces are not valid in user names or package names
   216  		{
   217  			in:   "hub.jazz.net/git/User 1/pkgname",
   218  			rerr: errors.New("hub.jazz.net/git/User 1/pkgname is not a valid path for a source on hub.jazz.net"),
   219  		},
   220  		{
   221  			in:   "hub.jazz.net/git/user1/pkg name",
   222  			rerr: errors.New("hub.jazz.net/git/user1/pkg name is not a valid path for a source on hub.jazz.net"),
   223  		},
   224  		// Dots are not valid in user names
   225  		{
   226  			in:   "hub.jazz.net/git/user.1/pkgname",
   227  			rerr: errors.New("hub.jazz.net/git/user.1/pkgname is not a valid path for a source on hub.jazz.net"),
   228  		},
   229  		{
   230  			in:   "hub.jazz.net/git/user1/pkg.name",
   231  			root: "hub.jazz.net/git/user1/pkg.name",
   232  			mb: maybeSources{
   233  				maybeGitSource{url: mkurl("https://hub.jazz.net/git/user1/pkg.name")},
   234  			},
   235  		},
   236  		// User names cannot have uppercase letters
   237  		{
   238  			in:   "hub.jazz.net/git/USER/pkgname",
   239  			rerr: errors.New("hub.jazz.net/git/USER/pkgname is not a valid path for a source on hub.jazz.net"),
   240  		},
   241  	},
   242  	"bitbucket": {
   243  		{
   244  			in:   "bitbucket.org/sdboyer/reporoot",
   245  			root: "bitbucket.org/sdboyer/reporoot",
   246  			mb: maybeSources{
   247  				maybeHgSource{url: mkurl("https://bitbucket.org/sdboyer/reporoot")},
   248  				maybeHgSource{url: mkurl("ssh://hg@bitbucket.org/sdboyer/reporoot")},
   249  				maybeHgSource{url: mkurl("http://bitbucket.org/sdboyer/reporoot")},
   250  				maybeGitSource{url: mkurl("https://bitbucket.org/sdboyer/reporoot")},
   251  				maybeGitSource{url: mkurl("ssh://git@bitbucket.org/sdboyer/reporoot")},
   252  				maybeGitSource{url: mkurl("git://bitbucket.org/sdboyer/reporoot")},
   253  				maybeGitSource{url: mkurl("http://bitbucket.org/sdboyer/reporoot")},
   254  			},
   255  		},
   256  		{
   257  			in:   "bitbucket.org/sdboyer/reporoot/foo/bar",
   258  			root: "bitbucket.org/sdboyer/reporoot",
   259  			mb: maybeSources{
   260  				maybeHgSource{url: mkurl("https://bitbucket.org/sdboyer/reporoot")},
   261  				maybeHgSource{url: mkurl("ssh://hg@bitbucket.org/sdboyer/reporoot")},
   262  				maybeHgSource{url: mkurl("http://bitbucket.org/sdboyer/reporoot")},
   263  				maybeGitSource{url: mkurl("https://bitbucket.org/sdboyer/reporoot")},
   264  				maybeGitSource{url: mkurl("ssh://git@bitbucket.org/sdboyer/reporoot")},
   265  				maybeGitSource{url: mkurl("git://bitbucket.org/sdboyer/reporoot")},
   266  				maybeGitSource{url: mkurl("http://bitbucket.org/sdboyer/reporoot")},
   267  			},
   268  		},
   269  		{
   270  			in:   "https://bitbucket.org/sdboyer/reporoot/foo/bar",
   271  			root: "bitbucket.org/sdboyer/reporoot",
   272  			mb: maybeSources{
   273  				maybeHgSource{url: mkurl("https://bitbucket.org/sdboyer/reporoot")},
   274  				maybeGitSource{url: mkurl("https://bitbucket.org/sdboyer/reporoot")},
   275  			},
   276  		},
   277  		// Less standard behaviors possible due to the hg/git ambiguity
   278  		{
   279  			in:   "bitbucket.org/sdboyer/reporoot.git",
   280  			root: "bitbucket.org/sdboyer/reporoot.git",
   281  			mb: maybeSources{
   282  				maybeGitSource{url: mkurl("https://bitbucket.org/sdboyer/reporoot.git")},
   283  				maybeGitSource{url: mkurl("ssh://git@bitbucket.org/sdboyer/reporoot.git")},
   284  				maybeGitSource{url: mkurl("git://bitbucket.org/sdboyer/reporoot.git")},
   285  				maybeGitSource{url: mkurl("http://bitbucket.org/sdboyer/reporoot.git")},
   286  			},
   287  		},
   288  		{
   289  			in:   "git@bitbucket.org:sdboyer/reporoot.git",
   290  			root: "bitbucket.org/sdboyer/reporoot.git",
   291  			mb: maybeSources{
   292  				maybeGitSource{url: mkurl("ssh://git@bitbucket.org/sdboyer/reporoot.git")},
   293  			},
   294  		},
   295  		{
   296  			in:   "bitbucket.org/sdboyer/reporoot.hg",
   297  			root: "bitbucket.org/sdboyer/reporoot.hg",
   298  			mb: maybeSources{
   299  				maybeHgSource{url: mkurl("https://bitbucket.org/sdboyer/reporoot.hg")},
   300  				maybeHgSource{url: mkurl("ssh://hg@bitbucket.org/sdboyer/reporoot.hg")},
   301  				maybeHgSource{url: mkurl("http://bitbucket.org/sdboyer/reporoot.hg")},
   302  			},
   303  		},
   304  		{
   305  			in:   "hg@bitbucket.org:sdboyer/reporoot",
   306  			root: "bitbucket.org/sdboyer/reporoot",
   307  			mb: maybeSources{
   308  				maybeHgSource{url: mkurl("ssh://hg@bitbucket.org/sdboyer/reporoot")},
   309  			},
   310  		},
   311  		{
   312  			in:     "git://bitbucket.org/sdboyer/reporoot.hg",
   313  			root:   "bitbucket.org/sdboyer/reporoot.hg",
   314  			srcerr: errors.New("git is not a valid scheme for accessing an hg repository"),
   315  		},
   316  	},
   317  	"launchpad": {
   318  		// tests for launchpad, mostly bazaar
   319  		// TODO(sdboyer) need more tests to deal w/launchpad's oddities
   320  		{
   321  			in:   "launchpad.net/govcstestbzrrepo",
   322  			root: "launchpad.net/govcstestbzrrepo",
   323  			mb: maybeSources{
   324  				maybeBzrSource{url: mkurl("https://launchpad.net/govcstestbzrrepo")},
   325  				maybeBzrSource{url: mkurl("bzr+ssh://launchpad.net/govcstestbzrrepo")},
   326  				maybeBzrSource{url: mkurl("bzr://launchpad.net/govcstestbzrrepo")},
   327  				maybeBzrSource{url: mkurl("http://launchpad.net/govcstestbzrrepo")},
   328  			},
   329  		},
   330  		{
   331  			in:   "launchpad.net/govcstestbzrrepo/foo/bar",
   332  			root: "launchpad.net/govcstestbzrrepo",
   333  			mb: maybeSources{
   334  				maybeBzrSource{url: mkurl("https://launchpad.net/govcstestbzrrepo")},
   335  				maybeBzrSource{url: mkurl("bzr+ssh://launchpad.net/govcstestbzrrepo")},
   336  				maybeBzrSource{url: mkurl("bzr://launchpad.net/govcstestbzrrepo")},
   337  				maybeBzrSource{url: mkurl("http://launchpad.net/govcstestbzrrepo")},
   338  			},
   339  		},
   340  		{
   341  			in:   "launchpad.net/repo root",
   342  			rerr: errors.New("launchpad.net/repo root is not a valid path for a source on launchpad.net"),
   343  		},
   344  	},
   345  	"git.launchpad": {
   346  		{
   347  			in:   "git.launchpad.net/reporoot",
   348  			root: "git.launchpad.net/reporoot",
   349  			mb: maybeSources{
   350  				maybeGitSource{url: mkurl("https://git.launchpad.net/reporoot")},
   351  				maybeGitSource{url: mkurl("ssh://git.launchpad.net/reporoot")},
   352  				maybeGitSource{url: mkurl("git://git.launchpad.net/reporoot")},
   353  				maybeGitSource{url: mkurl("http://git.launchpad.net/reporoot")},
   354  			},
   355  		},
   356  		{
   357  			in:   "git.launchpad.net/reporoot/foo/bar",
   358  			root: "git.launchpad.net/reporoot",
   359  			mb: maybeSources{
   360  				maybeGitSource{url: mkurl("https://git.launchpad.net/reporoot")},
   361  				maybeGitSource{url: mkurl("ssh://git.launchpad.net/reporoot")},
   362  				maybeGitSource{url: mkurl("git://git.launchpad.net/reporoot")},
   363  				maybeGitSource{url: mkurl("http://git.launchpad.net/reporoot")},
   364  			},
   365  		},
   366  		{
   367  			in:   "git.launchpad.net/repo root",
   368  			rerr: errors.New("git.launchpad.net/repo root is not a valid path for a source on git.launchpad.net"),
   369  		},
   370  	},
   371  	"apache": {
   372  		{
   373  			in:   "git.apache.org/package-name.git",
   374  			root: "git.apache.org/package-name.git",
   375  			mb: maybeSources{
   376  				maybeGitSource{url: mkurl("https://git.apache.org/package-name.git")},
   377  				maybeGitSource{url: mkurl("ssh://git.apache.org/package-name.git")},
   378  				maybeGitSource{url: mkurl("git://git.apache.org/package-name.git")},
   379  				maybeGitSource{url: mkurl("http://git.apache.org/package-name.git")},
   380  			},
   381  		},
   382  		{
   383  			in:   "git.apache.org/package-name.git/foo/bar",
   384  			root: "git.apache.org/package-name.git",
   385  			mb: maybeSources{
   386  				maybeGitSource{url: mkurl("https://git.apache.org/package-name.git")},
   387  				maybeGitSource{url: mkurl("ssh://git.apache.org/package-name.git")},
   388  				maybeGitSource{url: mkurl("git://git.apache.org/package-name.git")},
   389  				maybeGitSource{url: mkurl("http://git.apache.org/package-name.git")},
   390  			},
   391  		},
   392  	},
   393  	"vcsext": {
   394  		// VCS extension-based syntax
   395  		{
   396  			in:   "foobar.com/baz.git",
   397  			root: "foobar.com/baz.git",
   398  			mb: maybeSources{
   399  				maybeGitSource{url: mkurl("https://foobar.com/baz.git")},
   400  				maybeGitSource{url: mkurl("ssh://foobar.com/baz.git")},
   401  				maybeGitSource{url: mkurl("git://foobar.com/baz.git")},
   402  				maybeGitSource{url: mkurl("http://foobar.com/baz.git")},
   403  			},
   404  		},
   405  		{
   406  			in:   "foobar.com/baz.git/extra/path",
   407  			root: "foobar.com/baz.git",
   408  			mb: maybeSources{
   409  				maybeGitSource{url: mkurl("https://foobar.com/baz.git")},
   410  				maybeGitSource{url: mkurl("ssh://foobar.com/baz.git")},
   411  				maybeGitSource{url: mkurl("git://foobar.com/baz.git")},
   412  				maybeGitSource{url: mkurl("http://foobar.com/baz.git")},
   413  			},
   414  		},
   415  		{
   416  			in:   "foobar.com/baz.bzr",
   417  			root: "foobar.com/baz.bzr",
   418  			mb: maybeSources{
   419  				maybeBzrSource{url: mkurl("https://foobar.com/baz.bzr")},
   420  				maybeBzrSource{url: mkurl("bzr+ssh://foobar.com/baz.bzr")},
   421  				maybeBzrSource{url: mkurl("bzr://foobar.com/baz.bzr")},
   422  				maybeBzrSource{url: mkurl("http://foobar.com/baz.bzr")},
   423  			},
   424  		},
   425  		{
   426  			in:   "foo-bar.com/baz.hg",
   427  			root: "foo-bar.com/baz.hg",
   428  			mb: maybeSources{
   429  				maybeHgSource{url: mkurl("https://foo-bar.com/baz.hg")},
   430  				maybeHgSource{url: mkurl("ssh://foo-bar.com/baz.hg")},
   431  				maybeHgSource{url: mkurl("http://foo-bar.com/baz.hg")},
   432  			},
   433  		},
   434  		{
   435  			in:   "git@foobar.com:baz.git",
   436  			root: "foobar.com/baz.git",
   437  			mb: maybeSources{
   438  				maybeGitSource{url: mkurl("ssh://git@foobar.com/baz.git")},
   439  			},
   440  		},
   441  		{
   442  			in:   "bzr+ssh://foobar.com/baz.bzr",
   443  			root: "foobar.com/baz.bzr",
   444  			mb: maybeSources{
   445  				maybeBzrSource{url: mkurl("bzr+ssh://foobar.com/baz.bzr")},
   446  			},
   447  		},
   448  		{
   449  			in:   "ssh://foobar.com/baz.bzr",
   450  			root: "foobar.com/baz.bzr",
   451  			mb: maybeSources{
   452  				maybeBzrSource{url: mkurl("ssh://foobar.com/baz.bzr")},
   453  			},
   454  		},
   455  		{
   456  			in:   "https://foobar.com/baz.hg",
   457  			root: "foobar.com/baz.hg",
   458  			mb: maybeSources{
   459  				maybeHgSource{url: mkurl("https://foobar.com/baz.hg")},
   460  			},
   461  		},
   462  		{
   463  			in:     "git://foobar.com/baz.hg",
   464  			root:   "foobar.com/baz.hg",
   465  			srcerr: errors.New("git is not a valid scheme for accessing hg repositories (path foobar.com/baz.hg)"),
   466  		},
   467  		// who knows why anyone would do this, but having a second vcs ext
   468  		// shouldn't throw us off - only the first one counts
   469  		{
   470  			in:   "foobar.com/baz.git/quark/quizzle.bzr/quorum",
   471  			root: "foobar.com/baz.git",
   472  			mb: maybeSources{
   473  				maybeGitSource{url: mkurl("https://foobar.com/baz.git")},
   474  				maybeGitSource{url: mkurl("ssh://foobar.com/baz.git")},
   475  				maybeGitSource{url: mkurl("git://foobar.com/baz.git")},
   476  				maybeGitSource{url: mkurl("http://foobar.com/baz.git")},
   477  			},
   478  		},
   479  	},
   480  	"vanity": {
   481  		// Vanity imports
   482  		{
   483  			in:   "golang.org/x/exp",
   484  			root: "golang.org/x/exp",
   485  			mb: maybeSources{
   486  				maybeGitSource{url: mkurl("https://go.googlesource.com/exp")},
   487  			},
   488  		},
   489  		{
   490  			in:   "golang.org/x/exp/inotify",
   491  			root: "golang.org/x/exp",
   492  			mb: maybeSources{
   493  				maybeGitSource{url: mkurl("https://go.googlesource.com/exp")},
   494  			},
   495  		},
   496  		{
   497  			in:   "golang.org/x/net/html",
   498  			root: "golang.org/x/net",
   499  			mb: maybeSources{
   500  				maybeGitSource{url: mkurl("https://go.googlesource.com/net")},
   501  			},
   502  		},
   503  	},
   504  }
   505  
   506  func TestDeduceFromPath(t *testing.T) {
   507  	do := func(typ string, fixtures []pathDeductionFixture, t *testing.T) {
   508  		t.Run(typ, func(t *testing.T) {
   509  			t.Parallel()
   510  
   511  			var deducer pathDeducer
   512  			switch typ {
   513  			case "github":
   514  				deducer = githubDeducer{regexp: ghRegex}
   515  			case "gopkg.in":
   516  				deducer = gopkginDeducer{regexp: gpinNewRegex}
   517  			case "jazz":
   518  				deducer = jazzDeducer{regexp: jazzRegex}
   519  			case "bitbucket":
   520  				deducer = bitbucketDeducer{regexp: bbRegex}
   521  			case "launchpad":
   522  				deducer = launchpadDeducer{regexp: lpRegex}
   523  			case "git.launchpad":
   524  				deducer = launchpadGitDeducer{regexp: glpRegex}
   525  			case "apache":
   526  				deducer = apacheDeducer{regexp: apacheRegex}
   527  			case "vcsext":
   528  				deducer = vcsExtensionDeducer{regexp: vcsExtensionRegex}
   529  			default:
   530  				// Should just be the vanity imports, which we do elsewhere
   531  				t.Log("skipping")
   532  				t.SkipNow()
   533  			}
   534  
   535  			printmb := func(mb maybeSources) string {
   536  				var buf bytes.Buffer
   537  				fmt.Fprintf(&buf, "%v maybeSources:", len(mb))
   538  				for _, elem := range mb {
   539  					fmt.Fprintf(&buf, "\n\t\t%s", elem)
   540  				}
   541  				return buf.String()
   542  			}
   543  
   544  			for _, fix := range fixtures {
   545  				fix := fix
   546  				t.Run(fix.in, func(t *testing.T) {
   547  					t.Parallel()
   548  					u, in, uerr := normalizeURI(fix.in)
   549  					if uerr != nil {
   550  						if fix.rerr == nil {
   551  							t.Errorf("bad input URI %s", uerr)
   552  						}
   553  						t.SkipNow()
   554  					}
   555  
   556  					root, rerr := deducer.deduceRoot(in)
   557  					if fix.rerr != nil {
   558  						if rerr == nil {
   559  							t.Errorf("Expected error on deducing root, got none:\n\t(WNT) %s", fix.rerr)
   560  						} else if fix.rerr.Error() != rerr.Error() {
   561  							t.Errorf("Got unexpected error on deducing root:\n\t(GOT) %s\n\t(WNT) %s", rerr, fix.rerr)
   562  						}
   563  					} else if rerr != nil {
   564  						t.Errorf("Got unexpected error on deducing root:\n\t(GOT) %s", rerr)
   565  					} else if root != fix.root {
   566  						t.Errorf("Deducer did not return expected root:\n\t(GOT) %s\n\t(WNT) %s", root, fix.root)
   567  					}
   568  
   569  					mb, mberr := deducer.deduceSource(in, u)
   570  					if fix.srcerr != nil {
   571  						if mberr == nil {
   572  							t.Errorf("Expected error on deducing source, got none:\n\t(WNT) %s", fix.srcerr)
   573  						} else if fix.srcerr.Error() != mberr.Error() {
   574  							t.Errorf("Got unexpected error on deducing source:\n\t(GOT) %s\n\t(WNT) %s", mberr, fix.srcerr)
   575  						}
   576  					} else if mberr != nil {
   577  						// don't complain the fix already expected an rerr
   578  						if fix.rerr == nil {
   579  							t.Errorf("Got unexpected error on deducing source:\n\t(GOT) %s", mberr)
   580  						}
   581  					} else if !reflect.DeepEqual(mb, fix.mb) {
   582  						if mb == nil {
   583  							t.Errorf("Deducer returned source maybes, but none expected:\n\t(GOT) (none)\n\t(WNT) %s", printmb(fix.mb))
   584  						} else if fix.mb == nil {
   585  							t.Errorf("Deducer returned source maybes, but none expected:\n\t(GOT) %s\n\t(WNT) (none)", printmb(mb))
   586  						} else {
   587  							t.Errorf("Deducer did not return expected source:\n\t(GOT) %s\n\t(WNT) %s", printmb(mb), printmb(fix.mb))
   588  						}
   589  					}
   590  				})
   591  			}
   592  		})
   593  	}
   594  	runSet := func(t *testing.T) {
   595  		for typ, fixtures := range pathDeductionFixtures {
   596  			do(typ, fixtures, t)
   597  		}
   598  	}
   599  	t.Run("first", runSet)
   600  
   601  	// Run the test set twice to ensure results are correct for both cached
   602  	// and uncached deductions.
   603  	t.Run("second", runSet)
   604  }
   605  
   606  func TestVanityDeduction(t *testing.T) {
   607  	if testing.Short() {
   608  		t.Skip("Skipping slow test in short mode")
   609  	}
   610  
   611  	sm, clean := mkNaiveSM(t)
   612  	defer clean()
   613  
   614  	vanities := pathDeductionFixtures["vanity"]
   615  	// group to avoid sourcemanager cleanup
   616  	ctx := context.Background()
   617  	do := func(t *testing.T) {
   618  		for _, fix := range vanities {
   619  			fix := fix
   620  			t.Run(fix.in, func(t *testing.T) {
   621  				t.Parallel()
   622  
   623  				pr, err := sm.DeduceProjectRoot(fix.in)
   624  				if err != nil {
   625  					t.Errorf("Unexpected err on deducing project root: %s", err)
   626  					return
   627  				} else if string(pr) != fix.root {
   628  					t.Errorf("Deducer did not return expected root:\n\t(GOT) %s\n\t(WNT) %s", pr, fix.root)
   629  				}
   630  
   631  				pd, err := sm.deduceCoord.deduceRootPath(ctx, fix.in)
   632  				if err != nil {
   633  					t.Errorf("Unexpected err on deducing source: %s", err)
   634  					return
   635  				}
   636  
   637  				if len(pd.mb) != 1 {
   638  					t.Errorf("Expected single maybeSource, but found: %d", len(pd.mb))
   639  					return
   640  				}
   641  
   642  				goturl, wanturl := pd.mb[0].(maybeGitSource).url.String(), fix.mb[0].(maybeGitSource).url.String()
   643  				if goturl != wanturl {
   644  					t.Errorf("Deduced repo ident does not match fixture:\n\t(GOT) %s\n\t(WNT) %s", goturl, wanturl)
   645  				}
   646  
   647  				urls, err := sm.SourceURLsForPath(fix.in)
   648  				if err != nil {
   649  					t.Errorf("Unexpected err on deducing source urls: %s", err)
   650  					return
   651  				}
   652  				if len(urls) != 1 {
   653  					t.Errorf("Deduced source URLs count for a vanity import should be 1, got %d", len(urls))
   654  				}
   655  				goturl = urls[0].String()
   656  				if goturl != wanturl {
   657  					t.Errorf("Deduced source URL does not match fixture:\n\t(GOT) %s\n\t(WNT) %s", goturl, wanturl)
   658  				}
   659  			})
   660  		}
   661  	}
   662  
   663  	// Run twice, to ensure correctness of cache
   664  	t.Run("first", do)
   665  	t.Run("second", do)
   666  }
   667  
   668  func TestVanityDeductionSchemeMismatch(t *testing.T) {
   669  	if testing.Short() {
   670  		t.Skip("Skipping slow test in short mode")
   671  	}
   672  
   673  	ctx := context.Background()
   674  	cm := newSupervisor(ctx)
   675  	dc := newDeductionCoordinator(cm)
   676  	_, err := dc.deduceRootPath(ctx, "ssh://golang.org/exp")
   677  	// TODO(sdboyer) this is not actually the error that it should be
   678  	if err == nil {
   679  		t.Error("should have errored on scheme mismatch between input and go-get metadata")
   680  	}
   681  }