1package semver 2 3import ( 4 "testing" 5) 6 7func prstr(s string) PRVersion { 8 return PRVersion{s, 0, false} 9} 10 11func prnum(i uint64) PRVersion { 12 return PRVersion{"", i, true} 13} 14 15type formatTest struct { 16 v Version 17 result string 18} 19 20var formatTests = []formatTest{ 21 {Version{1, 2, 3, nil, nil}, "1.2.3"}, 22 {Version{0, 0, 1, nil, nil}, "0.0.1"}, 23 {Version{0, 0, 1, []PRVersion{prstr("alpha"), prstr("preview")}, []string{"123", "456"}}, "0.0.1-alpha.preview+123.456"}, 24 {Version{1, 2, 3, []PRVersion{prstr("alpha"), prnum(1)}, []string{"123", "456"}}, "1.2.3-alpha.1+123.456"}, 25 {Version{1, 2, 3, []PRVersion{prstr("alpha"), prnum(1)}, nil}, "1.2.3-alpha.1"}, 26 {Version{1, 2, 3, nil, []string{"123", "456"}}, "1.2.3+123.456"}, 27 // Prereleases and build metadata hyphens 28 {Version{1, 2, 3, []PRVersion{prstr("alpha"), prstr("b-eta")}, []string{"123", "b-uild"}}, "1.2.3-alpha.b-eta+123.b-uild"}, 29 {Version{1, 2, 3, nil, []string{"123", "b-uild"}}, "1.2.3+123.b-uild"}, 30 {Version{1, 2, 3, []PRVersion{prstr("alpha"), prstr("b-eta")}, nil}, "1.2.3-alpha.b-eta"}, 31} 32 33var tolerantFormatTests = []formatTest{ 34 {Version{1, 2, 3, nil, nil}, "v1.2.3"}, 35 {Version{1, 2, 0, []PRVersion{prstr("alpha")}, nil}, "1.2.0-alpha"}, 36 {Version{1, 2, 0, nil, nil}, "1.2.00"}, 37 {Version{1, 2, 3, nil, nil}, " 1.2.3 "}, 38 {Version{1, 2, 3, nil, nil}, "01.02.03"}, 39 {Version{0, 0, 3, nil, nil}, "00.0.03"}, 40 {Version{0, 0, 3, nil, nil}, "000.0.03"}, 41 {Version{1, 2, 0, nil, nil}, "1.2"}, 42 {Version{1, 0, 0, nil, nil}, "1"}, 43} 44 45func TestStringer(t *testing.T) { 46 for _, test := range formatTests { 47 if res := test.v.String(); res != test.result { 48 t.Errorf("Stringer, expected %q but got %q", test.result, res) 49 } 50 } 51} 52 53func TestParse(t *testing.T) { 54 for _, test := range formatTests { 55 if v, err := Parse(test.result); err != nil { 56 t.Errorf("Error parsing %q: %q", test.result, err) 57 } else if comp := v.Compare(test.v); comp != 0 { 58 t.Errorf("Parsing, expected %q but got %q, comp: %d ", test.v, v, comp) 59 } else if err := v.Validate(); err != nil { 60 t.Errorf("Error validating parsed version %q: %q", test.v, err) 61 } 62 } 63} 64 65func TestParseTolerant(t *testing.T) { 66 for _, test := range tolerantFormatTests { 67 if v, err := ParseTolerant(test.result); err != nil { 68 t.Errorf("Error parsing %q: %q", test.result, err) 69 } else if comp := v.Compare(test.v); comp != 0 { 70 t.Errorf("Parsing, expected %q but got %q, comp: %d ", test.v, v, comp) 71 } else if err := v.Validate(); err != nil { 72 t.Errorf("Error validating parsed version %q: %q", test.v, err) 73 } 74 } 75} 76 77func TestMustParse(t *testing.T) { 78 _ = MustParse("32.2.1-alpha") 79} 80 81func TestMustParse_panic(t *testing.T) { 82 defer func() { 83 if recover() == nil { 84 t.Errorf("Should have panicked") 85 } 86 }() 87 _ = MustParse("invalid version") 88} 89 90func TestValidate(t *testing.T) { 91 for _, test := range formatTests { 92 if err := test.v.Validate(); err != nil { 93 t.Errorf("Error validating %q: %q", test.v, err) 94 } 95 } 96} 97 98var finalizeVersionMethod = []formatTest{ 99 {Version{1, 2, 3, nil, nil}, "1.2.3"}, 100 {Version{0, 0, 1, nil, nil}, "0.0.1"}, 101 {Version{0, 0, 1, []PRVersion{prstr("alpha"), prstr("preview")}, []string{"123", "456"}}, "0.0.1"}, 102 {Version{1, 2, 3, []PRVersion{prstr("alpha"), prnum(1)}, []string{"123", "456"}}, "1.2.3"}, 103 {Version{1, 2, 3, []PRVersion{prstr("alpha"), prnum(1)}, nil}, "1.2.3"}, 104 {Version{1, 2, 3, nil, []string{"123", "456"}}, "1.2.3"}, 105 // Prereleases and build metadata hyphens 106 {Version{1, 2, 3, []PRVersion{prstr("alpha"), prstr("b-eta")}, []string{"123", "b-uild"}}, "1.2.3"}, 107 {Version{1, 2, 3, nil, []string{"123", "b-uild"}}, "1.2.3"}, 108 {Version{1, 2, 3, []PRVersion{prstr("alpha"), prstr("b-eta")}, nil}, "1.2.3"}, 109} 110 111func TestFinalizeVersionMethod(t *testing.T) { 112 for _, test := range finalizeVersionMethod { 113 out := test.v.FinalizeVersion() 114 if out != test.result { 115 t.Errorf("Finalized version error, expected %q but got %q", test.result, out) 116 } 117 } 118} 119 120type compareTest struct { 121 v1 Version 122 v2 Version 123 result int 124} 125 126var compareTests = []compareTest{ 127 {Version{1, 0, 0, nil, nil}, Version{1, 0, 0, nil, nil}, 0}, 128 {Version{2, 0, 0, nil, nil}, Version{1, 0, 0, nil, nil}, 1}, 129 {Version{0, 1, 0, nil, nil}, Version{0, 1, 0, nil, nil}, 0}, 130 {Version{0, 2, 0, nil, nil}, Version{0, 1, 0, nil, nil}, 1}, 131 {Version{0, 0, 1, nil, nil}, Version{0, 0, 1, nil, nil}, 0}, 132 {Version{0, 0, 2, nil, nil}, Version{0, 0, 1, nil, nil}, 1}, 133 {Version{1, 2, 3, nil, nil}, Version{1, 2, 3, nil, nil}, 0}, 134 {Version{2, 2, 4, nil, nil}, Version{1, 2, 4, nil, nil}, 1}, 135 {Version{1, 3, 3, nil, nil}, Version{1, 2, 3, nil, nil}, 1}, 136 {Version{1, 2, 4, nil, nil}, Version{1, 2, 3, nil, nil}, 1}, 137 138 // Spec Examples #11 139 {Version{1, 0, 0, nil, nil}, Version{2, 0, 0, nil, nil}, -1}, 140 {Version{2, 0, 0, nil, nil}, Version{2, 1, 0, nil, nil}, -1}, 141 {Version{2, 1, 0, nil, nil}, Version{2, 1, 1, nil, nil}, -1}, 142 143 // Spec Examples #9 144 {Version{1, 0, 0, nil, nil}, Version{1, 0, 0, []PRVersion{prstr("alpha")}, nil}, 1}, 145 {Version{1, 0, 0, []PRVersion{prstr("alpha")}, nil}, Version{1, 0, 0, []PRVersion{prstr("alpha"), prnum(1)}, nil}, -1}, 146 {Version{1, 0, 0, []PRVersion{prstr("alpha"), prnum(1)}, nil}, Version{1, 0, 0, []PRVersion{prstr("alpha"), prstr("beta")}, nil}, -1}, 147 {Version{1, 0, 0, []PRVersion{prstr("alpha"), prstr("beta")}, nil}, Version{1, 0, 0, []PRVersion{prstr("beta")}, nil}, -1}, 148 {Version{1, 0, 0, []PRVersion{prstr("beta")}, nil}, Version{1, 0, 0, []PRVersion{prstr("beta"), prnum(2)}, nil}, -1}, 149 {Version{1, 0, 0, []PRVersion{prstr("beta"), prnum(2)}, nil}, Version{1, 0, 0, []PRVersion{prstr("beta"), prnum(11)}, nil}, -1}, 150 {Version{1, 0, 0, []PRVersion{prstr("beta"), prnum(11)}, nil}, Version{1, 0, 0, []PRVersion{prstr("rc"), prnum(1)}, nil}, -1}, 151 {Version{1, 0, 0, []PRVersion{prstr("rc"), prnum(1)}, nil}, Version{1, 0, 0, nil, nil}, -1}, 152 153 // Ignore Build metadata 154 {Version{1, 0, 0, nil, []string{"1", "2", "3"}}, Version{1, 0, 0, nil, nil}, 0}, 155} 156 157func TestCompare(t *testing.T) { 158 for _, test := range compareTests { 159 if res := test.v1.Compare(test.v2); res != test.result { 160 t.Errorf("Comparing %q : %q, expected %d but got %d", test.v1, test.v2, test.result, res) 161 } 162 // Test counterpart 163 if res := test.v2.Compare(test.v1); res != -test.result { 164 t.Errorf("Comparing %q : %q, expected %d but got %d", test.v2, test.v1, -test.result, res) 165 } 166 } 167} 168 169type wrongformatTest struct { 170 v *Version 171 str string 172} 173 174var wrongformatTests = []wrongformatTest{ 175 {nil, ""}, 176 {nil, "."}, 177 {nil, "1."}, 178 {nil, ".1"}, 179 {nil, "a.b.c"}, 180 {nil, "1.a.b"}, 181 {nil, "1.1.a"}, 182 {nil, "1.a.1"}, 183 {nil, "a.1.1"}, 184 {nil, ".."}, 185 {nil, "1.."}, 186 {nil, "1.1."}, 187 {nil, "1..1"}, 188 {nil, "1.1.+123"}, 189 {nil, "1.1.-beta"}, 190 {nil, "-1.1.1"}, 191 {nil, "1.-1.1"}, 192 {nil, "1.1.-1"}, 193 // giant numbers 194 {nil, "20000000000000000000.1.1"}, 195 {nil, "1.20000000000000000000.1"}, 196 {nil, "1.1.20000000000000000000"}, 197 {nil, "1.1.1-20000000000000000000"}, 198 // Leading zeroes 199 {nil, "01.1.1"}, 200 {nil, "001.1.1"}, 201 {nil, "1.01.1"}, 202 {nil, "1.001.1"}, 203 {nil, "1.1.01"}, 204 {nil, "1.1.001"}, 205 {nil, "1.1.1-01"}, 206 {nil, "1.1.1-001"}, 207 {nil, "1.1.1-beta.01"}, 208 {nil, "1.1.1-beta.001"}, 209 {&Version{0, 0, 0, []PRVersion{prstr("!")}, nil}, "0.0.0-!"}, 210 {&Version{0, 0, 0, nil, []string{"!"}}, "0.0.0+!"}, 211 // empty prversion 212 {&Version{0, 0, 0, []PRVersion{prstr(""), prstr("alpha")}, nil}, "0.0.0-.alpha"}, 213 // empty build meta data 214 {&Version{0, 0, 0, []PRVersion{prstr("alpha")}, []string{""}}, "0.0.0-alpha+"}, 215 {&Version{0, 0, 0, []PRVersion{prstr("alpha")}, []string{"test", ""}}, "0.0.0-alpha+test."}, 216} 217 218func TestWrongFormat(t *testing.T) { 219 for _, test := range wrongformatTests { 220 221 if res, err := Parse(test.str); err == nil { 222 t.Errorf("Parsing wrong format version %q, expected error but got %q", test.str, res) 223 } 224 225 if test.v != nil { 226 if err := test.v.Validate(); err == nil { 227 t.Errorf("Validating wrong format version %q (%q), expected error", test.v, test.str) 228 } 229 } 230 } 231} 232 233var wrongTolerantFormatTests = []wrongformatTest{ 234 {nil, "1.0+abc"}, 235 {nil, "1.0-rc.1"}, 236} 237 238func TestWrongTolerantFormat(t *testing.T) { 239 for _, test := range wrongTolerantFormatTests { 240 if res, err := ParseTolerant(test.str); err == nil { 241 t.Errorf("Parsing wrong format version %q, expected error but got %q", test.str, res) 242 } 243 } 244} 245 246func TestCompareHelper(t *testing.T) { 247 v := Version{1, 0, 0, []PRVersion{prstr("alpha")}, nil} 248 v1 := Version{1, 0, 0, nil, nil} 249 if !v.EQ(v) { 250 t.Errorf("%q should be equal to %q", v, v) 251 } 252 if !v.Equals(v) { 253 t.Errorf("%q should be equal to %q", v, v) 254 } 255 if !v1.NE(v) { 256 t.Errorf("%q should not be equal to %q", v1, v) 257 } 258 if !v.GTE(v) { 259 t.Errorf("%q should be greater than or equal to %q", v, v) 260 } 261 if !v.LTE(v) { 262 t.Errorf("%q should be less than or equal to %q", v, v) 263 } 264 if !v.LT(v1) { 265 t.Errorf("%q should be less than %q", v, v1) 266 } 267 if !v.LTE(v1) { 268 t.Errorf("%q should be less than or equal %q", v, v1) 269 } 270 if !v.LE(v1) { 271 t.Errorf("%q should be less than or equal %q", v, v1) 272 } 273 if !v1.GT(v) { 274 t.Errorf("%q should be greater than %q", v1, v) 275 } 276 if !v1.GTE(v) { 277 t.Errorf("%q should be greater than or equal %q", v1, v) 278 } 279 if !v1.GE(v) { 280 t.Errorf("%q should be greater than or equal %q", v1, v) 281 } 282} 283 284const ( 285 MAJOR = iota 286 MINOR 287 PATCH 288) 289 290type incrementTest struct { 291 version Version 292 incrementType int 293 expectingError bool 294 expectedVersion Version 295} 296 297var incrementTests = []incrementTest{ 298 {Version{1, 2, 3, nil, nil}, PATCH, false, Version{1, 2, 4, nil, nil}}, 299 {Version{1, 2, 3, nil, nil}, MINOR, false, Version{1, 3, 0, nil, nil}}, 300 {Version{1, 2, 3, nil, nil}, MAJOR, false, Version{2, 0, 0, nil, nil}}, 301 {Version{0, 1, 2, nil, nil}, PATCH, false, Version{0, 1, 3, nil, nil}}, 302 {Version{0, 1, 2, nil, nil}, MINOR, false, Version{0, 2, 0, nil, nil}}, 303 {Version{0, 1, 2, nil, nil}, MAJOR, false, Version{1, 0, 0, nil, nil}}, 304} 305 306func TestIncrements(t *testing.T) { 307 for _, test := range incrementTests { 308 var originalVersion = Version{ 309 test.version.Major, 310 test.version.Minor, 311 test.version.Patch, 312 test.version.Pre, 313 test.version.Build, 314 } 315 var err error 316 switch test.incrementType { 317 case PATCH: 318 err = test.version.IncrementPatch() 319 case MINOR: 320 err = test.version.IncrementMinor() 321 case MAJOR: 322 err = test.version.IncrementMajor() 323 } 324 if test.expectingError { 325 if err != nil { 326 t.Errorf("Increment version, expecting %q, got error %q", test.expectedVersion, err) 327 } 328 if test.version.EQ(originalVersion) { 329 t.Errorf("Increment version, expecting %q, got %q", test.expectedVersion, test.version) 330 } 331 } else { 332 if (err != nil) && !test.expectingError { 333 t.Errorf("Increment version %q, not expecting error, got %q", test.version, err) 334 } 335 if test.version.NE(test.expectedVersion) { 336 t.Errorf("Increment version, expecting %q, got %q", test.expectedVersion, test.version) 337 } 338 } 339 } 340} 341 342func TestPreReleaseVersions(t *testing.T) { 343 p1, err := NewPRVersion("123") 344 if !p1.IsNumeric() { 345 t.Errorf("Expected numeric prversion, got %q", p1) 346 } 347 if p1.VersionNum != 123 { 348 t.Error("Wrong prversion number") 349 } 350 if err != nil { 351 t.Errorf("Not expected error %q", err) 352 } 353 p2, err := NewPRVersion("alpha") 354 if p2.IsNumeric() { 355 t.Errorf("Expected non-numeric prversion, got %q", p2) 356 } 357 if p2.VersionStr != "alpha" { 358 t.Error("Wrong prversion string") 359 } 360 if err != nil { 361 t.Errorf("Not expected error %q", err) 362 } 363} 364 365func TestBuildMetaDataVersions(t *testing.T) { 366 _, err := NewBuildVersion("123") 367 if err != nil { 368 t.Errorf("Unexpected error %q", err) 369 } 370 371 _, err = NewBuildVersion("build") 372 if err != nil { 373 t.Errorf("Unexpected error %q", err) 374 } 375 376 _, err = NewBuildVersion("test?") 377 if err == nil { 378 t.Error("Expected error, got none") 379 } 380 381 _, err = NewBuildVersion("") 382 if err == nil { 383 t.Error("Expected error, got none") 384 } 385} 386 387func TestNewHelper(t *testing.T) { 388 v, err := New("1.2.3") 389 if err != nil { 390 t.Fatalf("Unexpected error %q", err) 391 } 392 393 // New returns pointer 394 if v == nil { 395 t.Fatal("Version is nil") 396 } 397 if v.Compare(Version{1, 2, 3, nil, nil}) != 0 { 398 t.Fatal("Unexpected comparison problem") 399 } 400} 401 402func TestMakeHelper(t *testing.T) { 403 v, err := Make("1.2.3") 404 if err != nil { 405 t.Fatalf("Unexpected error %q", err) 406 } 407 if v.Compare(Version{1, 2, 3, nil, nil}) != 0 { 408 t.Fatal("Unexpected comparison problem") 409 } 410} 411 412type finalizeTest struct { 413 input string 414 output string 415} 416 417var finalizeTests = []finalizeTest{ 418 {"", ""}, 419 {"1.2.3", "1.2.3"}, 420 {"0.0.1", "0.0.1"}, 421 {"0.0.1-alpha.preview+123.456", "0.0.1"}, 422 {"1.2.3-alpha.1+123.456", "1.2.3"}, 423 {"1.2.3-alpha.1", "1.2.3"}, 424 {"1.2.3+123.456", "1.2.3"}, 425 {"1.2.3-alpha.b-eta+123.b-uild", "1.2.3"}, 426 {"1.2.3+123.b-uild", "1.2.3"}, 427 {"1.2.3-alpha.b-eta", "1.2.3"}, 428 {"1.2-alpha", ""}, 429} 430 431func TestFinalizeVersion(t *testing.T) { 432 for _, test := range finalizeTests { 433 finalVer, err := FinalizeVersion(test.input) 434 if finalVer == "" { 435 if err == nil { 436 t.Errorf("Finalize Version error, expected error but got nil") 437 } 438 } else if finalVer != test.output && err != nil { 439 t.Errorf("Finalize Version error expected %q but got %q", test.output, finalVer) 440 } 441 } 442} 443 444func BenchmarkParseSimple(b *testing.B) { 445 const VERSION = "0.0.1" 446 b.ReportAllocs() 447 b.ResetTimer() 448 for n := 0; n < b.N; n++ { 449 _, _ = Parse(VERSION) 450 } 451} 452 453func BenchmarkParseComplex(b *testing.B) { 454 const VERSION = "0.0.1-alpha.preview+123.456" 455 b.ReportAllocs() 456 b.ResetTimer() 457 for n := 0; n < b.N; n++ { 458 _, _ = Parse(VERSION) 459 } 460} 461 462func BenchmarkParseAverage(b *testing.B) { 463 l := len(formatTests) 464 b.ReportAllocs() 465 b.ResetTimer() 466 for n := 0; n < b.N; n++ { 467 _, _ = Parse(formatTests[n%l].result) 468 } 469} 470 471func BenchmarkParseTolerantAverage(b *testing.B) { 472 l := len(tolerantFormatTests) 473 b.ReportAllocs() 474 b.ResetTimer() 475 for n := 0; n < b.N; n++ { 476 _, _ = ParseTolerant(tolerantFormatTests[n%l].result) 477 } 478} 479 480func BenchmarkStringSimple(b *testing.B) { 481 const VERSION = "0.0.1" 482 v, _ := Parse(VERSION) 483 b.ReportAllocs() 484 b.ResetTimer() 485 for n := 0; n < b.N; n++ { 486 _ = v.String() 487 } 488} 489 490func BenchmarkStringLarger(b *testing.B) { 491 const VERSION = "11.15.2012" 492 v, _ := Parse(VERSION) 493 b.ReportAllocs() 494 b.ResetTimer() 495 for n := 0; n < b.N; n++ { 496 _ = v.String() 497 } 498} 499 500func BenchmarkStringComplex(b *testing.B) { 501 const VERSION = "0.0.1-alpha.preview+123.456" 502 v, _ := Parse(VERSION) 503 b.ReportAllocs() 504 b.ResetTimer() 505 for n := 0; n < b.N; n++ { 506 _ = v.String() 507 } 508} 509 510func BenchmarkStringAverage(b *testing.B) { 511 l := len(formatTests) 512 b.ReportAllocs() 513 b.ResetTimer() 514 for n := 0; n < b.N; n++ { 515 _ = formatTests[n%l].v.String() 516 } 517} 518 519func BenchmarkValidateSimple(b *testing.B) { 520 const VERSION = "0.0.1" 521 v, _ := Parse(VERSION) 522 b.ReportAllocs() 523 b.ResetTimer() 524 for n := 0; n < b.N; n++ { 525 _ = v.Validate() 526 } 527} 528 529func BenchmarkValidateComplex(b *testing.B) { 530 const VERSION = "0.0.1-alpha.preview+123.456" 531 v, _ := Parse(VERSION) 532 b.ReportAllocs() 533 b.ResetTimer() 534 for n := 0; n < b.N; n++ { 535 _ = v.Validate() 536 } 537} 538 539func BenchmarkValidateAverage(b *testing.B) { 540 l := len(formatTests) 541 b.ReportAllocs() 542 b.ResetTimer() 543 for n := 0; n < b.N; n++ { 544 _ = formatTests[n%l].v.Validate() 545 } 546} 547 548func BenchmarkCompareSimple(b *testing.B) { 549 const VERSION = "0.0.1" 550 v, _ := Parse(VERSION) 551 b.ReportAllocs() 552 b.ResetTimer() 553 for n := 0; n < b.N; n++ { 554 v.Compare(v) 555 } 556} 557 558func BenchmarkCompareComplex(b *testing.B) { 559 const VERSION = "0.0.1-alpha.preview+123.456" 560 v, _ := Parse(VERSION) 561 b.ReportAllocs() 562 b.ResetTimer() 563 for n := 0; n < b.N; n++ { 564 v.Compare(v) 565 } 566} 567 568func BenchmarkCompareAverage(b *testing.B) { 569 l := len(compareTests) 570 b.ReportAllocs() 571 b.ResetTimer() 572 for n := 0; n < b.N; n++ { 573 compareTests[n%l].v1.Compare((compareTests[n%l].v2)) 574 } 575} 576