1package version 2 3import ( 4 "reflect" 5 "testing" 6) 7 8func TestNewVersion(t *testing.T) { 9 cases := []struct { 10 version string 11 err bool 12 }{ 13 {"", true}, 14 {"1.2.3", false}, 15 {"1.0", false}, 16 {"1", false}, 17 {"1.2.beta", true}, 18 {"1.21.beta", true}, 19 {"foo", true}, 20 {"1.2-5", false}, 21 {"1.2-beta.5", false}, 22 {"\n1.2", true}, 23 {"1.2.0-x.Y.0+metadata", false}, 24 {"1.2.0-x.Y.0+metadata-width-hypen", false}, 25 {"1.2.3-rc1-with-hypen", false}, 26 {"1.2.3.4", false}, 27 {"1.2.0.4-x.Y.0+metadata", false}, 28 {"1.2.0.4-x.Y.0+metadata-width-hypen", false}, 29 {"1.2.0-X-1.2.0+metadata~dist", false}, 30 {"1.2.3.4-rc1-with-hypen", false}, 31 {"1.2.3.4", false}, 32 {"v1.2.3", false}, 33 {"foo1.2.3", true}, 34 {"1.7rc2", false}, 35 {"v1.7rc2", false}, 36 {"1.0-", false}, 37 } 38 39 for _, tc := range cases { 40 _, err := NewVersion(tc.version) 41 if tc.err && err == nil { 42 t.Fatalf("expected error for version: %q", tc.version) 43 } else if !tc.err && err != nil { 44 t.Fatalf("error for version %q: %s", tc.version, err) 45 } 46 } 47} 48 49func TestNewSemver(t *testing.T) { 50 cases := []struct { 51 version string 52 err bool 53 }{ 54 {"", true}, 55 {"1.2.3", false}, 56 {"1.0", false}, 57 {"1", false}, 58 {"1.2.beta", true}, 59 {"1.21.beta", true}, 60 {"foo", true}, 61 {"1.2-5", false}, 62 {"1.2-beta.5", false}, 63 {"\n1.2", true}, 64 {"1.2.0-x.Y.0+metadata", false}, 65 {"1.2.0-x.Y.0+metadata-width-hypen", false}, 66 {"1.2.3-rc1-with-hypen", false}, 67 {"1.2.3.4", false}, 68 {"1.2.0.4-x.Y.0+metadata", false}, 69 {"1.2.0.4-x.Y.0+metadata-width-hypen", false}, 70 {"1.2.0-X-1.2.0+metadata~dist", false}, 71 {"1.2.3.4-rc1-with-hypen", false}, 72 {"1.2.3.4", false}, 73 {"v1.2.3", false}, 74 {"foo1.2.3", true}, 75 {"1.7rc2", true}, 76 {"v1.7rc2", true}, 77 {"1.0-", true}, 78 } 79 80 for _, tc := range cases { 81 _, err := NewSemver(tc.version) 82 if tc.err && err == nil { 83 t.Fatalf("expected error for version: %q", tc.version) 84 } else if !tc.err && err != nil { 85 t.Fatalf("error for version %q: %s", tc.version, err) 86 } 87 } 88} 89 90func TestVersionCompare(t *testing.T) { 91 cases := []struct { 92 v1 string 93 v2 string 94 expected int 95 }{ 96 {"1.2.3", "1.4.5", -1}, 97 {"1.2-beta", "1.2-beta", 0}, 98 {"1.2", "1.1.4", 1}, 99 {"1.2", "1.2-beta", 1}, 100 {"1.2+foo", "1.2+beta", 0}, 101 {"v1.2", "v1.2-beta", 1}, 102 {"v1.2+foo", "v1.2+beta", 0}, 103 {"v1.2.3.4", "v1.2.3.4", 0}, 104 {"v1.2.0.0", "v1.2", 0}, 105 {"v1.2.0.0.1", "v1.2", 1}, 106 {"v1.2", "v1.2.0.0", 0}, 107 {"v1.2", "v1.2.0.0.1", -1}, 108 {"v1.2.0.0", "v1.2.0.0.1", -1}, 109 {"v1.2.3.0", "v1.2.3.4", -1}, 110 {"1.7rc2", "1.7rc1", 1}, 111 {"1.7rc2", "1.7", -1}, 112 {"1.2.0", "1.2.0-X-1.2.0+metadata~dist", 1}, 113 } 114 115 for _, tc := range cases { 116 v1, err := NewVersion(tc.v1) 117 if err != nil { 118 t.Fatalf("err: %s", err) 119 } 120 121 v2, err := NewVersion(tc.v2) 122 if err != nil { 123 t.Fatalf("err: %s", err) 124 } 125 126 actual := v1.Compare(v2) 127 expected := tc.expected 128 if actual != expected { 129 t.Fatalf( 130 "%s <=> %s\nexpected: %d\nactual: %d", 131 tc.v1, tc.v2, 132 expected, actual) 133 } 134 } 135} 136 137func TestVersionCompare_versionAndSemver(t *testing.T) { 138 cases := []struct { 139 versionRaw string 140 semverRaw string 141 expected int 142 }{ 143 {"0.0.2", "0.0.2", 0}, 144 {"1.0.2alpha", "1.0.2-alpha", 0}, 145 {"v1.2+foo", "v1.2+beta", 0}, 146 {"v1.2", "v1.2+meta", 0}, 147 {"1.2", "1.2-beta", 1}, 148 {"v1.2", "v1.2-beta", 1}, 149 {"1.2.3", "1.4.5", -1}, 150 {"v1.2", "v1.2.0.0.1", -1}, 151 {"v1.0.3-", "v1.0.3", -1}, 152 } 153 154 for _, tc := range cases { 155 ver, err := NewVersion(tc.versionRaw) 156 if err != nil { 157 t.Fatalf("err: %s", err) 158 } 159 160 semver, err := NewSemver(tc.semverRaw) 161 if err != nil { 162 t.Fatalf("err: %s", err) 163 } 164 165 actual := ver.Compare(semver) 166 if actual != tc.expected { 167 t.Fatalf( 168 "%s <=> %s\nexpected: %d\n actual: %d", 169 tc.versionRaw, tc.semverRaw, tc.expected, actual, 170 ) 171 } 172 } 173} 174 175func TestVersionEqual_nil(t *testing.T) { 176 mustVersion := func(v string) *Version { 177 ver, err := NewVersion(v) 178 if err != nil { 179 t.Fatal(err) 180 } 181 return ver 182 } 183 cases := []struct { 184 leftVersion *Version 185 rightVersion *Version 186 expected bool 187 }{ 188 {mustVersion("1.0.0"), nil, false}, 189 {nil, mustVersion("1.0.0"), false}, 190 {nil, nil, true}, 191 } 192 193 for _, tc := range cases { 194 given := tc.leftVersion.Equal(tc.rightVersion) 195 if given != tc.expected { 196 t.Fatalf("expected Equal to nil to be %t", tc.expected) 197 } 198 } 199} 200 201func TestComparePreReleases(t *testing.T) { 202 cases := []struct { 203 v1 string 204 v2 string 205 expected int 206 }{ 207 {"1.2-beta.2", "1.2-beta.2", 0}, 208 {"1.2-beta.1", "1.2-beta.2", -1}, 209 {"1.2-beta.2", "1.2-beta.11", -1}, 210 {"3.2-alpha.1", "3.2-alpha", 1}, 211 {"1.2-beta.2", "1.2-beta.1", 1}, 212 {"1.2-beta.11", "1.2-beta.2", 1}, 213 {"1.2-beta", "1.2-beta.3", -1}, 214 {"1.2-alpha", "1.2-beta.3", -1}, 215 {"1.2-beta", "1.2-alpha.3", 1}, 216 {"3.0-alpha.3", "3.0-rc.1", -1}, 217 {"3.0-alpha3", "3.0-rc1", -1}, 218 {"3.0-alpha.1", "3.0-alpha.beta", -1}, 219 {"5.4-alpha", "5.4-alpha.beta", 1}, 220 {"v1.2-beta.2", "v1.2-beta.2", 0}, 221 {"v1.2-beta.1", "v1.2-beta.2", -1}, 222 {"v3.2-alpha.1", "v3.2-alpha", 1}, 223 {"v3.2-rc.1-1-g123", "v3.2-rc.2", 1}, 224 } 225 226 for _, tc := range cases { 227 v1, err := NewVersion(tc.v1) 228 if err != nil { 229 t.Fatalf("err: %s", err) 230 } 231 232 v2, err := NewVersion(tc.v2) 233 if err != nil { 234 t.Fatalf("err: %s", err) 235 } 236 237 actual := v1.Compare(v2) 238 expected := tc.expected 239 if actual != expected { 240 t.Fatalf( 241 "%s <=> %s\nexpected: %d\nactual: %d", 242 tc.v1, tc.v2, 243 expected, actual) 244 } 245 } 246} 247 248func TestVersionMetadata(t *testing.T) { 249 cases := []struct { 250 version string 251 expected string 252 }{ 253 {"1.2.3", ""}, 254 {"1.2-beta", ""}, 255 {"1.2.0-x.Y.0", ""}, 256 {"1.2.0-x.Y.0+metadata", "metadata"}, 257 {"1.2.0-metadata-1.2.0+metadata~dist", "metadata~dist"}, 258 } 259 260 for _, tc := range cases { 261 v, err := NewVersion(tc.version) 262 if err != nil { 263 t.Fatalf("err: %s", err) 264 } 265 266 actual := v.Metadata() 267 expected := tc.expected 268 if actual != expected { 269 t.Fatalf("expected: %s\nactual: %s", expected, actual) 270 } 271 } 272} 273 274func TestVersionPrerelease(t *testing.T) { 275 cases := []struct { 276 version string 277 expected string 278 }{ 279 {"1.2.3", ""}, 280 {"1.2-beta", "beta"}, 281 {"1.2.0-x.Y.0", "x.Y.0"}, 282 {"1.2.0-7.Y.0", "7.Y.0"}, 283 {"1.2.0-x.Y.0+metadata", "x.Y.0"}, 284 {"1.2.0-metadata-1.2.0+metadata~dist", "metadata-1.2.0"}, 285 {"17.03.0-ce", "ce"}, // zero-padded fields 286 } 287 288 for _, tc := range cases { 289 v, err := NewVersion(tc.version) 290 if err != nil { 291 t.Fatalf("err: %s", err) 292 } 293 294 actual := v.Prerelease() 295 expected := tc.expected 296 if actual != expected { 297 t.Fatalf("expected: %s\nactual: %s", expected, actual) 298 } 299 } 300} 301 302func TestVersionSegments(t *testing.T) { 303 cases := []struct { 304 version string 305 expected []int 306 }{ 307 {"1.2.3", []int{1, 2, 3}}, 308 {"1.2-beta", []int{1, 2, 0}}, 309 {"1-x.Y.0", []int{1, 0, 0}}, 310 {"1.2.0-x.Y.0+metadata", []int{1, 2, 0}}, 311 {"1.2.0-metadata-1.2.0+metadata~dist", []int{1, 2, 0}}, 312 {"17.03.0-ce", []int{17, 3, 0}}, // zero-padded fields 313 } 314 315 for _, tc := range cases { 316 v, err := NewVersion(tc.version) 317 if err != nil { 318 t.Fatalf("err: %s", err) 319 } 320 321 actual := v.Segments() 322 expected := tc.expected 323 if !reflect.DeepEqual(actual, expected) { 324 t.Fatalf("expected: %#v\nactual: %#v", expected, actual) 325 } 326 } 327} 328 329func TestVersionSegments64(t *testing.T) { 330 cases := []struct { 331 version string 332 expected []int64 333 }{ 334 {"1.2.3", []int64{1, 2, 3}}, 335 {"1.2-beta", []int64{1, 2, 0}}, 336 {"1-x.Y.0", []int64{1, 0, 0}}, 337 {"1.2.0-x.Y.0+metadata", []int64{1, 2, 0}}, 338 {"1.4.9223372036854775807", []int64{1, 4, 9223372036854775807}}, 339 } 340 341 for _, tc := range cases { 342 v, err := NewVersion(tc.version) 343 if err != nil { 344 t.Fatalf("err: %s", err) 345 } 346 347 actual := v.Segments64() 348 expected := tc.expected 349 if !reflect.DeepEqual(actual, expected) { 350 t.Fatalf("expected: %#v\nactual: %#v", expected, actual) 351 } 352 353 { 354 expected := actual[0] 355 actual[0]++ 356 actual = v.Segments64() 357 if actual[0] != expected { 358 t.Fatalf("Segments64 is mutable") 359 } 360 } 361 } 362} 363 364func TestVersionString(t *testing.T) { 365 cases := [][]string{ 366 {"1.2.3", "1.2.3"}, 367 {"1.2-beta", "1.2.0-beta"}, 368 {"1.2.0-x.Y.0", "1.2.0-x.Y.0"}, 369 {"1.2.0-x.Y.0+metadata", "1.2.0-x.Y.0+metadata"}, 370 {"1.2.0-metadata-1.2.0+metadata~dist", "1.2.0-metadata-1.2.0+metadata~dist"}, 371 {"17.03.0-ce", "17.3.0-ce"}, // zero-padded fields 372 } 373 374 for _, tc := range cases { 375 v, err := NewVersion(tc[0]) 376 if err != nil { 377 t.Fatalf("err: %s", err) 378 } 379 380 actual := v.String() 381 expected := tc[1] 382 if actual != expected { 383 t.Fatalf("expected: %s\nactual: %s", expected, actual) 384 } 385 if actual := v.Original(); actual != tc[0] { 386 t.Fatalf("expected original: %q\nactual: %q", tc[0], actual) 387 } 388 } 389} 390 391func TestEqual(t *testing.T) { 392 cases := []struct { 393 v1 string 394 v2 string 395 expected bool 396 }{ 397 {"1.2.3", "1.4.5", false}, 398 {"1.2-beta", "1.2-beta", true}, 399 {"1.2", "1.1.4", false}, 400 {"1.2", "1.2-beta", false}, 401 {"1.2+foo", "1.2+beta", true}, 402 {"v1.2", "v1.2-beta", false}, 403 {"v1.2+foo", "v1.2+beta", true}, 404 {"v1.2.3.4", "v1.2.3.4", true}, 405 {"v1.2.0.0", "v1.2", true}, 406 {"v1.2.0.0.1", "v1.2", false}, 407 {"v1.2", "v1.2.0.0", true}, 408 {"v1.2", "v1.2.0.0.1", false}, 409 {"v1.2.0.0", "v1.2.0.0.1", false}, 410 {"v1.2.3.0", "v1.2.3.4", false}, 411 {"1.7rc2", "1.7rc1", false}, 412 {"1.7rc2", "1.7", false}, 413 {"1.2.0", "1.2.0-X-1.2.0+metadata~dist", false}, 414 } 415 416 for _, tc := range cases { 417 v1, err := NewVersion(tc.v1) 418 if err != nil { 419 t.Fatalf("err: %s", err) 420 } 421 422 v2, err := NewVersion(tc.v2) 423 if err != nil { 424 t.Fatalf("err: %s", err) 425 } 426 427 actual := v1.Equal(v2) 428 expected := tc.expected 429 if actual != expected { 430 t.Fatalf( 431 "%s <=> %s\nexpected: %t\nactual: %t", 432 tc.v1, tc.v2, 433 expected, actual) 434 } 435 } 436} 437 438func TestGreaterThan(t *testing.T) { 439 cases := []struct { 440 v1 string 441 v2 string 442 expected bool 443 }{ 444 {"1.2.3", "1.4.5", false}, 445 {"1.2-beta", "1.2-beta", false}, 446 {"1.2", "1.1.4", true}, 447 {"1.2", "1.2-beta", true}, 448 {"1.2+foo", "1.2+beta", false}, 449 {"v1.2", "v1.2-beta", true}, 450 {"v1.2+foo", "v1.2+beta", false}, 451 {"v1.2.3.4", "v1.2.3.4", false}, 452 {"v1.2.0.0", "v1.2", false}, 453 {"v1.2.0.0.1", "v1.2", true}, 454 {"v1.2", "v1.2.0.0", false}, 455 {"v1.2", "v1.2.0.0.1", false}, 456 {"v1.2.0.0", "v1.2.0.0.1", false}, 457 {"v1.2.3.0", "v1.2.3.4", false}, 458 {"1.7rc2", "1.7rc1", true}, 459 {"1.7rc2", "1.7", false}, 460 {"1.2.0", "1.2.0-X-1.2.0+metadata~dist", true}, 461 } 462 463 for _, tc := range cases { 464 v1, err := NewVersion(tc.v1) 465 if err != nil { 466 t.Fatalf("err: %s", err) 467 } 468 469 v2, err := NewVersion(tc.v2) 470 if err != nil { 471 t.Fatalf("err: %s", err) 472 } 473 474 actual := v1.GreaterThan(v2) 475 expected := tc.expected 476 if actual != expected { 477 t.Fatalf( 478 "%s > %s\nexpected: %t\nactual: %t", 479 tc.v1, tc.v2, 480 expected, actual) 481 } 482 } 483} 484 485func TestLessThan(t *testing.T) { 486 cases := []struct { 487 v1 string 488 v2 string 489 expected bool 490 }{ 491 {"1.2.3", "1.4.5", true}, 492 {"1.2-beta", "1.2-beta", false}, 493 {"1.2", "1.1.4", false}, 494 {"1.2", "1.2-beta", false}, 495 {"1.2+foo", "1.2+beta", false}, 496 {"v1.2", "v1.2-beta", false}, 497 {"v1.2+foo", "v1.2+beta", false}, 498 {"v1.2.3.4", "v1.2.3.4", false}, 499 {"v1.2.0.0", "v1.2", false}, 500 {"v1.2.0.0.1", "v1.2", false}, 501 {"v1.2", "v1.2.0.0", false}, 502 {"v1.2", "v1.2.0.0.1", true}, 503 {"v1.2.0.0", "v1.2.0.0.1", true}, 504 {"v1.2.3.0", "v1.2.3.4", true}, 505 {"1.7rc2", "1.7rc1", false}, 506 {"1.7rc2", "1.7", true}, 507 {"1.2.0", "1.2.0-X-1.2.0+metadata~dist", false}, 508 } 509 510 for _, tc := range cases { 511 v1, err := NewVersion(tc.v1) 512 if err != nil { 513 t.Fatalf("err: %s", err) 514 } 515 516 v2, err := NewVersion(tc.v2) 517 if err != nil { 518 t.Fatalf("err: %s", err) 519 } 520 521 actual := v1.LessThan(v2) 522 expected := tc.expected 523 if actual != expected { 524 t.Fatalf( 525 "%s < %s\nexpected: %t\nactual: %t", 526 tc.v1, tc.v2, 527 expected, actual) 528 } 529 } 530} 531 532func TestGreaterThanOrEqual(t *testing.T) { 533 cases := []struct { 534 v1 string 535 v2 string 536 expected bool 537 }{ 538 {"1.2.3", "1.4.5", false}, 539 {"1.2-beta", "1.2-beta", true}, 540 {"1.2", "1.1.4", true}, 541 {"1.2", "1.2-beta", true}, 542 {"1.2+foo", "1.2+beta", true}, 543 {"v1.2", "v1.2-beta", true}, 544 {"v1.2+foo", "v1.2+beta", true}, 545 {"v1.2.3.4", "v1.2.3.4", true}, 546 {"v1.2.0.0", "v1.2", true}, 547 {"v1.2.0.0.1", "v1.2", true}, 548 {"v1.2", "v1.2.0.0", true}, 549 {"v1.2", "v1.2.0.0.1", false}, 550 {"v1.2.0.0", "v1.2.0.0.1", false}, 551 {"v1.2.3.0", "v1.2.3.4", false}, 552 {"1.7rc2", "1.7rc1", true}, 553 {"1.7rc2", "1.7", false}, 554 {"1.2.0", "1.2.0-X-1.2.0+metadata~dist", true}, 555 } 556 557 for _, tc := range cases { 558 v1, err := NewVersion(tc.v1) 559 if err != nil { 560 t.Fatalf("err: %s", err) 561 } 562 563 v2, err := NewVersion(tc.v2) 564 if err != nil { 565 t.Fatalf("err: %s", err) 566 } 567 568 actual := v1.GreaterThanOrEqual(v2) 569 expected := tc.expected 570 if actual != expected { 571 t.Fatalf( 572 "%s >= %s\nexpected: %t\nactual: %t", 573 tc.v1, tc.v2, 574 expected, actual) 575 } 576 } 577} 578 579func TestLessThanOrEqual(t *testing.T) { 580 cases := []struct { 581 v1 string 582 v2 string 583 expected bool 584 }{ 585 {"1.2.3", "1.4.5", true}, 586 {"1.2-beta", "1.2-beta", true}, 587 {"1.2", "1.1.4", false}, 588 {"1.2", "1.2-beta", false}, 589 {"1.2+foo", "1.2+beta", true}, 590 {"v1.2", "v1.2-beta", false}, 591 {"v1.2+foo", "v1.2+beta", true}, 592 {"v1.2.3.4", "v1.2.3.4", true}, 593 {"v1.2.0.0", "v1.2", true}, 594 {"v1.2.0.0.1", "v1.2", false}, 595 {"v1.2", "v1.2.0.0", true}, 596 {"v1.2", "v1.2.0.0.1", true}, 597 {"v1.2.0.0", "v1.2.0.0.1", true}, 598 {"v1.2.3.0", "v1.2.3.4", true}, 599 {"1.7rc2", "1.7rc1", false}, 600 {"1.7rc2", "1.7", true}, 601 {"1.2.0", "1.2.0-X-1.2.0+metadata~dist", false}, 602 } 603 604 for _, tc := range cases { 605 v1, err := NewVersion(tc.v1) 606 if err != nil { 607 t.Fatalf("err: %s", err) 608 } 609 610 v2, err := NewVersion(tc.v2) 611 if err != nil { 612 t.Fatalf("err: %s", err) 613 } 614 615 actual := v1.LessThanOrEqual(v2) 616 expected := tc.expected 617 if actual != expected { 618 t.Fatalf( 619 "%s <= %s\nexpected: %t\nactual: %t", 620 tc.v1, tc.v2, 621 expected, actual) 622 } 623 } 624} 625