package main import "testing" func TestVersionsAreOrderedAsSemverSays(t *testing.T) { // Each is lower than the next (semver.org ยง11's own example, and the edges around it). ordered := []string{"0.0.1", "0.1.0", "1.0.0-0", "1.0.0-alpha", "1.0.0-alpha.1", "1.0.0-alpha.beta", "1.0.0-beta", "1.0.0-beta.2", "1.0.0-beta.11", "1.0.0-rc.1", "1.0.0", "1.0.1", "1.2.0", "1.10.0", "2.0.0"} for i := 0; i+1 < len(ordered); i++ { a, _ := ParseVersion(ordered[i]) b, _ := ParseVersion(ordered[i+1]) if Compare(a, b) >= 0 || Compare(b, a) <= 0 { t.Errorf("%s should be lower than %s", ordered[i], ordered[i+1]) } } a, _ := ParseVersion("1.2.3+build.1") b, _ := ParseVersion("1.2.3") if Compare(a, b) != 0 { t.Error("build metadata does not order") } for _, bad := range []string{"1.2", "x", "1.2.3.4", "latest", ""} { if _, err := ParseVersion(bad); err == nil { t.Errorf("%q read as a version", bad) } } } func TestRangesAreReadAsNpmReadsThem(t *testing.T) { cases := []struct { r string in []string out []string }{ {"1.2.3", []string{"1.2.3"}, []string{"1.2.4", "1.2.3-beta"}}, {"=1.2.3", []string{"1.2.3"}, []string{"1.2.2"}}, {"^1.2.3", []string{"1.2.3", "1.9.9"}, []string{"2.0.0", "1.2.2", "1.3.0-beta", "2.0.0-0"}}, {"^0.2.3", []string{"0.2.3", "0.2.9"}, []string{"0.3.0", "0.2.2"}}, {"^0.0.3", []string{"0.0.3"}, []string{"0.0.4"}}, {"^1.2", []string{"1.2.0", "1.9.0"}, []string{"2.0.0", "1.1.9"}}, {"^0.x", []string{"0.0.1", "0.9.9"}, []string{"1.0.0"}}, {"^0.0", []string{"0.0.9"}, []string{"0.1.0"}}, {"^1.2.3-beta.2", []string{"1.2.3-beta.2", "1.2.3-beta.4", "1.2.3", "1.5.0"}, []string{"1.2.3-beta.1", "1.2.4-beta.1", "2.0.0"}}, {"~1.2.3", []string{"1.2.3", "1.2.9"}, []string{"1.3.0", "1.2.2"}}, {"~1.2", []string{"1.2.0", "1.2.9"}, []string{"1.3.0"}}, {"~1", []string{"1.0.0", "1.9.9"}, []string{"2.0.0"}}, {"~0.2.3", []string{"0.2.5"}, []string{"0.3.0"}}, {"*", []string{"0.0.0", "9.9.9"}, []string{"1.0.0-beta"}}, {"", []string{"1.0.0"}, nil}, {"x", []string{"1.0.0"}, nil}, {"1.x", []string{"1.0.0", "1.9.9"}, []string{"2.0.0", "0.9.9"}}, {"1.2.*", []string{"1.2.0", "1.2.9"}, []string{"1.3.0"}}, {"1", []string{"1.5.0"}, []string{"2.0.0"}}, {">1.2.3", []string{"1.2.4"}, []string{"1.2.3"}}, {">1.2", []string{"1.3.0"}, []string{"1.2.9"}}, {">=1.2.3", []string{"1.2.3", "5.0.0"}, []string{"1.2.2"}}, {"<1.2.3", []string{"1.2.2"}, []string{"1.2.3", "1.2.3-beta"}}, {"<1.2", []string{"1.1.9"}, []string{"1.2.0"}}, {"<=1.2.3", []string{"1.2.3"}, []string{"1.2.4"}}, {"<=1.2", []string{"1.2.9"}, []string{"1.3.0"}}, {">= 1.2.3 < 2", []string{"1.2.3", "1.9.9"}, []string{"2.0.0", "1.2.2"}}, {">=1.2.3 <1.5.0", []string{"1.4.9"}, []string{"1.5.0"}}, {"1.2.3 - 2.3.4", []string{"1.2.3", "2.3.4"}, []string{"2.3.5", "1.2.2"}}, {"1.2 - 2.3", []string{"1.2.0", "2.3.9"}, []string{"2.4.0", "1.1.9"}}, {"1.2.3 - 2", []string{"2.9.9"}, []string{"3.0.0"}}, {"^1.0.0 || ^3.0.0", []string{"1.5.0", "3.1.0"}, []string{"2.0.0"}}, {"1.2.3 || >=2.5.0 <3", []string{"1.2.3", "2.6.0"}, []string{"2.0.0", "3.0.0"}}, {"v1.2.3", []string{"1.2.3"}, nil}, {"~>1.2.3", []string{"1.2.9"}, []string{"1.3.0"}}, {">=1.0.0-rc.1 <1.0.0", []string{"1.0.0-rc.2"}, []string{"0.9.0-rc.1"}}, } for _, c := range cases { r, err := ParseRange(c.r) if err != nil { t.Errorf("%q: %v", c.r, err) continue } for _, s := range c.in { v, err := ParseVersion(s) if err != nil { t.Fatal(err) } if !r.Satisfies(v) { t.Errorf("%q should hold %s", c.r, s) } } for _, s := range c.out { v, _ := ParseVersion(s) if r.Satisfies(v) { t.Errorf("%q should not hold %s", c.r, s) } } } } func TestARangeThatIsNotOneIsRefused(t *testing.T) { for _, bad := range []string{"latest", "^abc", "1.2.3.4", ">=x.y.z", "1.x-beta"} { if _, err := ParseRange(bad); err == nil { t.Errorf("%q read as a range", bad) } } } func TestTheHighestSatisfyingVersionIsTheOneARangeResolvesTo(t *testing.T) { var vs []Version for _, s := range []string{"0.1.0", "0.1.4", "0.2.0", "0.2.1-beta", "1.0.0"} { v, _ := ParseVersion(s) vs = append(vs, v) } r, _ := ParseRange("^0.1.0") if best, ok := MaxSatisfying(r, vs); !ok || best.String() != "0.1.4" { t.Fatalf("^0.1.0 resolved to %v", best) } r, _ = ParseRange("^2.0.0") if _, ok := MaxSatisfying(r, vs); ok { t.Fatal("^2.0.0 resolved to something") } }