github.com/gagliardetto/golang-go@v0.0.0-20201020153340-53909ea70814/cmd/go/not-internal/mvs/mvs_test.go (about) 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 mvs 6 7 import ( 8 "fmt" 9 "reflect" 10 "strings" 11 "testing" 12 13 "golang.org/x/mod/module" 14 ) 15 16 var tests = ` 17 # Scenario from blog. 18 name: blog 19 A: B1 C2 20 B1: D3 21 C1: D2 22 C2: D4 23 C3: D5 24 C4: G1 25 D2: E1 26 D3: E2 27 D4: E2 F1 28 D5: E2 29 G1: C4 30 A2: B1 C4 D4 31 build A: A B1 C2 D4 E2 F1 32 upgrade* A: A B1 C4 D5 E2 F1 G1 33 upgrade A C4: A B1 C4 D4 E2 F1 G1 34 downgrade A2 D2: A2 C4 D2 35 36 name: trim 37 A: B1 C2 38 B1: D3 39 C2: B2 40 B2: 41 build A: A B2 C2 D3 42 43 # Cross-dependency between D and E. 44 # No matter how it arises, should get result of merging all build lists via max, 45 # which leads to including both D2 and E2. 46 47 name: cross1 48 A: B C 49 B: D1 50 C: D2 51 D1: E2 52 D2: E1 53 build A: A B C D2 E2 54 55 name: cross1V 56 A: B2 C D2 E1 57 B1: 58 B2: D1 59 C: D2 60 D1: E2 61 D2: E1 62 build A: A B2 C D2 E2 63 64 name: cross1U 65 A: B1 C 66 B1: 67 B2: D1 68 C: D2 69 D1: E2 70 D2: E1 71 build A: A B1 C D2 E1 72 upgrade A B2: A B2 C D2 E2 73 74 name: cross1R 75 A: B C 76 B: D2 77 C: D1 78 D1: E2 79 D2: E1 80 build A: A B C D2 E2 81 82 name: cross1X 83 A: B C 84 B: D1 E2 85 C: D2 86 D1: E2 87 D2: E1 88 build A: A B C D2 E2 89 90 name: cross2 91 A: B D2 92 B: D1 93 D1: E2 94 D2: E1 95 build A: A B D2 E2 96 97 name: cross2X 98 A: B D2 99 B: D1 E2 100 C: D2 101 D1: E2 102 D2: E1 103 build A: A B D2 E2 104 105 name: cross3 106 A: B D2 E1 107 B: D1 108 D1: E2 109 D2: E1 110 build A: A B D2 E2 111 112 name: cross3X 113 A: B D2 E1 114 B: D1 E2 115 D1: E2 116 D2: E1 117 build A: A B D2 E2 118 119 # Should not get E2 here, because B has been updated 120 # not to depend on D1 anymore. 121 name: cross4 122 A1: B1 D2 123 A2: B2 D2 124 B1: D1 125 B2: D2 126 D1: E2 127 D2: E1 128 build A1: A1 B1 D2 E2 129 build A2: A2 B2 D2 E1 130 131 # But the upgrade from A1 preserves the E2 dep explicitly. 132 upgrade A1 B2: A1 B2 D2 E2 133 upgradereq A1 B2: B2 E2 134 135 name: cross5 136 A: D1 137 D1: E2 138 D2: E1 139 build A: A D1 E2 140 upgrade* A: A D2 E2 141 upgrade A D2: A D2 E2 142 upgradereq A D2: D2 E2 143 144 name: cross6 145 A: D2 146 D1: E2 147 D2: E1 148 build A: A D2 E1 149 upgrade* A: A D2 E2 150 upgrade A E2: A D2 E2 151 152 name: cross7 153 A: B C 154 B: D1 155 C: E1 156 D1: E2 157 E1: D2 158 build A: A B C D2 E2 159 160 # golang.org/issue/31248: 161 # Even though we select X2, the requirement on I1 162 # via X1 should be preserved. 163 name: cross8 164 M: A1 B1 165 A1: X1 166 B1: X2 167 X1: I1 168 X2: 169 build M: M A1 B1 I1 X2 170 171 # Upgrade from B1 to B2 should not drop the transitive dep on D. 172 name: drop 173 A: B1 C1 174 B1: D1 175 B2: 176 C2: 177 D2: 178 build A: A B1 C1 D1 179 upgrade* A: A B2 C2 D2 180 181 name: simplify 182 A: B1 C1 183 B1: C2 184 C1: D1 185 C2: 186 build A: A B1 C2 D1 187 188 name: up1 189 A: B1 C1 190 B1: 191 B2: 192 B3: 193 B4: 194 B5.hidden: 195 C2: 196 C3: 197 build A: A B1 C1 198 upgrade* A: A B4 C3 199 200 name: up2 201 A: B5.hidden C1 202 B1: 203 B2: 204 B3: 205 B4: 206 B5.hidden: 207 C2: 208 C3: 209 build A: A B5.hidden C1 210 upgrade* A: A B5.hidden C3 211 212 name: down1 213 A: B2 214 B1: C1 215 B2: C2 216 build A: A B2 C2 217 downgrade A C1: A B1 218 219 name: down2 220 A: B2 E2 221 B1: 222 B2: C2 F2 223 C1: 224 D1: 225 C2: D2 E2 226 D2: B2 227 E2: D2 228 E1: 229 F1: 230 downgrade A F1: A B1 E1 231 232 name: down3 233 A: 234 235 # golang.org/issue/25542. 236 name: noprev1 237 A: B4 C2 238 B2.hidden: 239 C2: 240 downgrade A B2.hidden: A B2.hidden C2 241 242 name: noprev2 243 A: B4 C2 244 B2.hidden: 245 B1: 246 C2: 247 downgrade A B2.hidden: A B2.hidden C2 248 249 name: noprev3 250 A: B4 C2 251 B3: 252 B2.hidden: 253 C2: 254 downgrade A B2.hidden: A B2.hidden C2 255 256 # Cycles involving the target. 257 258 # The target must be the newest version of itself. 259 name: cycle1 260 A: B1 261 B1: A1 262 B2: A2 263 B3: A3 264 build A: A B1 265 upgrade A B2: A B2 266 upgrade* A: A B3 267 268 # golang.org/issue/29773: 269 # Requirements of older versions of the target 270 # must be carried over. 271 name: cycle2 272 A: B1 273 A1: C1 274 A2: D1 275 B1: A1 276 B2: A2 277 C1: A2 278 C2: 279 D2: 280 build A: A B1 C1 D1 281 upgrade* A: A B2 C2 D2 282 283 # Cycles with multiple possible solutions. 284 # (golang.org/issue/34086) 285 name: cycle3 286 M: A1 C2 287 A1: B1 288 B1: C1 289 B2: C2 290 C1: 291 C2: B2 292 build M: M A1 B2 C2 293 req M: A1 B2 294 req M A: A1 B2 295 req M C: A1 C2 296 297 # Requirement minimization. 298 299 name: req1 300 A: B1 C1 D1 E1 F1 301 B1: C1 E1 F1 302 req A: B1 D1 303 req A C: B1 C1 D1 304 305 name: req2 306 A: G1 H1 307 G1: H1 308 H1: G1 309 req A: G1 310 req A G: G1 311 req A H: H1 312 313 name: req3 314 M: A1 B1 315 A1: X1 316 B1: X2 317 X1: I1 318 X2: 319 req M: A1 B1 320 ` 321 322 func Test(t *testing.T) { 323 var ( 324 name string 325 reqs reqsMap 326 fns []func(*testing.T) 327 ) 328 flush := func() { 329 if name != "" { 330 t.Run(name, func(t *testing.T) { 331 for _, fn := range fns { 332 fn(t) 333 } 334 }) 335 } 336 } 337 m := func(s string) module.Version { 338 return module.Version{Path: s[:1], Version: s[1:]} 339 } 340 ms := func(list []string) []module.Version { 341 var mlist []module.Version 342 for _, s := range list { 343 mlist = append(mlist, m(s)) 344 } 345 return mlist 346 } 347 checkList := func(t *testing.T, desc string, list []module.Version, err error, val string) { 348 if err != nil { 349 t.Fatalf("%s: %v", desc, err) 350 } 351 vs := ms(strings.Fields(val)) 352 if !reflect.DeepEqual(list, vs) { 353 t.Errorf("%s = %v, want %v", desc, list, vs) 354 } 355 } 356 357 for _, line := range strings.Split(tests, "\n") { 358 line = strings.TrimSpace(line) 359 if strings.HasPrefix(line, "#") || line == "" { 360 continue 361 } 362 i := strings.Index(line, ":") 363 if i < 0 { 364 t.Fatalf("missing colon: %q", line) 365 } 366 key := strings.TrimSpace(line[:i]) 367 val := strings.TrimSpace(line[i+1:]) 368 if key == "" { 369 t.Fatalf("missing key: %q", line) 370 } 371 kf := strings.Fields(key) 372 switch kf[0] { 373 case "name": 374 if len(kf) != 1 { 375 t.Fatalf("name takes no arguments: %q", line) 376 } 377 flush() 378 reqs = make(reqsMap) 379 fns = nil 380 name = val 381 continue 382 case "build": 383 if len(kf) != 2 { 384 t.Fatalf("build takes one argument: %q", line) 385 } 386 fns = append(fns, func(t *testing.T) { 387 list, err := BuildList(m(kf[1]), reqs) 388 checkList(t, key, list, err, val) 389 }) 390 continue 391 case "upgrade*": 392 if len(kf) != 2 { 393 t.Fatalf("upgrade* takes one argument: %q", line) 394 } 395 fns = append(fns, func(t *testing.T) { 396 list, err := UpgradeAll(m(kf[1]), reqs) 397 checkList(t, key, list, err, val) 398 }) 399 continue 400 case "upgradereq": 401 if len(kf) < 2 { 402 t.Fatalf("upgrade takes at least one argument: %q", line) 403 } 404 fns = append(fns, func(t *testing.T) { 405 list, err := Upgrade(m(kf[1]), reqs, ms(kf[2:])...) 406 if err == nil { 407 // Copy the reqs map, but substitute the upgraded requirements in 408 // place of the target's original requirements. 409 upReqs := make(reqsMap, len(reqs)) 410 for m, r := range reqs { 411 upReqs[m] = r 412 } 413 upReqs[m(kf[1])] = list 414 415 list, err = Req(m(kf[1]), nil, upReqs) 416 } 417 checkList(t, key, list, err, val) 418 }) 419 continue 420 case "upgrade": 421 if len(kf) < 2 { 422 t.Fatalf("upgrade takes at least one argument: %q", line) 423 } 424 fns = append(fns, func(t *testing.T) { 425 list, err := Upgrade(m(kf[1]), reqs, ms(kf[2:])...) 426 checkList(t, key, list, err, val) 427 }) 428 continue 429 case "downgrade": 430 if len(kf) < 2 { 431 t.Fatalf("downgrade takes at least one argument: %q", line) 432 } 433 fns = append(fns, func(t *testing.T) { 434 list, err := Downgrade(m(kf[1]), reqs, ms(kf[1:])...) 435 checkList(t, key, list, err, val) 436 }) 437 continue 438 case "req": 439 if len(kf) < 2 { 440 t.Fatalf("req takes at least one argument: %q", line) 441 } 442 fns = append(fns, func(t *testing.T) { 443 list, err := Req(m(kf[1]), kf[2:], reqs) 444 checkList(t, key, list, err, val) 445 }) 446 continue 447 } 448 if len(kf) == 1 && 'A' <= key[0] && key[0] <= 'Z' { 449 var rs []module.Version 450 for _, f := range strings.Fields(val) { 451 r := m(f) 452 if reqs[r] == nil { 453 reqs[r] = []module.Version{} 454 } 455 rs = append(rs, r) 456 } 457 reqs[m(key)] = rs 458 continue 459 } 460 t.Fatalf("bad line: %q", line) 461 } 462 flush() 463 } 464 465 type reqsMap map[module.Version][]module.Version 466 467 func (r reqsMap) Max(v1, v2 string) string { 468 if v1 == "none" || v2 == "" { 469 return v2 470 } 471 if v2 == "none" || v1 == "" { 472 return v1 473 } 474 if v1 < v2 { 475 return v2 476 } 477 return v1 478 } 479 480 func (r reqsMap) Upgrade(m module.Version) (module.Version, error) { 481 var u module.Version 482 for k := range r { 483 if k.Path == m.Path && u.Version < k.Version && !strings.HasSuffix(k.Version, ".hidden") { 484 u = k 485 } 486 } 487 if u.Path == "" { 488 return module.Version{}, fmt.Errorf("missing module: %v", module.Version{Path: m.Path}) 489 } 490 return u, nil 491 } 492 493 func (r reqsMap) Previous(m module.Version) (module.Version, error) { 494 var p module.Version 495 for k := range r { 496 if k.Path == m.Path && p.Version < k.Version && k.Version < m.Version && !strings.HasSuffix(k.Version, ".hidden") { 497 p = k 498 } 499 } 500 if p.Path == "" { 501 return module.Version{Path: m.Path, Version: "none"}, nil 502 } 503 return p, nil 504 } 505 506 func (r reqsMap) Required(m module.Version) ([]module.Version, error) { 507 rr, ok := r[m] 508 if !ok { 509 return nil, fmt.Errorf("missing module: %v", m) 510 } 511 return rr, nil 512 }