Files
summercms/modules/kiosk/version_test.go
Jakub Zych 60551485ed fix(34): CR-01 never move a pseudo-version install back to its base release
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>.
2026-10-29 21:58:07 +01:00

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")
}
})
}