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 5package module 6 7import "testing" 8 9var 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 57func 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 68var 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, false, true}, 82 {"-x/z", false, true, true}, 83 {"x..y/z", false, false, false}, 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+", true, 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 {"github.com/!123/logrus", false, false, true}, 167 168 // TODO: CL 41822 allowed Unicode letters in old "go get" 169 // without due consideration of the implications, and only on github.com (!). 170 // For now, we disallow non-ASCII characters in module mode, 171 // in both module paths and general import paths, 172 // until we can get the implications right. 173 // When we do, we'll enable them everywhere, not just for GitHub. 174 {"github.com/user/unicode/испытание", false, false, true}, 175 176 {"../x", false, false, false}, 177 {"./y", false, false, false}, 178 {"x:y", false, false, false}, 179 {`\temp\foo`, false, false, false}, 180 {".gitignore", false, false, true}, 181 {".github/ISSUE_TEMPLATE", false, false, true}, 182 {"x☺y", false, false, false}, 183} 184 185func TestCheckPath(t *testing.T) { 186 for _, tt := range checkPathTests { 187 err := CheckPath(tt.path) 188 if tt.ok && err != nil { 189 t.Errorf("CheckPath(%q) = %v, wanted nil error", tt.path, err) 190 } else if !tt.ok && err == nil { 191 t.Errorf("CheckPath(%q) succeeded, wanted error", tt.path) 192 } 193 194 err = CheckImportPath(tt.path) 195 if tt.importOK && err != nil { 196 t.Errorf("CheckImportPath(%q) = %v, wanted nil error", tt.path, err) 197 } else if !tt.importOK && err == nil { 198 t.Errorf("CheckImportPath(%q) succeeded, wanted error", tt.path) 199 } 200 201 err = CheckFilePath(tt.path) 202 if tt.fileOK && err != nil { 203 t.Errorf("CheckFilePath(%q) = %v, wanted nil error", tt.path, err) 204 } else if !tt.fileOK && err == nil { 205 t.Errorf("CheckFilePath(%q) succeeded, wanted error", tt.path) 206 } 207 } 208} 209 210var splitPathVersionTests = []struct { 211 pathPrefix string 212 version string 213}{ 214 {"x.y/z", ""}, 215 {"x.y/z", "/v2"}, 216 {"x.y/z", "/v3"}, 217 {"gopkg.in/yaml", ".v0"}, 218 {"gopkg.in/yaml", ".v1"}, 219 {"gopkg.in/yaml", ".v2"}, 220 {"gopkg.in/yaml", ".v3"}, 221} 222 223func TestSplitPathVersion(t *testing.T) { 224 for _, tt := range splitPathVersionTests { 225 pathPrefix, version, ok := SplitPathVersion(tt.pathPrefix + tt.version) 226 if pathPrefix != tt.pathPrefix || version != tt.version || !ok { 227 t.Errorf("SplitPathVersion(%q) = %q, %q, %v, want %q, %q, true", tt.pathPrefix+tt.version, pathPrefix, version, ok, tt.pathPrefix, tt.version) 228 } 229 } 230 231 for _, tt := range checkPathTests { 232 pathPrefix, version, ok := SplitPathVersion(tt.path) 233 if pathPrefix+version != tt.path { 234 t.Errorf("SplitPathVersion(%q) = %q, %q, %v, doesn't add to input", tt.path, pathPrefix, version, ok) 235 } 236 } 237} 238 239var encodeTests = []struct { 240 path string 241 enc string // empty means same as path 242}{ 243 {path: "ascii.com/abcdefghijklmnopqrstuvwxyz.-+/~_0123456789"}, 244 {path: "github.com/GoogleCloudPlatform/omega", enc: "github.com/!google!cloud!platform/omega"}, 245} 246 247func TestEncodePath(t *testing.T) { 248 // Check invalid paths. 249 for _, tt := range checkPathTests { 250 if !tt.ok { 251 _, err := EncodePath(tt.path) 252 if err == nil { 253 t.Errorf("EncodePath(%q): succeeded, want error (invalid path)", tt.path) 254 } 255 } 256 } 257 258 // Check encodings. 259 for _, tt := range encodeTests { 260 enc, err := EncodePath(tt.path) 261 if err != nil { 262 t.Errorf("EncodePath(%q): unexpected error: %v", tt.path, err) 263 continue 264 } 265 want := tt.enc 266 if want == "" { 267 want = tt.path 268 } 269 if enc != want { 270 t.Errorf("EncodePath(%q) = %q, want %q", tt.path, enc, want) 271 } 272 } 273} 274 275var badDecode = []string{ 276 "github.com/GoogleCloudPlatform/omega", 277 "github.com/!google!cloud!platform!/omega", 278 "github.com/!0google!cloud!platform/omega", 279 "github.com/!_google!cloud!platform/omega", 280 "github.com/!!google!cloud!platform/omega", 281 "", 282} 283 284func TestDecodePath(t *testing.T) { 285 // Check invalid decodings. 286 for _, bad := range badDecode { 287 _, err := DecodePath(bad) 288 if err == nil { 289 t.Errorf("DecodePath(%q): succeeded, want error (invalid decoding)", bad) 290 } 291 } 292 293 // Check invalid paths (or maybe decodings). 294 for _, tt := range checkPathTests { 295 if !tt.ok { 296 path, err := DecodePath(tt.path) 297 if err == nil { 298 t.Errorf("DecodePath(%q) = %q, want error (invalid path)", tt.path, path) 299 } 300 } 301 } 302 303 // Check encodings. 304 for _, tt := range encodeTests { 305 enc := tt.enc 306 if enc == "" { 307 enc = tt.path 308 } 309 path, err := DecodePath(enc) 310 if err != nil { 311 t.Errorf("DecodePath(%q): unexpected error: %v", enc, err) 312 continue 313 } 314 if path != tt.path { 315 t.Errorf("DecodePath(%q) = %q, want %q", enc, path, tt.path) 316 } 317 } 318} 319