1package constraints 2 3import ( 4 "testing" 5 6 "github.com/davecgh/go-spew/spew" 7 "github.com/go-test/deep" 8) 9 10func TestParse(t *testing.T) { 11 tests := []struct { 12 Input string 13 Want UnionSpec 14 WantErr string 15 }{ 16 { 17 "", 18 nil, 19 "empty specification", 20 }, 21 { 22 "1", 23 UnionSpec{ 24 IntersectionSpec{ 25 SelectionSpec{ 26 Operator: OpEqual, 27 Boundary: VersionSpec{ 28 Major: NumConstraint{Num: 1}, 29 Minor: NumConstraint{Num: 0}, 30 Patch: NumConstraint{Num: 0}, 31 }, 32 }, 33 }, 34 }, 35 "", 36 }, 37 { 38 "1.1", 39 UnionSpec{ 40 IntersectionSpec{ 41 SelectionSpec{ 42 Operator: OpEqual, 43 Boundary: VersionSpec{ 44 Major: NumConstraint{Num: 1}, 45 Minor: NumConstraint{Num: 1}, 46 Patch: NumConstraint{Num: 0}, 47 }, 48 }, 49 }, 50 }, 51 "", 52 }, 53 { 54 "1.1.1", 55 UnionSpec{ 56 IntersectionSpec{ 57 SelectionSpec{ 58 Operator: OpEqual, 59 Boundary: VersionSpec{ 60 Major: NumConstraint{Num: 1}, 61 Minor: NumConstraint{Num: 1}, 62 Patch: NumConstraint{Num: 1}, 63 }, 64 }, 65 }, 66 }, 67 "", 68 }, 69 { 70 "1.0.0.0", 71 nil, 72 "too many numbered portions; only three are allowed (major, minor, patch)", 73 }, 74 { 75 "v1.0.0", 76 nil, 77 `a "v" prefix should not be used when specifying versions`, 78 }, 79 { 80 "1.0.0-beta2", 81 UnionSpec{ 82 IntersectionSpec{ 83 SelectionSpec{ 84 Operator: OpEqual, 85 Boundary: VersionSpec{ 86 Major: NumConstraint{Num: 1}, 87 Minor: NumConstraint{Num: 0}, 88 Patch: NumConstraint{Num: 0}, 89 Prerelease: "beta2", 90 }, 91 }, 92 }, 93 }, 94 "", 95 }, 96 { 97 "1.0-beta2", 98 UnionSpec{ 99 IntersectionSpec{ 100 SelectionSpec{ 101 Operator: OpEqual, 102 Boundary: VersionSpec{ 103 Major: NumConstraint{Num: 1}, 104 Minor: NumConstraint{Num: 0}, 105 Patch: NumConstraint{Num: 0}, // implied by the prerelease tag to ensure constraint consistency 106 Prerelease: "beta2", 107 }, 108 }, 109 }, 110 }, 111 "", 112 }, 113 { 114 "1.0.0-beta.2", 115 UnionSpec{ 116 IntersectionSpec{ 117 SelectionSpec{ 118 Operator: OpEqual, 119 Boundary: VersionSpec{ 120 Major: NumConstraint{Num: 1}, 121 Minor: NumConstraint{Num: 0}, 122 Patch: NumConstraint{Num: 0}, 123 Prerelease: "beta.2", 124 }, 125 }, 126 }, 127 }, 128 "", 129 }, 130 { 131 "1.0.0+foo", 132 UnionSpec{ 133 IntersectionSpec{ 134 SelectionSpec{ 135 Operator: OpEqual, 136 Boundary: VersionSpec{ 137 Major: NumConstraint{Num: 1}, 138 Minor: NumConstraint{Num: 0}, 139 Patch: NumConstraint{Num: 0}, 140 Metadata: "foo", 141 }, 142 }, 143 }, 144 }, 145 "", 146 }, 147 { 148 "1.0.0+foo.bar", 149 UnionSpec{ 150 IntersectionSpec{ 151 SelectionSpec{ 152 Operator: OpEqual, 153 Boundary: VersionSpec{ 154 Major: NumConstraint{Num: 1}, 155 Minor: NumConstraint{Num: 0}, 156 Patch: NumConstraint{Num: 0}, 157 Metadata: "foo.bar", 158 }, 159 }, 160 }, 161 }, 162 "", 163 }, 164 { 165 "1.0.0-beta1+foo.bar", 166 UnionSpec{ 167 IntersectionSpec{ 168 SelectionSpec{ 169 Operator: OpEqual, 170 Boundary: VersionSpec{ 171 Major: NumConstraint{Num: 1}, 172 Minor: NumConstraint{Num: 0}, 173 Patch: NumConstraint{Num: 0}, 174 Prerelease: "beta1", 175 Metadata: "foo.bar", 176 }, 177 }, 178 }, 179 }, 180 "", 181 }, 182 { 183 ">1.1.1", 184 UnionSpec{ 185 IntersectionSpec{ 186 SelectionSpec{ 187 Operator: OpGreaterThan, 188 Boundary: VersionSpec{ 189 Major: NumConstraint{Num: 1}, 190 Minor: NumConstraint{Num: 1}, 191 Patch: NumConstraint{Num: 1}, 192 }, 193 }, 194 }, 195 }, 196 ``, 197 }, 198 { 199 ">2.*.*", 200 UnionSpec{ 201 IntersectionSpec{ 202 SelectionSpec{ 203 Operator: OpGreaterThanOrEqual, 204 Boundary: VersionSpec{ 205 Major: NumConstraint{Num: 3}, 206 Minor: NumConstraint{Num: 0}, 207 Patch: NumConstraint{Num: 0}, 208 }, 209 }, 210 }, 211 }, 212 ``, 213 }, 214 { 215 ">=1.1.1", 216 UnionSpec{ 217 IntersectionSpec{ 218 SelectionSpec{ 219 Operator: OpGreaterThanOrEqual, 220 Boundary: VersionSpec{ 221 Major: NumConstraint{Num: 1}, 222 Minor: NumConstraint{Num: 1}, 223 Patch: NumConstraint{Num: 1}, 224 }, 225 }, 226 }, 227 }, 228 ``, 229 }, 230 { 231 ">=2.*.*", 232 UnionSpec{ 233 IntersectionSpec{ 234 SelectionSpec{ 235 Operator: OpGreaterThanOrEqual, 236 Boundary: VersionSpec{ 237 Major: NumConstraint{Num: 2}, 238 Minor: NumConstraint{Num: 0}, 239 Patch: NumConstraint{Num: 0}, 240 }, 241 }, 242 }, 243 }, 244 ``, 245 }, 246 { 247 "=>1.1.1", 248 nil, 249 `invalid constraint operator "=>"; did you mean ">="?`, 250 }, 251 { 252 "<1.1.1", 253 UnionSpec{ 254 IntersectionSpec{ 255 SelectionSpec{ 256 Operator: OpLessThan, 257 Boundary: VersionSpec{ 258 Major: NumConstraint{Num: 1}, 259 Minor: NumConstraint{Num: 1}, 260 Patch: NumConstraint{Num: 1}, 261 }, 262 }, 263 }, 264 }, 265 ``, 266 }, 267 { 268 "<2.*.*", 269 UnionSpec{ 270 IntersectionSpec{ 271 SelectionSpec{ 272 Operator: OpLessThan, 273 Boundary: VersionSpec{ 274 Major: NumConstraint{Num: 2}, 275 Minor: NumConstraint{Num: 0}, 276 Patch: NumConstraint{Num: 0}, 277 }, 278 }, 279 }, 280 }, 281 ``, 282 }, 283 { 284 "<=1.1.1", 285 UnionSpec{ 286 IntersectionSpec{ 287 SelectionSpec{ 288 Operator: OpLessThanOrEqual, 289 Boundary: VersionSpec{ 290 Major: NumConstraint{Num: 1}, 291 Minor: NumConstraint{Num: 1}, 292 Patch: NumConstraint{Num: 1}, 293 }, 294 }, 295 }, 296 }, 297 ``, 298 }, 299 { 300 "<=2.*.*", 301 UnionSpec{ 302 IntersectionSpec{ 303 SelectionSpec{ 304 Operator: OpLessThan, 305 Boundary: VersionSpec{ 306 Major: NumConstraint{Num: 3}, 307 Minor: NumConstraint{Num: 0}, 308 Patch: NumConstraint{Num: 0}, 309 }, 310 }, 311 }, 312 }, 313 ``, 314 }, 315 { 316 "=<1.1.1", 317 nil, 318 `invalid constraint operator "=<"; did you mean "<="?`, 319 }, 320 { 321 "~1.1.1", 322 UnionSpec{ 323 IntersectionSpec{ 324 SelectionSpec{ 325 Operator: OpGreaterThanOrEqualPatchOnly, 326 Boundary: VersionSpec{ 327 Major: NumConstraint{Num: 1}, 328 Minor: NumConstraint{Num: 1}, 329 Patch: NumConstraint{Num: 1}, 330 }, 331 }, 332 }, 333 }, 334 ``, 335 }, 336 { 337 "~1.1", 338 UnionSpec{ 339 IntersectionSpec{ 340 SelectionSpec{ 341 Operator: OpGreaterThanOrEqualPatchOnly, 342 Boundary: VersionSpec{ 343 Major: NumConstraint{Num: 1}, 344 Minor: NumConstraint{Num: 1}, 345 Patch: NumConstraint{Num: 0}, 346 }, 347 }, 348 }, 349 }, 350 ``, 351 }, 352 { 353 "~1", 354 UnionSpec{ 355 IntersectionSpec{ 356 SelectionSpec{ 357 Operator: OpGreaterThanOrEqualMinorOnly, 358 Boundary: VersionSpec{ 359 Major: NumConstraint{Num: 1}, 360 Minor: NumConstraint{Num: 0}, 361 Patch: NumConstraint{Num: 0}, 362 }, 363 }, 364 }, 365 }, 366 ``, 367 }, 368 { 369 "^1.1.1", 370 UnionSpec{ 371 IntersectionSpec{ 372 SelectionSpec{ 373 Operator: OpGreaterThanOrEqualMinorOnly, 374 Boundary: VersionSpec{ 375 Major: NumConstraint{Num: 1}, 376 Minor: NumConstraint{Num: 1}, 377 Patch: NumConstraint{Num: 1}, 378 }, 379 }, 380 }, 381 }, 382 ``, 383 }, 384 { 385 "^1.1", 386 UnionSpec{ 387 IntersectionSpec{ 388 SelectionSpec{ 389 Operator: OpGreaterThanOrEqualMinorOnly, 390 Boundary: VersionSpec{ 391 Major: NumConstraint{Num: 1}, 392 Minor: NumConstraint{Num: 1}, 393 Patch: NumConstraint{Num: 0}, 394 }, 395 }, 396 }, 397 }, 398 ``, 399 }, 400 { 401 "^0.1", 402 UnionSpec{ 403 IntersectionSpec{ 404 SelectionSpec{ 405 Operator: OpGreaterThanOrEqualPatchOnly, 406 Boundary: VersionSpec{ 407 Major: NumConstraint{Num: 0}, 408 Minor: NumConstraint{Num: 1}, 409 Patch: NumConstraint{Num: 0}, 410 }, 411 }, 412 }, 413 }, 414 ``, 415 }, 416 { 417 "^1", 418 UnionSpec{ 419 IntersectionSpec{ 420 SelectionSpec{ 421 Operator: OpGreaterThanOrEqualMinorOnly, 422 Boundary: VersionSpec{ 423 Major: NumConstraint{Num: 1}, 424 Minor: NumConstraint{Num: 0}, 425 Patch: NumConstraint{Num: 0}, 426 }, 427 }, 428 }, 429 }, 430 ``, 431 }, 432 { 433 "=1.1.1", 434 UnionSpec{ 435 IntersectionSpec{ 436 SelectionSpec{ 437 Operator: OpEqual, 438 Boundary: VersionSpec{ 439 Major: NumConstraint{Num: 1}, 440 Minor: NumConstraint{Num: 1}, 441 Patch: NumConstraint{Num: 1}, 442 }, 443 }, 444 }, 445 }, 446 ``, 447 }, 448 { 449 "!1.1.1", 450 UnionSpec{ 451 IntersectionSpec{ 452 SelectionSpec{ 453 Operator: OpNotEqual, 454 Boundary: VersionSpec{ 455 Major: NumConstraint{Num: 1}, 456 Minor: NumConstraint{Num: 1}, 457 Patch: NumConstraint{Num: 1}, 458 }, 459 }, 460 }, 461 }, 462 ``, 463 }, 464 { 465 "1.*.*", 466 UnionSpec{ 467 IntersectionSpec{ 468 SelectionSpec{ 469 Operator: OpMatch, 470 Boundary: VersionSpec{ 471 Major: NumConstraint{Num: 1}, 472 Minor: NumConstraint{Unconstrained: true}, 473 Patch: NumConstraint{Unconstrained: true}, 474 }, 475 }, 476 }, 477 }, 478 ``, 479 }, 480 { 481 "=1.*.*", 482 UnionSpec{ 483 IntersectionSpec{ 484 SelectionSpec{ 485 Operator: OpEqual, 486 Boundary: VersionSpec{ 487 Major: NumConstraint{Num: 1}, 488 Minor: NumConstraint{Num: 0}, 489 Patch: NumConstraint{Num: 0}, 490 }, 491 }, 492 }, 493 }, 494 ``, 495 }, 496 { 497 "1.0.x", 498 UnionSpec{ 499 IntersectionSpec{ 500 SelectionSpec{ 501 Operator: OpMatch, 502 Boundary: VersionSpec{ 503 Major: NumConstraint{Num: 1}, 504 Minor: NumConstraint{Num: 0}, 505 Patch: NumConstraint{Unconstrained: true}, 506 }, 507 }, 508 }, 509 }, 510 ``, 511 }, 512 { 513 "1.0.0 - 2.0.0", 514 UnionSpec{ 515 IntersectionSpec{ 516 SelectionSpec{ 517 Operator: OpGreaterThanOrEqual, 518 Boundary: VersionSpec{ 519 Major: NumConstraint{Num: 1}, 520 Minor: NumConstraint{Num: 0}, 521 Patch: NumConstraint{Num: 0}, 522 }, 523 }, 524 SelectionSpec{ 525 Operator: OpLessThanOrEqual, 526 Boundary: VersionSpec{ 527 Major: NumConstraint{Num: 2}, 528 Minor: NumConstraint{Num: 0}, 529 Patch: NumConstraint{Num: 0}, 530 }, 531 }, 532 }, 533 }, 534 ``, 535 }, 536 { 537 "1.*.* - 2.*.*", 538 UnionSpec{ 539 IntersectionSpec{ 540 SelectionSpec{ 541 Operator: OpGreaterThanOrEqual, 542 Boundary: VersionSpec{ 543 Major: NumConstraint{Num: 1}, 544 Minor: NumConstraint{Num: 0}, 545 Patch: NumConstraint{Num: 0}, 546 }, 547 }, 548 SelectionSpec{ 549 Operator: OpLessThan, 550 Boundary: VersionSpec{ 551 Major: NumConstraint{Num: 3}, 552 Minor: NumConstraint{Num: 0}, 553 Patch: NumConstraint{Num: 0}, 554 }, 555 }, 556 }, 557 }, 558 ``, 559 }, 560 { 561 ">1.0.0 - 2.0.0", 562 nil, 563 `lower bound of range specified with "-" operator must be an exact version`, 564 }, 565 { 566 "1.0.0 - >2.0.0", 567 nil, 568 `upper bound of range specified with "-" operator must be an exact version`, 569 }, 570 { 571 ">=1.0.0 <2.0.0", 572 UnionSpec{ 573 IntersectionSpec{ 574 SelectionSpec{ 575 Operator: OpGreaterThanOrEqual, 576 Boundary: VersionSpec{ 577 Major: NumConstraint{Num: 1}, 578 Minor: NumConstraint{Num: 0}, 579 Patch: NumConstraint{Num: 0}, 580 }, 581 }, 582 SelectionSpec{ 583 Operator: OpLessThan, 584 Boundary: VersionSpec{ 585 Major: NumConstraint{Num: 2}, 586 Minor: NumConstraint{Num: 0}, 587 Patch: NumConstraint{Num: 0}, 588 }, 589 }, 590 }, 591 }, 592 ``, 593 }, 594 { 595 ">=1.0 <2 || 2.0-beta.1", 596 UnionSpec{ 597 IntersectionSpec{ 598 SelectionSpec{ 599 Operator: OpGreaterThanOrEqual, 600 Boundary: VersionSpec{ 601 Major: NumConstraint{Num: 1}, 602 Minor: NumConstraint{Num: 0}, 603 Patch: NumConstraint{Num: 0}, 604 }, 605 }, 606 SelectionSpec{ 607 Operator: OpLessThan, 608 Boundary: VersionSpec{ 609 Major: NumConstraint{Num: 2}, 610 Minor: NumConstraint{Num: 0}, 611 Patch: NumConstraint{Num: 0}, 612 }, 613 }, 614 }, 615 IntersectionSpec{ 616 SelectionSpec{ 617 Operator: OpEqual, 618 Boundary: VersionSpec{ 619 Major: NumConstraint{Num: 2}, 620 Minor: NumConstraint{Num: 0}, 621 Patch: NumConstraint{Num: 0}, 622 Prerelease: "beta.1", 623 }, 624 }, 625 }, 626 }, 627 ``, 628 }, 629 { 630 "1.0.0, 2.0.0", 631 nil, 632 `commas are not needed to separate version selections; separate with spaces instead`, 633 }, 634 { 635 "= 1.1.1", 636 nil, 637 `no spaces allowed after operator "="`, 638 }, 639 { 640 "= 1.1.1", 641 nil, 642 `no spaces allowed after operator "="`, 643 }, 644 { 645 "garbage", 646 nil, 647 `the sequence "garbage" is not valid`, 648 }, 649 { 650 "&1.1.0", 651 nil, 652 `invalid constraint operator "&"`, 653 }, 654 } 655 656 for _, test := range tests { 657 t.Run(test.Input, func(t *testing.T) { 658 got, err := Parse(test.Input) 659 var gotErr string 660 if err != nil { 661 gotErr = err.Error() 662 } 663 if gotErr != test.WantErr { 664 t.Errorf("wrong error\ngot: %s\nwant: %s", gotErr, test.WantErr) 665 return 666 } 667 if err != nil { 668 return 669 } 670 671 t.Logf("got: %s", spew.Sdump(got)) 672 t.Logf("want: %s", spew.Sdump(test.Want)) 673 674 for _, problem := range deep.Equal(got, test.Want) { 675 t.Error(problem) 676 } 677 }) 678 } 679} 680