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