...

Source file src/golang.org/x/mod/module/module_test.go

Documentation: golang.org/x/mod/module

     1  // 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  
     5  package module
     6  
     7  import "testing"
     8  
     9  var checkTests = []struct {
    10  	path    string
    11  	version string
    12  	ok      bool
    13  }{
    14  	{"rsc.io/quote", "0.1.0", false},
    15  	{"rsc io/quote", "v1.0.0", false},
    16  
    17  	{"github.com/go-yaml/yaml", "v0.8.0", true},
    18  	{"github.com/go-yaml/yaml", "v1.0.0", true},
    19  	{"github.com/go-yaml/yaml", "v2.0.0", false},
    20  	{"github.com/go-yaml/yaml", "v2.1.5", false},
    21  	{"github.com/go-yaml/yaml", "v3.0.0", false},
    22  
    23  	{"github.com/go-yaml/yaml/v2", "v1.0.0", false},
    24  	{"github.com/go-yaml/yaml/v2", "v2.0.0", true},
    25  	{"github.com/go-yaml/yaml/v2", "v2.1.5", true},
    26  	{"github.com/go-yaml/yaml/v2", "v3.0.0", false},
    27  
    28  	{"gopkg.in/yaml.v0", "v0.8.0", true},
    29  	{"gopkg.in/yaml.v0", "v1.0.0", false},
    30  	{"gopkg.in/yaml.v0", "v2.0.0", false},
    31  	{"gopkg.in/yaml.v0", "v2.1.5", false},
    32  	{"gopkg.in/yaml.v0", "v3.0.0", false},
    33  
    34  	{"gopkg.in/yaml.v1", "v0.8.0", false},
    35  	{"gopkg.in/yaml.v1", "v1.0.0", true},
    36  	{"gopkg.in/yaml.v1", "v2.0.0", false},
    37  	{"gopkg.in/yaml.v1", "v2.1.5", false},
    38  	{"gopkg.in/yaml.v1", "v3.0.0", false},
    39  
    40  	// For gopkg.in, .v1 means v1 only (not v0).
    41  	// But early versions of vgo still generated v0 pseudo-versions for it.
    42  	// Even though now we'd generate those as v1 pseudo-versions,
    43  	// we accept the old pseudo-versions to avoid breaking existing go.mod files.
    44  	// For example gopkg.in/yaml.v2@v2.2.1's go.mod requires check.v1 at a v0 pseudo-version.
    45  	{"gopkg.in/check.v1", "v0.0.0", false},
    46  	{"gopkg.in/check.v1", "v0.0.0-20160102150405-abcdef123456", true},
    47  
    48  	{"gopkg.in/yaml.v2", "v1.0.0", false},
    49  	{"gopkg.in/yaml.v2", "v2.0.0", true},
    50  	{"gopkg.in/yaml.v2", "v2.1.5", true},
    51  	{"gopkg.in/yaml.v2", "v3.0.0", false},
    52  
    53  	{"rsc.io/quote", "v17.0.0", false},
    54  	{"rsc.io/quote", "v17.0.0+incompatible", true},
    55  }
    56  
    57  func TestCheck(t *testing.T) {
    58  	for _, tt := range checkTests {
    59  		err := Check(tt.path, tt.version)
    60  		if tt.ok && err != nil {
    61  			t.Errorf("Check(%q, %q) = %v, wanted nil error", tt.path, tt.version, err)
    62  		} else if !tt.ok && err == nil {
    63  			t.Errorf("Check(%q, %q) succeeded, wanted error", tt.path, tt.version)
    64  		}
    65  	}
    66  }
    67  
    68  var checkPathTests = []struct {
    69  	path     string
    70  	ok       bool
    71  	importOK bool
    72  	fileOK   bool
    73  }{
    74  	{"x.y/z", true, true, true},
    75  	{"x.y", true, true, true},
    76  
    77  	{"", false, false, false},
    78  	{"x.y/\xFFz", false, false, false},
    79  	{"/x.y/z", false, false, false},
    80  	{"x./z", false, false, false},
    81  	{".x/z", false, true, true},
    82  	{"-x/z", false, false, true},
    83  	{"x..y/z", true, true, true},
    84  	{"x.y/z/../../w", false, false, false},
    85  	{"x.y//z", false, false, false},
    86  	{"x.y/z//w", false, false, false},
    87  	{"x.y/z/", false, false, false},
    88  
    89  	{"x.y/z/v0", false, true, true},
    90  	{"x.y/z/v1", false, true, true},
    91  	{"x.y/z/v2", true, true, true},
    92  	{"x.y/z/v2.0", false, true, true},
    93  	{"X.y/z", false, true, true},
    94  
    95  	{"!x.y/z", false, false, true},
    96  	{"_x.y/z", false, true, true},
    97  	{"x.y!/z", false, false, true},
    98  	{"x.y\"/z", false, false, false},
    99  	{"x.y#/z", false, false, true},
   100  	{"x.y$/z", false, false, true},
   101  	{"x.y%/z", false, false, true},
   102  	{"x.y&/z", false, false, true},
   103  	{"x.y'/z", false, false, false},
   104  	{"x.y(/z", false, false, true},
   105  	{"x.y)/z", false, false, true},
   106  	{"x.y*/z", false, false, false},
   107  	{"x.y+/z", false, true, true},
   108  	{"x.y,/z", false, false, true},
   109  	{"x.y-/z", true, true, true},
   110  	{"x.y./zt", false, false, false},
   111  	{"x.y:/z", false, false, false},
   112  	{"x.y;/z", false, false, false},
   113  	{"x.y</z", false, false, false},
   114  	{"x.y=/z", false, false, true},
   115  	{"x.y>/z", false, false, false},
   116  	{"x.y?/z", false, false, false},
   117  	{"x.y@/z", false, false, true},
   118  	{"x.y[/z", false, false, true},
   119  	{"x.y\\/z", false, false, false},
   120  	{"x.y]/z", false, false, true},
   121  	{"x.y^/z", false, false, true},
   122  	{"x.y_/z", false, true, true},
   123  	{"x.y`/z", false, false, false},
   124  	{"x.y{/z", false, false, true},
   125  	{"x.y}/z", false, false, true},
   126  	{"x.y~/z", false, true, true},
   127  	{"x.y/z!", false, false, true},
   128  	{"x.y/z\"", false, false, false},
   129  	{"x.y/z#", false, false, true},
   130  	{"x.y/z$", false, false, true},
   131  	{"x.y/z%", false, false, true},
   132  	{"x.y/z&", false, false, true},
   133  	{"x.y/z'", false, false, false},
   134  	{"x.y/z(", false, false, true},
   135  	{"x.y/z)", false, false, true},
   136  	{"x.y/z*", false, false, false},
   137  	{"x.y/z++", false, true, true},
   138  	{"x.y/z,", false, false, true},
   139  	{"x.y/z-", true, true, true},
   140  	{"x.y/z.t", true, true, true},
   141  	{"x.y/z/t", true, true, true},
   142  	{"x.y/z:", false, false, false},
   143  	{"x.y/z;", false, false, false},
   144  	{"x.y/z<", false, false, false},
   145  	{"x.y/z=", false, false, true},
   146  	{"x.y/z>", false, false, false},
   147  	{"x.y/z?", false, false, false},
   148  	{"x.y/z@", false, false, true},
   149  	{"x.y/z[", false, false, true},
   150  	{"x.y/z\\", false, false, false},
   151  	{"x.y/z]", false, false, true},
   152  	{"x.y/z^", false, false, true},
   153  	{"x.y/z_", true, true, true},
   154  	{"x.y/z`", false, false, false},
   155  	{"x.y/z{", false, false, true},
   156  	{"x.y/z}", false, false, true},
   157  	{"x.y/z~", true, true, true},
   158  	{"x.y/x.foo", true, true, true},
   159  	{"x.y/aux.foo", false, false, false},
   160  	{"x.y/prn", false, false, false},
   161  	{"x.y/prn2", true, true, true},
   162  	{"x.y/com", true, true, true},
   163  	{"x.y/com1", false, false, false},
   164  	{"x.y/com1.txt", false, false, false},
   165  	{"x.y/calm1", true, true, true},
   166  	{"x.y/z~", true, true, true},
   167  	{"x.y/z~0", false, false, true},
   168  	{"x.y/z~09", false, false, true},
   169  	{"x.y/z09", true, true, true},
   170  	{"x.y/z09~", true, true, true},
   171  	{"x.y/z09~09z", true, true, true},
   172  	{"x.y/z09~09z~09", false, false, true},
   173  	{"github.com/!123/logrus", false, false, true},
   174  
   175  	// TODO: CL 41822 allowed Unicode letters in old "go get"
   176  	// without due consideration of the implications, and only on github.com (!).
   177  	// For now, we disallow non-ASCII characters in module mode,
   178  	// in both module paths and general import paths,
   179  	// until we can get the implications right.
   180  	// When we do, we'll enable them everywhere, not just for GitHub.
   181  	{"github.com/user/unicode/испытание", false, false, true},
   182  
   183  	{"../x", false, false, false},
   184  	{"./y", false, false, false},
   185  	{"x:y", false, false, false},
   186  	{`\temp\foo`, false, false, false},
   187  	{".gitignore", false, true, true},
   188  	{".github/ISSUE_TEMPLATE", false, true, true},
   189  	{"x☺y", false, false, false},
   190  }
   191  
   192  func TestCheckPath(t *testing.T) {
   193  	for _, tt := range checkPathTests {
   194  		err := CheckPath(tt.path)
   195  		if tt.ok && err != nil {
   196  			t.Errorf("CheckPath(%q) = %v, wanted nil error", tt.path, err)
   197  		} else if !tt.ok && err == nil {
   198  			t.Errorf("CheckPath(%q) succeeded, wanted error", tt.path)
   199  		}
   200  
   201  		err = CheckImportPath(tt.path)
   202  		if tt.importOK && err != nil {
   203  			t.Errorf("CheckImportPath(%q) = %v, wanted nil error", tt.path, err)
   204  		} else if !tt.importOK && err == nil {
   205  			t.Errorf("CheckImportPath(%q) succeeded, wanted error", tt.path)
   206  		}
   207  
   208  		err = CheckFilePath(tt.path)
   209  		if tt.fileOK && err != nil {
   210  			t.Errorf("CheckFilePath(%q) = %v, wanted nil error", tt.path, err)
   211  		} else if !tt.fileOK && err == nil {
   212  			t.Errorf("CheckFilePath(%q) succeeded, wanted error", tt.path)
   213  		}
   214  	}
   215  }
   216  
   217  var splitPathVersionTests = []struct {
   218  	pathPrefix string
   219  	version    string
   220  }{
   221  	{"x.y/z", ""},
   222  	{"x.y/z", "/v2"},
   223  	{"x.y/z", "/v3"},
   224  	{"x.y/v", ""},
   225  	{"gopkg.in/yaml", ".v0"},
   226  	{"gopkg.in/yaml", ".v1"},
   227  	{"gopkg.in/yaml", ".v2"},
   228  	{"gopkg.in/yaml", ".v3"},
   229  }
   230  
   231  func TestSplitPathVersion(t *testing.T) {
   232  	for _, tt := range splitPathVersionTests {
   233  		pathPrefix, version, ok := SplitPathVersion(tt.pathPrefix + tt.version)
   234  		if pathPrefix != tt.pathPrefix || version != tt.version || !ok {
   235  			t.Errorf("SplitPathVersion(%q) = %q, %q, %v, want %q, %q, true", tt.pathPrefix+tt.version, pathPrefix, version, ok, tt.pathPrefix, tt.version)
   236  		}
   237  	}
   238  
   239  	for _, tt := range checkPathTests {
   240  		pathPrefix, version, ok := SplitPathVersion(tt.path)
   241  		if pathPrefix+version != tt.path {
   242  			t.Errorf("SplitPathVersion(%q) = %q, %q, %v, doesn't add to input", tt.path, pathPrefix, version, ok)
   243  		}
   244  	}
   245  }
   246  
   247  var escapeTests = []struct {
   248  	path string
   249  	esc  string // empty means same as path
   250  }{
   251  	{path: "ascii.com/abcdefghijklmnopqrstuvwxyz.-/~_0123456789"},
   252  	{path: "github.com/GoogleCloudPlatform/omega", esc: "github.com/!google!cloud!platform/omega"},
   253  }
   254  
   255  func TestEscapePath(t *testing.T) {
   256  	// Check invalid paths.
   257  	for _, tt := range checkPathTests {
   258  		if !tt.ok {
   259  			_, err := EscapePath(tt.path)
   260  			if err == nil {
   261  				t.Errorf("EscapePath(%q): succeeded, want error (invalid path)", tt.path)
   262  			}
   263  		}
   264  	}
   265  
   266  	// Check encodings.
   267  	for _, tt := range escapeTests {
   268  		esc, err := EscapePath(tt.path)
   269  		if err != nil {
   270  			t.Errorf("EscapePath(%q): unexpected error: %v", tt.path, err)
   271  			continue
   272  		}
   273  		want := tt.esc
   274  		if want == "" {
   275  			want = tt.path
   276  		}
   277  		if esc != want {
   278  			t.Errorf("EscapePath(%q) = %q, want %q", tt.path, esc, want)
   279  		}
   280  	}
   281  }
   282  
   283  var badUnescape = []string{
   284  	"github.com/GoogleCloudPlatform/omega",
   285  	"github.com/!google!cloud!platform!/omega",
   286  	"github.com/!0google!cloud!platform/omega",
   287  	"github.com/!_google!cloud!platform/omega",
   288  	"github.com/!!google!cloud!platform/omega",
   289  	"",
   290  }
   291  
   292  func TestUnescapePath(t *testing.T) {
   293  	// Check invalid decodings.
   294  	for _, bad := range badUnescape {
   295  		_, err := UnescapePath(bad)
   296  		if err == nil {
   297  			t.Errorf("UnescapePath(%q): succeeded, want error (invalid decoding)", bad)
   298  		}
   299  	}
   300  
   301  	// Check invalid paths (or maybe decodings).
   302  	for _, tt := range checkPathTests {
   303  		if !tt.ok {
   304  			path, err := UnescapePath(tt.path)
   305  			if err == nil {
   306  				t.Errorf("UnescapePath(%q) = %q, want error (invalid path)", tt.path, path)
   307  			}
   308  		}
   309  	}
   310  
   311  	// Check encodings.
   312  	for _, tt := range escapeTests {
   313  		esc := tt.esc
   314  		if esc == "" {
   315  			esc = tt.path
   316  		}
   317  		path, err := UnescapePath(esc)
   318  		if err != nil {
   319  			t.Errorf("UnescapePath(%q): unexpected error: %v", esc, err)
   320  			continue
   321  		}
   322  		if path != tt.path {
   323  			t.Errorf("UnescapePath(%q) = %q, want %q", esc, path, tt.path)
   324  		}
   325  	}
   326  }
   327  
   328  func TestMatchPathMajor(t *testing.T) {
   329  	for _, test := range []struct {
   330  		v, pathMajor string
   331  		want         bool
   332  	}{
   333  		{"v0.0.0", "", true},
   334  		{"v0.0.0", "/v2", false},
   335  		{"v0.0.0", ".v0", true},
   336  		{"v0.0.0-20190510104115-cbcb75029529", ".v1", true},
   337  		{"v1.0.0", "/v2", false},
   338  		{"v1.0.0", ".v1", true},
   339  		{"v1.0.0", ".v1-unstable", true},
   340  		{"v2.0.0+incompatible", "", true},
   341  		{"v2.0.0", "", false},
   342  		{"v2.0.0", "/v2", true},
   343  		{"v2.0.0", ".v2", true},
   344  	} {
   345  		if got := MatchPathMajor(test.v, test.pathMajor); got != test.want {
   346  			t.Errorf("MatchPathMajor(%q, %q) = %v, want %v", test.v, test.pathMajor, got, test.want)
   347  		}
   348  	}
   349  }
   350  
   351  func TestMatchPrefixPatterns(t *testing.T) {
   352  	for _, test := range []struct {
   353  		globs, target string
   354  		want          bool
   355  	}{
   356  		{"", "rsc.io/quote", false},
   357  		{"/", "rsc.io/quote", false},
   358  		{"*/quote", "rsc.io/quote", true},
   359  		{"*/quo", "rsc.io/quote", false},
   360  		{"*/quo??", "rsc.io/quote", true},
   361  		{"*/quo*", "rsc.io/quote", true},
   362  		{"*quo*", "rsc.io/quote", false},
   363  		{"rsc.io", "rsc.io/quote", true},
   364  		{"*.io", "rsc.io/quote", true},
   365  		{"rsc.io/", "rsc.io/quote", true},
   366  		{"rsc", "rsc.io/quote", false},
   367  		{"rsc*", "rsc.io/quote", true},
   368  
   369  		{"rsc.io", "rsc.io/quote/v3", true},
   370  		{"*/quote", "rsc.io/quote/v3", true},
   371  		{"*/quote/", "rsc.io/quote/v3", true},
   372  		{"*/quote/*", "rsc.io/quote/v3", true},
   373  		{"*/quote/*/", "rsc.io/quote/v3", true},
   374  		{"*/v3", "rsc.io/quote/v3", false},
   375  		{"*/*/v3", "rsc.io/quote/v3", true},
   376  		{"*/*/*", "rsc.io/quote/v3", true},
   377  		{"*/*/*/", "rsc.io/quote/v3", true},
   378  		{"*/*/*", "rsc.io/quote", false},
   379  		{"*/*/*/", "rsc.io/quote", false},
   380  
   381  		{"*/*/*,,", "rsc.io/quote", false},
   382  		{"*/*/*,,*/quote", "rsc.io/quote", true},
   383  		{",,*/quote", "rsc.io/quote", true},
   384  	} {
   385  		if got := MatchPrefixPatterns(test.globs, test.target); got != test.want {
   386  			t.Errorf("MatchPrefixPatterns(%q, %q) = %t, want %t", test.globs, test.target, got, test.want)
   387  		}
   388  	}
   389  }
   390  

View as plain text