plugin:update dropped a go.mod require that was not a strict vX.Y.Z and treated it as v0.0.0, so a module at a commit after v0.4.0 (v0.4.1-0.<ts>-<hash>) was moved back to v0.4.0. kiosk.Newer now places a release against a release, a git describe string or a pseudo-version (by the tag it builds on, in Go's version order); plugin:update and the admin Plugins screen badge share it. A pseudo-version with no tag before its commit is left alone with a note naming go get <module>@<tag>.
182 lines
7.1 KiB
Go
182 lines
7.1 KiB
Go
package kiosk
|
|
|
|
import "testing"
|
|
|
|
// TestVersions pins the version rules the registry, plugin:install,
|
|
// plugin:update and the admin share.
|
|
func TestVersions(t *testing.T) {
|
|
t.Run("ValidVersion", func(t *testing.T) {
|
|
for v, want := range map[string]bool{
|
|
"v0.0.0": true, "v0.6.0": true, "v1.20.300": true, "v12345678901234567890.0.1": true,
|
|
"0.6.0": false, "v0.6": false, "v0.6.0.1": false, "v0.6.0-rc.1": false, "v0.6.0+build": false,
|
|
"v00.6.0": false, "v0.06.0": false, "v0.6.00": false, "V0.6.0": false, " v0.6.0": false,
|
|
"v0.6.0\n": false, "v-1.0.0": false, "": false, "v0.6.0-1-gabcdef0": false,
|
|
} {
|
|
if got := ValidVersion(v); got != want {
|
|
t.Errorf("ValidVersion(%q) = %v, want %v", v, got, want)
|
|
}
|
|
}
|
|
})
|
|
|
|
t.Run("CompareVersions", func(t *testing.T) {
|
|
cases := []struct {
|
|
a, b string
|
|
want int
|
|
}{
|
|
{"v0.0.0", "v0.0.0", 0}, {"v0.0.1", "v0.0.0", 1}, {"v0.1.0", "v0.0.99", 1},
|
|
{"v1.0.0", "v0.99.99", 1}, {"v0.9.0", "v0.10.0", -1}, {"v0.10.0", "v0.9.0", 1},
|
|
{"v99999999999999999999.0.0", "v99999999999999999998.9.9", 1},
|
|
{"v0.5.3", "v0.6.0", -1}, {"v0.6.0", "v0.6.0", 0},
|
|
}
|
|
for _, c := range cases {
|
|
if got := CompareVersions(c.a, c.b); got != c.want {
|
|
t.Errorf("CompareVersions(%s, %s) = %d, want %d", c.a, c.b, got, c.want)
|
|
}
|
|
if got := CompareVersions(c.b, c.a); got != -c.want {
|
|
t.Errorf("CompareVersions(%s, %s) = %d, want %d (antisymmetric)", c.b, c.a, got, -c.want)
|
|
}
|
|
}
|
|
})
|
|
|
|
t.Run("BaseVersion", func(t *testing.T) {
|
|
for in, want := range map[string]string{
|
|
"v0.6.0": "v0.6.0",
|
|
"v0.6.0-12-gdeadbee": "v0.6.0",
|
|
"v0.6.0-1-g0123456789ab": "v0.6.0",
|
|
"v0.6.0-dirty": "",
|
|
"v0.6.0-12-gdeadbee-dirty": "",
|
|
"v0.6.0-rc.1": "",
|
|
"v0.6.0-rc.1-2-gabcdef0": "",
|
|
"deadbee": "",
|
|
"0.6.0-1-gabcdef0": "",
|
|
"v0.6.0-x-gabcdef0": "",
|
|
"": "",
|
|
} {
|
|
if got := BaseVersion(in); got != want {
|
|
t.Errorf("BaseVersion(%q) = %q, want %q", in, got, want)
|
|
}
|
|
}
|
|
})
|
|
|
|
t.Run("pseudo-versions", func(t *testing.T) {
|
|
for v, want := range map[string]bool{
|
|
"v0.0.0-20261029101500-abcdefabcdef": true,
|
|
"v0.6.1-0.20261029101500-abcdefabcdef": true,
|
|
"v0.6.0-rc.1.0.20261029101500-abcdefabcdef": true,
|
|
"v0.6.1-0.2026102910150-abcdefabcdef": false,
|
|
"v0.6.1-0.20261029101500-abcdefabcde": false,
|
|
"v0.6.1": false,
|
|
"v0.6.1-12-gabcdef0": false,
|
|
} {
|
|
if got := isPseudoVersion(v); got != want {
|
|
t.Errorf("isPseudoVersion(%q) = %v, want %v", v, got, want)
|
|
}
|
|
}
|
|
})
|
|
|
|
t.Run("Satisfies", func(t *testing.T) {
|
|
cases := []struct {
|
|
have, min string
|
|
want bool
|
|
}{
|
|
{"v0.6.0", "", true}, {"", "", true}, {"garbage", "", true},
|
|
{"v0.6.0", "v0.6.0", true}, {"v0.6.1", "v0.6.0", true}, {"v1.0.0", "v0.6.0", true},
|
|
{"v0.5.9", "v0.6.0", false}, {"", "v0.6.0", false}, {"v0.6.0-3-gabcdef0", "v0.6.0", false},
|
|
// A pseudo-version minimum vX.Y.Z-0.<ts>-<hash> sorts just
|
|
// below vX.Y.Z: the release itself meets it, the one before
|
|
// does not.
|
|
{"v0.6.1", "v0.6.1-0.20261029101500-abcdefabcdef", true},
|
|
{"v0.7.0", "v0.6.1-0.20261029101500-abcdefabcdef", true},
|
|
{"v0.6.0", "v0.6.1-0.20261029101500-abcdefabcdef", false},
|
|
{"v0.6.0", "v0.6.0-rc.1.0.20261029101500-abcdefabcdef", true},
|
|
{"v0.0.1", "v0.0.0-20261029101500-abcdefabcdef", true},
|
|
{"v0.6.0", "latest", false}, {"v0.6.0", "v0.6", false},
|
|
}
|
|
for _, c := range cases {
|
|
if got := Satisfies(c.have, c.min); got != c.want {
|
|
t.Errorf("Satisfies(%q, %q) = %v, want %v", c.have, c.min, got, c.want)
|
|
}
|
|
}
|
|
})
|
|
|
|
t.Run("Newer", func(t *testing.T) {
|
|
cases := []struct {
|
|
release, installed string
|
|
want bool
|
|
}{
|
|
{"v0.4.1", "v0.4.0", true}, {"v0.4.0", "v0.4.0", false}, {"v0.3.9", "v0.4.0", false},
|
|
{"v0.4.1", "v0.4.0-3-gabc1234", true}, {"v0.4.0", "v0.4.0-3-gabc1234", false},
|
|
// A commit after v0.4.0 (go get M@main): v0.4.0 and older are
|
|
// downgrades; v0.4.1 is the next release in Go's order.
|
|
{"v0.4.0", "v0.4.1-0.20261001120000-abcdef123456", false},
|
|
{"v0.3.0", "v0.4.1-0.20261001120000-abcdef123456", false},
|
|
{"v0.4.1", "v0.4.1-0.20261001120000-abcdef123456", true},
|
|
{"v0.5.0", "v0.4.1-0.20261001120000-abcdef123456", true},
|
|
// A commit after the pre-release v0.5.0-rc.1.
|
|
{"v0.4.9", "v0.5.0-rc.1.0.20261001120000-abcdef123456", false},
|
|
{"v0.5.0", "v0.5.0-rc.1.0.20261001120000-abcdef123456", true},
|
|
// No tag before the commit, a bare hash, a pre-release, nothing:
|
|
// never newer.
|
|
{"v0.1.0", "v0.0.0-20261001120000-abcdef123456", false},
|
|
{"v9.0.0", "abc1234", false}, {"v9.0.0", "v0.5.0-rc.1", false}, {"v9.0.0", "", false},
|
|
{"main", "v0.4.0", false}, {"v0.5.0-rc.1", "v0.4.0", false},
|
|
}
|
|
for _, c := range cases {
|
|
if got := Newer(c.release, c.installed); got != c.want {
|
|
t.Errorf("Newer(%q, %q) = %v, want %v", c.release, c.installed, got, c.want)
|
|
}
|
|
}
|
|
for v, want := range map[string]bool{
|
|
"v0.4.0": true, "v0.4.0-3-gabc1234": true,
|
|
"v0.4.1-0.20261001120000-abcdef123456": true,
|
|
"v0.5.0-rc.1.0.20261001120000-abcdef123456": true,
|
|
"v0.0.0-20261001120000-abcdef123456": false,
|
|
"abc1234": false, "v0.5.0-rc.1": false, "": false,
|
|
} {
|
|
if got := Comparable(v); got != want {
|
|
t.Errorf("Comparable(%q) = %v, want %v", v, got, want)
|
|
}
|
|
}
|
|
})
|
|
|
|
t.Run("NewestCompatible", func(t *testing.T) {
|
|
if _, ok := NewestCompatible(nil, "v0.6.0"); ok {
|
|
t.Error("nil list found a version")
|
|
}
|
|
if _, ok := NewestCompatible([]RegistryVersion{}, "v0.6.0"); ok {
|
|
t.Error("empty list found a version")
|
|
}
|
|
incompatible := []RegistryVersion{{Version: "v0.2.0", Framework: "v0.7.0"}, {Version: "v0.3.0", Framework: "v1.0.0"}}
|
|
if got, ok := NewestCompatible(incompatible, "v0.6.0"); ok {
|
|
t.Errorf("all incompatible found %+v", got)
|
|
}
|
|
unsorted := []RegistryVersion{
|
|
{Version: "v0.1.0", Framework: "v0.5.0"},
|
|
{Version: "v0.10.0", Framework: "v0.6.0", Commit: "ten"},
|
|
{Version: "v0.9.0", Framework: "v0.5.0"},
|
|
{Version: "v0.11.0", Framework: "v0.7.0"},
|
|
{Version: "v0.12.0-rc.1", Framework: ""},
|
|
{Version: "main", Framework: ""},
|
|
{Version: "v0.2.0", Framework: ""},
|
|
}
|
|
got, ok := NewestCompatible(unsorted, "v0.6.0")
|
|
if !ok || got.Version != "v0.10.0" || got.Commit != "ten" {
|
|
t.Errorf("unsorted = %+v, %v; want v0.10.0", got, ok)
|
|
}
|
|
if got, ok := NewestCompatible(unsorted, "v0.7.0"); !ok || got.Version != "v0.11.0" {
|
|
t.Errorf("framework v0.7.0 = %+v, %v; want v0.11.0", got, ok)
|
|
}
|
|
// A framework that is not a release only meets empty minimums.
|
|
if got, ok := NewestCompatible(unsorted, ""); !ok || got.Version != "v0.2.0" {
|
|
t.Errorf("unknown framework = %+v, %v; want v0.2.0", got, ok)
|
|
}
|
|
pseudo := []RegistryVersion{{Version: "v0.4.0", Framework: "v0.6.1-0.20261029101500-abcdefabcdef"}}
|
|
if _, ok := NewestCompatible(pseudo, "v0.6.0"); ok {
|
|
t.Error("pseudo-version framework minimum met by the release before it")
|
|
}
|
|
if _, ok := NewestCompatible(pseudo, "v0.6.1"); !ok {
|
|
t.Error("pseudo-version framework minimum not met by its release")
|
|
}
|
|
})
|
|
}
|