2021-08-07 18:26:56 +00:00
|
|
|
package tagcmp_test
|
|
|
|
|
|
|
|
import (
|
|
|
|
"sort"
|
|
|
|
"testing"
|
|
|
|
|
|
|
|
"coopcloud.tech/tagcmp"
|
|
|
|
)
|
|
|
|
|
|
|
|
var giteaTags = []string{
|
|
|
|
"latest",
|
|
|
|
"1",
|
|
|
|
"1-linux-amd64",
|
|
|
|
"1-linux-amd64-rootless",
|
|
|
|
"1-linux-arm64",
|
|
|
|
"1-linux-arm64-rootless",
|
|
|
|
"1-rootless",
|
|
|
|
"1.0",
|
|
|
|
"1.0.0",
|
|
|
|
"1.0.1",
|
|
|
|
"1.0.2",
|
|
|
|
"1.1",
|
|
|
|
"1.1.0",
|
|
|
|
"1.1.1",
|
|
|
|
"1.1.2",
|
|
|
|
"1.1.3",
|
|
|
|
"1.1.4",
|
|
|
|
"1.10",
|
|
|
|
"1.10-linux-amd64",
|
|
|
|
"1.10-linux-arm64",
|
|
|
|
"1.10.0",
|
|
|
|
"1.10.0-linux-amd64",
|
|
|
|
"1.10.0-linux-arm64",
|
|
|
|
"1.10.0-rc1",
|
|
|
|
"1.10.0-rc1-linux-amd64",
|
|
|
|
"1.10.0-rc1-linux-arm64",
|
|
|
|
"1.10.0-rc2",
|
|
|
|
"1.10.0-rc2-linux-amd64",
|
|
|
|
"1.10.0-rc2-linux-arm64",
|
|
|
|
"1.10.1",
|
|
|
|
"1.10.1-linux-amd64",
|
|
|
|
"1.10.1-linux-arm64",
|
|
|
|
"1.10.2",
|
|
|
|
"1.10.2-linux-amd64",
|
|
|
|
"1.10.2-linux-arm64",
|
|
|
|
"1.10.3",
|
|
|
|
"1.10.3-linux-amd64",
|
|
|
|
"1.10.3-linux-arm64",
|
|
|
|
"1.10.4",
|
|
|
|
"1.10.4-linux-amd64",
|
|
|
|
"1.10.4-linux-arm64",
|
|
|
|
"1.10.5",
|
|
|
|
"1.10.5-linux-amd64",
|
|
|
|
"1.10.5-linux-arm64",
|
|
|
|
"1.10.6",
|
|
|
|
"1.10.6-linux-amd64",
|
|
|
|
"1.10.6-linux-arm64",
|
|
|
|
"1.11",
|
|
|
|
"1.11-linux-amd64",
|
|
|
|
"1.11-linux-arm64",
|
|
|
|
"1.11.0",
|
|
|
|
"1.11.0-linux-amd64",
|
|
|
|
"1.11.0-linux-arm64",
|
|
|
|
"1.11.0-rc1",
|
|
|
|
"1.11.0-rc1-linux-amd64",
|
|
|
|
"1.11.0-rc1-linux-arm64",
|
|
|
|
"1.11.0-rc2",
|
|
|
|
"1.11.0-rc2-linux-amd64",
|
|
|
|
"1.11.0-rc2-linux-arm64",
|
|
|
|
"1.11.1",
|
|
|
|
"1.11.1-linux-amd64",
|
|
|
|
"1.11.1-linux-arm64",
|
|
|
|
"1.11.2",
|
|
|
|
"1.11.2-linux-amd64",
|
|
|
|
"1.11.2-linux-arm64",
|
|
|
|
"1.11.3",
|
|
|
|
"1.11.3-linux-amd64",
|
|
|
|
"1.11.3-linux-arm64",
|
|
|
|
"1.11.4",
|
|
|
|
"1.11.4-linux-amd64",
|
|
|
|
"1.11.4-linux-arm64",
|
|
|
|
"1.11.5",
|
|
|
|
"1.11.5-linux-amd64",
|
|
|
|
"1.11.5-linux-arm64",
|
|
|
|
"1.11.6",
|
|
|
|
"1.11.6-linux-amd64",
|
|
|
|
"1.11.6-linux-arm64",
|
|
|
|
"1.11.7",
|
|
|
|
"1.11.7-linux-amd64",
|
|
|
|
"1.11.7-linux-arm64",
|
|
|
|
"1.11.8",
|
|
|
|
"1.11.8-linux-amd64",
|
|
|
|
"1.11.8-linux-arm64",
|
|
|
|
"1.12",
|
|
|
|
"1.12-linux-amd64",
|
|
|
|
"1.12-linux-arm64",
|
|
|
|
"1.12.0",
|
|
|
|
"1.12.0-linux-amd64",
|
|
|
|
"1.12.0-linux-arm64",
|
|
|
|
"1.12.0-rc1",
|
|
|
|
"1.12.0-rc1-linux-amd64",
|
|
|
|
"1.12.0-rc1-linux-arm64",
|
|
|
|
"1.12.0-rc2",
|
|
|
|
"1.12.0-rc2-linux-amd64",
|
|
|
|
"1.12.0-rc2-linux-arm64",
|
|
|
|
"1.12.1",
|
|
|
|
"1.12.1-linux-amd64",
|
|
|
|
"1.12.1-linux-arm64",
|
|
|
|
"1.12.2",
|
|
|
|
"1.12.2-linux-amd64",
|
|
|
|
"1.12.2-linux-arm64",
|
|
|
|
"1.12.3",
|
|
|
|
"1.12.3-linux-amd64",
|
|
|
|
"1.12.3-linux-arm64",
|
|
|
|
"1.12.4",
|
|
|
|
"1.12.4-linux-amd64",
|
|
|
|
"1.12.4-linux-arm64",
|
|
|
|
"1.12.5",
|
|
|
|
"1.12.5-linux-amd64",
|
|
|
|
"1.12.5-linux-arm64",
|
|
|
|
"1.12.6",
|
|
|
|
"1.12.6-linux-amd64",
|
|
|
|
"1.12.6-linux-arm64",
|
|
|
|
"1.13",
|
|
|
|
"1.13-linux-amd64",
|
|
|
|
"1.13-linux-arm64",
|
|
|
|
"1.13.0",
|
|
|
|
"1.13.0-linux-amd64",
|
|
|
|
"1.13.0-linux-arm64",
|
|
|
|
"1.13.0-rc1",
|
|
|
|
"1.13.0-rc1-linux-amd64",
|
|
|
|
"1.13.0-rc1-linux-arm64",
|
|
|
|
"1.13.0-rc2",
|
|
|
|
"1.13.0-rc2-linux-amd64",
|
|
|
|
"1.13.0-rc2-linux-arm64",
|
|
|
|
"1.13.1",
|
|
|
|
"1.13.1-linux-amd64",
|
|
|
|
"1.13.1-linux-arm64",
|
|
|
|
"1.13.2",
|
|
|
|
"1.13.2-linux-amd64",
|
|
|
|
"1.13.2-linux-arm64",
|
|
|
|
"1.13.3",
|
|
|
|
"1.13.3-linux-amd64",
|
|
|
|
"1.13.3-linux-arm64",
|
|
|
|
"1.13.4",
|
|
|
|
"1.13.4-linux-amd64",
|
|
|
|
"1.13.4-linux-arm64",
|
|
|
|
"1.13.5",
|
|
|
|
"1.13.5-linux-amd64",
|
|
|
|
"1.13.5-linux-arm64",
|
|
|
|
"1.13.6",
|
|
|
|
"1.13.6-linux-amd64",
|
|
|
|
"1.13.6-linux-arm64",
|
|
|
|
"1.13.7",
|
|
|
|
"1.13.7-linux-amd64",
|
|
|
|
"1.13.7-linux-arm64",
|
|
|
|
"1.14",
|
|
|
|
"1.14-linux-amd64",
|
|
|
|
"1.14-linux-amd64-rootless",
|
|
|
|
"1.14-linux-arm64",
|
|
|
|
"1.14-linux-arm64-rootless",
|
|
|
|
"1.14-rootless",
|
|
|
|
"1.14.0",
|
|
|
|
"1.14.0-linux-amd64",
|
|
|
|
"1.14.0-linux-amd64-rootless",
|
|
|
|
"1.14.0-linux-arm64",
|
|
|
|
"1.14.0-linux-arm64-rootless",
|
|
|
|
"1.14.0-rc1",
|
|
|
|
"1.14.0-rc1-linux-amd64",
|
|
|
|
"1.14.0-rc1-linux-amd64-rootless",
|
|
|
|
"1.14.0-rc1-linux-arm64",
|
|
|
|
"1.14.0-rc1-linux-arm64-rootless",
|
|
|
|
"1.14.0-rc1-rootless",
|
|
|
|
"1.14.0-rc2",
|
|
|
|
"1.14.0-rc2-linux-amd64",
|
|
|
|
"1.14.0-rc2-linux-amd64-rootless",
|
|
|
|
"1.14.0-rc2-linux-arm64",
|
|
|
|
"1.14.0-rc2-linux-arm64-rootless",
|
|
|
|
"1.14.0-rc2-rootless",
|
|
|
|
"1.14.0-rootless",
|
|
|
|
"1.14.1",
|
|
|
|
"1.14.1-linux-amd64",
|
|
|
|
"1.14.1-linux-amd64-rootless",
|
|
|
|
"1.14.1-linux-arm64",
|
|
|
|
"1.14.1-linux-arm64-rootless",
|
|
|
|
"1.14.1-rootless",
|
|
|
|
"1.14.2",
|
|
|
|
"1.14.2-linux-amd64",
|
|
|
|
"1.14.2-linux-amd64-rootless",
|
|
|
|
"1.14.2-linux-arm64",
|
|
|
|
"1.14.2-linux-arm64-rootless",
|
|
|
|
"1.14.2-rootless",
|
|
|
|
"1.14.3",
|
|
|
|
"1.14.3-linux-amd64",
|
|
|
|
"1.14.3-linux-amd64-rootless",
|
|
|
|
"1.14.3-linux-arm64",
|
|
|
|
"1.14.3-linux-arm64-rootless",
|
|
|
|
"1.14.3-rootless",
|
|
|
|
"1.14.4",
|
|
|
|
"1.14.4-linux-amd64",
|
|
|
|
"1.14.4-linux-amd64-rootless",
|
|
|
|
"1.14.4-linux-arm64",
|
|
|
|
"1.14.4-linux-arm64-rootless",
|
|
|
|
"1.14.4-rootless",
|
|
|
|
"1.14.5",
|
|
|
|
"1.14.5-linux-amd64",
|
|
|
|
"1.14.5-linux-amd64-rootless",
|
|
|
|
"1.14.5-linux-arm64",
|
|
|
|
"1.14.5-linux-arm64-rootless",
|
|
|
|
"1.14.5-rootless",
|
|
|
|
"1.14.6",
|
|
|
|
"1.14.6-linux-amd64",
|
|
|
|
"1.14.6-linux-amd64-rootless",
|
|
|
|
"1.14.6-linux-arm64",
|
|
|
|
"1.14.6-linux-arm64-rootless",
|
|
|
|
"1.14.6-rootless",
|
|
|
|
"1.15.0-rc1",
|
|
|
|
"1.15.0-rc1-linux-amd64",
|
|
|
|
"1.15.0-rc1-linux-amd64-rootless",
|
|
|
|
"1.15.0-rc1-linux-arm64",
|
|
|
|
"1.15.0-rc1-linux-arm64-rootless",
|
|
|
|
"1.15.0-rc1-rootless",
|
|
|
|
"1.15.0-rc2",
|
|
|
|
"1.15.0-rc2-linux-amd64",
|
|
|
|
"1.15.0-rc2-linux-amd64-rootless",
|
|
|
|
"1.15.0-rc2-linux-arm64",
|
|
|
|
"1.15.0-rc2-linux-arm64-rootless",
|
|
|
|
"1.15.0-rc2-rootless",
|
|
|
|
"1.15.0-rc3",
|
|
|
|
"1.15.0-rc3-linux-amd64",
|
|
|
|
"1.15.0-rc3-linux-amd64-rootless",
|
|
|
|
"1.15.0-rc3-linux-arm64",
|
|
|
|
"1.15.0-rc3-linux-arm64-rootless",
|
|
|
|
"1.15.0-rc3-rootless",
|
|
|
|
"1.2",
|
|
|
|
"1.2.0",
|
|
|
|
"1.2.0-rc1",
|
|
|
|
"1.2.0-rc2",
|
|
|
|
"1.2.0-rc3",
|
|
|
|
"1.2.0-rc4",
|
|
|
|
"1.2.1",
|
|
|
|
"1.2.2",
|
|
|
|
"1.2.3",
|
|
|
|
"1.3",
|
|
|
|
"1.3.0",
|
|
|
|
"1.3.0-rc1",
|
|
|
|
"1.3.0-rc2",
|
|
|
|
"1.3.1",
|
|
|
|
"1.3.2",
|
|
|
|
"1.3.3",
|
|
|
|
"1.4",
|
|
|
|
"1.4.0",
|
|
|
|
"1.4.0-rc1",
|
|
|
|
"1.4.0-rc2",
|
|
|
|
"1.4.0-rc3",
|
|
|
|
"1.4.1",
|
|
|
|
"1.4.2",
|
|
|
|
"1.4.3",
|
|
|
|
"1.5",
|
|
|
|
"1.5.0",
|
|
|
|
"1.5.0-rc1",
|
|
|
|
"1.5.0-rc2",
|
|
|
|
"1.5.1",
|
|
|
|
"1.5.2",
|
|
|
|
"1.5.3",
|
|
|
|
"1.6",
|
|
|
|
"1.6.0",
|
|
|
|
"1.6.0-rc1",
|
|
|
|
"1.6.0-rc2",
|
|
|
|
"1.6.1",
|
|
|
|
"1.6.2",
|
|
|
|
"1.6.3",
|
|
|
|
"1.6.4",
|
|
|
|
"1.7",
|
|
|
|
"1.7.0",
|
|
|
|
"1.7.0-rc1",
|
|
|
|
"1.7.0-rc2",
|
|
|
|
"1.7.0-rc3",
|
|
|
|
"1.7.1",
|
|
|
|
"1.7.2",
|
|
|
|
"1.7.3",
|
|
|
|
"1.7.4",
|
|
|
|
"1.7.5",
|
|
|
|
"1.7.6",
|
|
|
|
"1.8",
|
|
|
|
"1.8.0",
|
|
|
|
"1.8.0-rc1",
|
|
|
|
"1.8.0-rc2",
|
|
|
|
"1.8.0-rc3",
|
|
|
|
"1.8.1",
|
|
|
|
"1.8.2",
|
|
|
|
"1.8.3",
|
|
|
|
"1.9",
|
|
|
|
"1.9-linux-amd64",
|
|
|
|
"1.9-linux-arm64",
|
|
|
|
"1.9.0",
|
|
|
|
"1.9.1",
|
|
|
|
"1.9.2",
|
|
|
|
"1.9.2-linux-amd64",
|
|
|
|
"1.9.2-linux-arm64",
|
|
|
|
"1.9.3",
|
|
|
|
"1.9.3-linux-amd64",
|
|
|
|
"1.9.3-linux-arm64",
|
|
|
|
"1.9.4",
|
|
|
|
"1.9.4-linux-amd64",
|
|
|
|
"1.9.4-linux-arm64",
|
|
|
|
"1.9.5",
|
|
|
|
"1.9.5-linux-amd64",
|
|
|
|
"1.9.5-linux-arm64",
|
|
|
|
"1.9.6",
|
|
|
|
"1.9.6-linux-amd64",
|
|
|
|
"1.9.6-linux-arm64",
|
|
|
|
"dev",
|
|
|
|
"dev-linux-amd64",
|
|
|
|
"dev-linux-amd64-rootless",
|
|
|
|
"dev-linux-arm64",
|
|
|
|
"dev-linux-arm64-rootless",
|
|
|
|
"dev-rootless",
|
|
|
|
"latest-rootless",
|
|
|
|
"linux-amd64",
|
|
|
|
"linux-amd64-rootless",
|
|
|
|
"linux-arm64",
|
|
|
|
"linux-arm64-rootless",
|
|
|
|
}
|
|
|
|
|
|
|
|
var supported = []string{
|
|
|
|
// semver
|
|
|
|
"5",
|
|
|
|
"2.6",
|
|
|
|
"4.3.5",
|
|
|
|
|
|
|
|
// semver with 'v'
|
|
|
|
"v1",
|
|
|
|
"v2.3",
|
|
|
|
"v1.0.2",
|
|
|
|
|
|
|
|
// semver with suffix
|
|
|
|
"6-alpine",
|
|
|
|
"6.2-alpine",
|
|
|
|
"6.2.1-alpine",
|
|
|
|
|
|
|
|
// semver with sufix and 'v'
|
|
|
|
"v6-alpine",
|
|
|
|
"v6.2-alpine",
|
|
|
|
"v6.2.1-alpine",
|
|
|
|
"v6.2.1-alpine",
|
|
|
|
|
2021-10-11 12:38:08 +00:00
|
|
|
// semver with '+'
|
|
|
|
"5+SDFJ_-2l4x.",
|
|
|
|
"2.6+SDFJ_-2l4x.",
|
|
|
|
"4.3.5+SDFJ_-2l4x.",
|
|
|
|
|
|
|
|
// semver with '+' and 'v'
|
|
|
|
"v5+SDFJ_-2l4x.",
|
|
|
|
"v2.6+SDFJ_-2l4x.",
|
|
|
|
"v4.3.5+SDFJ_-2l4x.",
|
|
|
|
|
|
|
|
// semver with '+' and suffix
|
|
|
|
"5-alpine+SDFJ_-2l4x.",
|
|
|
|
"2.6-alpine+SDFJ_-2l4x.",
|
|
|
|
"4.3.5-alpine+SDFJ_-2l4x.",
|
|
|
|
|
|
|
|
// semver with 'v', '+' and suffix
|
|
|
|
"v5-alpine+SDFJ_-2l4x.",
|
|
|
|
"v2.6-alpine+SDFJ_-2l4x.",
|
|
|
|
"v4.3.5-alpine+SDFJ_-2l4x.",
|
|
|
|
|
2021-08-07 18:26:56 +00:00
|
|
|
// semver with multiple suffix values
|
|
|
|
"v6.2.1-alpine-foo",
|
2021-10-11 12:38:08 +00:00
|
|
|
|
|
|
|
// semver with multiple suffix values and '+'
|
|
|
|
"v6.2.1-alpine-foo+68BC1E",
|
2021-08-07 18:26:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
var unsupported = []string{
|
|
|
|
// empty
|
|
|
|
"",
|
|
|
|
|
2021-10-11 12:38:08 +00:00
|
|
|
// parametrized
|
2021-08-07 18:26:56 +00:00
|
|
|
"${MAILU_VERSION:-master}",
|
|
|
|
"${PHP_VERSION}-fpm-alpine3.13",
|
|
|
|
|
|
|
|
// commit hash like
|
|
|
|
"0a1b2c3d4e5f6a7b8c9d0a1b2c3d4e5f6a7b8c9d",
|
|
|
|
|
|
|
|
// numeric
|
|
|
|
"20191109",
|
|
|
|
"e02267d",
|
|
|
|
|
|
|
|
// not semver
|
|
|
|
"3.0.6.0",
|
|
|
|
"r1295",
|
|
|
|
"version-r1070",
|
|
|
|
|
2021-10-11 12:38:08 +00:00
|
|
|
// too much dots
|
|
|
|
"1.0.0.0.0",
|
|
|
|
|
2021-08-07 18:26:56 +00:00
|
|
|
// prerelease
|
|
|
|
"3.7.0b1",
|
|
|
|
"3.8.0b1-alpine",
|
|
|
|
|
|
|
|
// multiple versions
|
|
|
|
"5.36-backdrop-php7.4",
|
|
|
|
"v1.0.5_3.4.0",
|
|
|
|
"v1.0.5_3.4.0_openid-sso",
|
|
|
|
|
|
|
|
// tz based
|
|
|
|
"RELEASE.2021-04-22T15-44-28Z",
|
|
|
|
|
|
|
|
// only text
|
|
|
|
"alpine",
|
|
|
|
"latest",
|
|
|
|
"master",
|
|
|
|
|
|
|
|
// multiple - delimters
|
|
|
|
"apache-debian-1.8-prod",
|
|
|
|
"version-znc-1.8.2",
|
2021-10-11 12:38:08 +00:00
|
|
|
|
|
|
|
// unparsable major/minor/patch parts:
|
|
|
|
"a.0.0",
|
|
|
|
"1.a",
|
|
|
|
"1.a.0",
|
|
|
|
"1.0.a",
|
2021-08-07 18:26:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestParseUnsupported(t *testing.T) {
|
|
|
|
for _, tag := range unsupported {
|
|
|
|
if _, err := tagcmp.Parse(tag); err == nil {
|
|
|
|
t.Errorf("'%s' was parsed but it is unsupported", tag)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestParseSupported(t *testing.T) {
|
|
|
|
for _, tag := range supported {
|
|
|
|
if _, err := tagcmp.Parse(tag); err != nil {
|
|
|
|
t.Errorf("'%s' was not parsed but it is supported", tag)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestParseRetainZeroes(t *testing.T) {
|
|
|
|
tag, err := tagcmp.Parse("18.04")
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("'18.04' should have parsed but didn't: %s", err)
|
|
|
|
}
|
|
|
|
if tag.Minor != "04" {
|
|
|
|
t.Errorf("parsing '18.04' didn't retain zeroes: %s", tag.Minor)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestDetectsV(t *testing.T) {
|
|
|
|
tag1, err := tagcmp.Parse("v2")
|
|
|
|
if !tag1.UsesV {
|
|
|
|
t.Error("'v2' uses 'v' but wasn't detected as such")
|
|
|
|
}
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("'v2' should have parsed but didn't: %s", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
tag2, err := tagcmp.Parse("2")
|
|
|
|
if tag2.UsesV {
|
|
|
|
t.Error("'v2' doesn't use 'v' but wasn't detected as such")
|
|
|
|
}
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("'2' should have parsed but didn't: %s", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestMissingParts(t *testing.T) {
|
|
|
|
tag1, err := tagcmp.Parse("v2")
|
|
|
|
if !tag1.MissingMinor || !tag1.MissingPatch {
|
|
|
|
t.Error("'v2' parsed without realising there are missing parts")
|
|
|
|
}
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("'v2' should have parsed but didn't: %s", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
tag2, err := tagcmp.Parse("v2.3")
|
|
|
|
if !tag2.MissingPatch {
|
|
|
|
t.Error("'v2.3' parsed without realising there are missing parts")
|
|
|
|
}
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("'v2.3' should have parsed but didn't: %s", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestMajorPart(t *testing.T) {
|
|
|
|
majors := map[string]string{
|
|
|
|
"1.2.3": "1",
|
|
|
|
"18.04": "18",
|
|
|
|
"10.1": "10",
|
|
|
|
"3": "3",
|
|
|
|
}
|
|
|
|
|
|
|
|
for m := range majors {
|
|
|
|
if p, _ := tagcmp.Parse(m); p.Major != majors[m] {
|
|
|
|
t.Errorf("'%s' didn't parse major part correctly: %s", m, p.Major)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestMinorPart(t *testing.T) {
|
|
|
|
minors := map[string]string{
|
|
|
|
"1.2.3": "2",
|
|
|
|
"18.04": "04",
|
|
|
|
"10.1": "1",
|
|
|
|
"3": "",
|
|
|
|
}
|
|
|
|
|
|
|
|
for m := range minors {
|
|
|
|
if p, _ := tagcmp.Parse(m); p.Minor != minors[m] {
|
|
|
|
t.Errorf("'%s' didn't parse minor part correctly: %s", m, p.Minor)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestPatchPart(t *testing.T) {
|
|
|
|
patches := map[string]string{
|
|
|
|
"1.2.3": "3",
|
|
|
|
"18.04": "",
|
|
|
|
"10.1": "",
|
|
|
|
"3": "",
|
|
|
|
}
|
|
|
|
|
|
|
|
for m := range patches {
|
|
|
|
if p, _ := tagcmp.Parse(m); p.Patch != patches[m] {
|
|
|
|
t.Errorf("'%s' didn't parse patch part correctly: %s", m, p.Patch)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-10-11 12:38:08 +00:00
|
|
|
func TestIsParsableSupported(t *testing.T) {
|
|
|
|
for _, tag := range supported {
|
|
|
|
if !tagcmp.IsParsable(tag) {
|
|
|
|
t.Errorf("'%s' should be parsable but IsParsable returned false", tag)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestIsParsableUnsupported(t *testing.T) {
|
|
|
|
for _, tag := range unsupported {
|
|
|
|
if tagcmp.IsParsable(tag) {
|
|
|
|
t.Errorf("'%s' should not be parsable but IsParsable returned true", tag)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-08-07 18:26:56 +00:00
|
|
|
func TestIsGreaterThan(t *testing.T) {
|
|
|
|
pairs := []struct {
|
|
|
|
t1 string
|
|
|
|
t2 string
|
|
|
|
expected bool
|
|
|
|
}{
|
|
|
|
{"1.2.3", "1.2", false},
|
2021-10-11 12:38:08 +00:00
|
|
|
{"1.2.3", "1.2.4", false},
|
2021-08-07 18:26:56 +00:00
|
|
|
{"18.04", "18.1", true},
|
|
|
|
{"10.1", "10.1.2", true},
|
|
|
|
{"3", "2", true},
|
|
|
|
{"1.2.3", "1.2.3", false},
|
|
|
|
}
|
|
|
|
for _, p := range pairs {
|
|
|
|
p1, err := tagcmp.Parse(p.t1)
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("'%s' should have parsed", p.t1)
|
|
|
|
}
|
|
|
|
p2, err := tagcmp.Parse(p.t2)
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("'%s' should have parsed", p.t2)
|
|
|
|
}
|
|
|
|
res := p1.IsGreaterThan(p2)
|
|
|
|
if res != p.expected {
|
|
|
|
t.Errorf("(%s).IsGreatherThan(%s) gave %t but expected %t", p.t1, p.t2, res, p.expected)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
func TestIsLessThan(t *testing.T) {
|
|
|
|
pairs := []struct {
|
|
|
|
t1 string
|
|
|
|
t2 string
|
|
|
|
expected bool
|
|
|
|
}{
|
|
|
|
{"1.2.3", "2.0", true},
|
|
|
|
{"18.04", "18.1", false},
|
|
|
|
{"10.1", "10.0.4", false},
|
|
|
|
{"3", "4.0", false},
|
|
|
|
{"1.2", "1.3.4", false},
|
|
|
|
{"0.0.1", "0.2.1", true},
|
|
|
|
{"0.0.1", "2.0.0", true},
|
|
|
|
{"1.3.9", "1.4.8", true},
|
|
|
|
{"v0.2.1", "v16.0.1", true},
|
|
|
|
}
|
|
|
|
for _, p := range pairs {
|
|
|
|
p1, err := tagcmp.Parse(p.t1)
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("'%s' should have parsed", p.t1)
|
|
|
|
}
|
|
|
|
p2, err := tagcmp.Parse(p.t2)
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("'%s' should have parsed", p.t2)
|
|
|
|
}
|
|
|
|
res := p1.IsLessThan(p2)
|
|
|
|
if res != p.expected {
|
|
|
|
t.Errorf("(%s).IsLessThan(%s) gave %t but expected %t", p.t1, p.t2, res, p.expected)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestEquals(t *testing.T) {
|
|
|
|
pairs := []struct {
|
|
|
|
t1 string
|
|
|
|
t2 string
|
|
|
|
expected bool
|
|
|
|
}{
|
|
|
|
{"1.2.3", "1.2.3", true},
|
2021-10-11 12:38:08 +00:00
|
|
|
{"1.2.3", "1.2", false},
|
|
|
|
{"1.2.3", "1", false},
|
2021-08-07 18:26:56 +00:00
|
|
|
{"18.04", "18.4", true},
|
|
|
|
{"10.0", "10.0.4", false},
|
|
|
|
{"3", "4.0", false},
|
|
|
|
{"1.2", "1.2.3", false},
|
2021-10-11 12:38:08 +00:00
|
|
|
{"3", "4", false},
|
|
|
|
{"1.3", "1.4", false},
|
|
|
|
{"3+FF812B", "3", false},
|
2021-08-07 18:26:56 +00:00
|
|
|
}
|
|
|
|
for _, p := range pairs {
|
|
|
|
p1, err := tagcmp.Parse(p.t1)
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("'%s' should have parsed", p.t1)
|
|
|
|
}
|
|
|
|
p2, err := tagcmp.Parse(p.t2)
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("'%s' should have parsed", p.t2)
|
|
|
|
}
|
|
|
|
res := p1.Equals(p2)
|
|
|
|
if res != p.expected {
|
|
|
|
t.Errorf("(%s).Equals(%s) gave %t but expected %t", p.t1, p.t2, res, p.expected)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestIsCompatible(t *testing.T) {
|
|
|
|
pairs := []struct {
|
|
|
|
t1 string
|
|
|
|
t2 string
|
|
|
|
expected bool
|
|
|
|
}{
|
|
|
|
{"v1", "v2", true},
|
|
|
|
{"v1", "v2.4", false},
|
|
|
|
{"1", "2", true},
|
|
|
|
{"2.3.4", "v2.3.4", false},
|
|
|
|
{"1.2.3", "1.2.6", true},
|
|
|
|
{"1.2.3", "1.2.0", true},
|
|
|
|
{"5-alpine", "6-alpine", true},
|
|
|
|
{"5-alpine", "6.5-alpine", false},
|
2021-08-09 13:05:03 +00:00
|
|
|
{"5", "5-alpine", false},
|
2021-08-07 18:26:56 +00:00
|
|
|
}
|
|
|
|
for _, p := range pairs {
|
|
|
|
p1, err := tagcmp.Parse(p.t1)
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("'%s' should have parsed", p.t1)
|
|
|
|
}
|
|
|
|
p2, err := tagcmp.Parse(p.t2)
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("'%s' should have parsed", p.t2)
|
|
|
|
}
|
|
|
|
res := p1.IsCompatible(p2)
|
|
|
|
if res != p.expected {
|
|
|
|
t.Errorf("(%s).IsCompatible(%s) gave %t but expected %t", p.t1, p.t2, res, p.expected)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-09-06 10:20:06 +00:00
|
|
|
func TestSortAsc1(t *testing.T) {
|
2021-08-07 18:26:56 +00:00
|
|
|
rawTags := []string{
|
|
|
|
"v1.4.8",
|
|
|
|
"v1.3.9",
|
|
|
|
"v2.0.0",
|
|
|
|
"v16.0.1",
|
|
|
|
"v0.0.1",
|
|
|
|
"v0.2.1",
|
|
|
|
"v5.9.1",
|
|
|
|
}
|
|
|
|
|
|
|
|
var tags []tagcmp.Tag
|
|
|
|
for _, rawTag := range rawTags {
|
|
|
|
tag, err := tagcmp.Parse(rawTag)
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("'%s' should have parsed but didn't: %s", tag, err)
|
|
|
|
}
|
|
|
|
tags = append(tags, tag)
|
|
|
|
}
|
|
|
|
|
2021-09-06 10:20:06 +00:00
|
|
|
sort.Sort(tagcmp.ByTagAsc(tags))
|
2021-08-07 18:26:56 +00:00
|
|
|
|
|
|
|
expected := []string{
|
|
|
|
"v0.0.1",
|
|
|
|
"v0.2.1",
|
|
|
|
"v1.3.9",
|
|
|
|
"v1.4.8",
|
|
|
|
"v2.0.0",
|
|
|
|
"v5.9.1",
|
|
|
|
"v16.0.1",
|
|
|
|
}
|
|
|
|
|
|
|
|
for idx, tag := range tags {
|
|
|
|
if tag.String() != expected[idx] {
|
|
|
|
t.Errorf("'%s' sorted out of order, saw '%s', expected '%s'", tag, tags, expected)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-09-06 10:20:06 +00:00
|
|
|
func TestSortAsc2(t *testing.T) {
|
2021-08-09 13:17:01 +00:00
|
|
|
rawTags := []string{
|
|
|
|
"10.0",
|
|
|
|
"10.6",
|
|
|
|
"10.2",
|
|
|
|
"10.1",
|
|
|
|
"10.5",
|
|
|
|
"5.5",
|
|
|
|
}
|
|
|
|
|
|
|
|
var tags []tagcmp.Tag
|
|
|
|
for _, rawTag := range rawTags {
|
|
|
|
tag, err := tagcmp.Parse(rawTag)
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("'%s' should have parsed but didn't: %s", tag, err)
|
|
|
|
}
|
|
|
|
tags = append(tags, tag)
|
|
|
|
}
|
|
|
|
|
2021-09-06 10:20:06 +00:00
|
|
|
sort.Sort(tagcmp.ByTagAsc(tags))
|
2021-08-09 13:17:01 +00:00
|
|
|
|
|
|
|
expected := []string{
|
|
|
|
"5.5",
|
|
|
|
"10.0",
|
|
|
|
"10.1",
|
|
|
|
"10.2",
|
|
|
|
"10.5",
|
|
|
|
"10.6",
|
|
|
|
}
|
|
|
|
|
|
|
|
for idx, tag := range tags {
|
|
|
|
if tag.String() != expected[idx] {
|
|
|
|
t.Errorf("'%s' sorted out of order, saw '%s', expected '%s'", tag, tags, expected)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-09-06 10:20:06 +00:00
|
|
|
func TestSortDesc(t *testing.T) {
|
|
|
|
rawTags := []string{
|
|
|
|
"10.0",
|
|
|
|
"10.6",
|
|
|
|
"10.2",
|
|
|
|
"10.1",
|
|
|
|
"10.5",
|
|
|
|
"5.5",
|
|
|
|
}
|
|
|
|
|
|
|
|
var tags []tagcmp.Tag
|
|
|
|
for _, rawTag := range rawTags {
|
|
|
|
tag, err := tagcmp.Parse(rawTag)
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("'%s' should have parsed but didn't: %s", tag, err)
|
|
|
|
}
|
|
|
|
tags = append(tags, tag)
|
|
|
|
}
|
|
|
|
|
|
|
|
sort.Sort(tagcmp.ByTagDesc(tags))
|
|
|
|
|
|
|
|
expected := []string{
|
|
|
|
"10.6",
|
|
|
|
"10.5",
|
|
|
|
"10.2",
|
|
|
|
"10.1",
|
|
|
|
"10.0",
|
|
|
|
"5.5",
|
|
|
|
}
|
|
|
|
|
|
|
|
for idx, tag := range tags {
|
|
|
|
if tag.String() != expected[idx] {
|
|
|
|
t.Errorf("'%s' sorted out of order, saw '%s', expected '%s'", tag, tags, expected)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-10-11 12:38:08 +00:00
|
|
|
func TestTagString(t *testing.T) {
|
2021-08-07 18:26:56 +00:00
|
|
|
for _, tag := range supported {
|
|
|
|
p, err := tagcmp.Parse(tag)
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("'%s' was not parsed but it is supported", tag)
|
|
|
|
}
|
|
|
|
if p.String() != tag {
|
|
|
|
t.Errorf("String() of '%s' didn't render properly: %s", tag, p.String())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestGiteaFilterCompatible(t *testing.T) {
|
|
|
|
expected := []string{
|
|
|
|
"1.14.0-rootless",
|
|
|
|
"1.14.1-rootless",
|
|
|
|
"1.14.2-rootless",
|
|
|
|
"1.14.3-rootless",
|
|
|
|
"1.14.4-rootless",
|
|
|
|
"1.14.5-rootless",
|
|
|
|
"1.14.6-rootless",
|
|
|
|
}
|
|
|
|
|
|
|
|
tag, err := tagcmp.Parse("1.14.0-rootless")
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("'1.14.0-rootless' should have parsed but didn't: %s", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
var filtered []tagcmp.Tag
|
|
|
|
for _, giteaTag := range giteaTags {
|
|
|
|
// not interested in unsupported tags right now
|
|
|
|
p, _ := tagcmp.Parse(giteaTag)
|
|
|
|
if tag.IsCompatible(p) {
|
|
|
|
filtered = append(filtered, p)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-09-06 10:20:06 +00:00
|
|
|
sort.Sort(tagcmp.ByTagAsc(filtered))
|
2021-08-07 18:26:56 +00:00
|
|
|
|
|
|
|
for idx, tag := range filtered {
|
|
|
|
if tag.String() != expected[idx] {
|
|
|
|
t.Errorf("'%s' out of order or incompatible, saw '%s', expected '%s'", tag, filtered, expected)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-10-11 12:38:08 +00:00
|
|
|
|
|
|
|
func TestDeltaParse(t *testing.T) {
|
|
|
|
supportedDeltas := []string{
|
|
|
|
"1",
|
|
|
|
"1.0",
|
|
|
|
"1.0.0",
|
|
|
|
"-1",
|
|
|
|
"-1.0",
|
|
|
|
"-1.0.0",
|
|
|
|
"-1.0.5",
|
|
|
|
"-1.2.5",
|
|
|
|
"1.-2",
|
|
|
|
}
|
|
|
|
unsupportedDeltas := []string{
|
|
|
|
"AAAAAAAAAAAAAAAA",
|
|
|
|
"1.2.3.4",
|
|
|
|
"1.ab.2",
|
|
|
|
"1.2.a",
|
|
|
|
}
|
|
|
|
for _, delta := range supportedDeltas {
|
|
|
|
if _, err := tagcmp.ParseDelta(delta); err != nil {
|
|
|
|
t.Errorf("'%s' wasn't parsed but it is supported: %s", delta, err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for _, delta := range unsupportedDeltas {
|
|
|
|
if _, err := tagcmp.ParseDelta(delta); err == nil {
|
|
|
|
t.Errorf("'%s' was parsed but it is not supported", delta)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestDeltaString(t *testing.T) {
|
|
|
|
supportedDeltas := []struct {
|
|
|
|
in string
|
|
|
|
out string
|
|
|
|
}{
|
|
|
|
{"1", "1.0.0"},
|
|
|
|
{"1.0", "1.0.0"},
|
|
|
|
{"1.0.0", "1.0.0"},
|
|
|
|
{"-1", "-1.0.0"},
|
|
|
|
{"-1.0", "-1.0.0"},
|
|
|
|
{"-1.0.0", "-1.0.0"},
|
|
|
|
{"-1.0.5", "-1.0.5"},
|
|
|
|
{"-1.2.5", "-1.2.5"},
|
|
|
|
{"1.-2", "1.-2.0"},
|
|
|
|
}
|
|
|
|
for _, test := range supportedDeltas {
|
|
|
|
parsedDelta, err := tagcmp.ParseDelta(test.in)
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("'%s' was not parsed but it is supported", test.in)
|
|
|
|
}
|
|
|
|
if parsedDelta.String() != test.out {
|
|
|
|
t.Errorf("String() of '%s' didn't render properly: %s", test.in, parsedDelta.String())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-01 09:48:47 +00:00
|
|
|
func TestIsUpgradeCompatible(t *testing.T) {
|
|
|
|
testsTrue := [][]string{
|
|
|
|
{"22-fpm", "22-fpm"},
|
|
|
|
{"22-fpm", "22.0-fpm"},
|
|
|
|
{"22-fpm", "22.0.0-fpm"},
|
|
|
|
{"22-fpm", "22.2.0-fpm"},
|
|
|
|
{"22-fpm", "22.0.0-fpm"},
|
|
|
|
{"22.2-fpm", "22.2-fpm"},
|
|
|
|
{"22.2-fpm", "22.2.0-fpm"},
|
|
|
|
{"22.2.2-fpm", "22.2.2-fpm"},
|
|
|
|
}
|
|
|
|
testsFalse := [][]string{
|
|
|
|
{"22-fpm", "22-alpine"},
|
|
|
|
{"22-fpm", "23-fpm"},
|
|
|
|
{"22-fpm", "21-fpm"},
|
|
|
|
{"22.2-fpm", "22.0.2-fpm"},
|
|
|
|
{"22.2.0-fpm", "22.2.2-fpm"},
|
|
|
|
}
|
|
|
|
for _, test := range testsTrue {
|
|
|
|
pin, err := tagcmp.Parse(test[0])
|
|
|
|
if err != nil {
|
|
|
|
t.Error(err)
|
|
|
|
}
|
|
|
|
upTag, err := tagcmp.Parse(test[1])
|
|
|
|
if err != nil {
|
|
|
|
t.Error(err)
|
|
|
|
}
|
|
|
|
if !pin.IsUpgradeCompatible(upTag) {
|
|
|
|
t.Errorf("pin %s should be upgradable to %s but returned false", test[0], test[1])
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for _, test := range testsFalse {
|
|
|
|
pin, err := tagcmp.Parse(test[0])
|
|
|
|
if err != nil {
|
|
|
|
t.Error(err)
|
|
|
|
}
|
|
|
|
upTag, err := tagcmp.Parse(test[1])
|
|
|
|
if err != nil {
|
|
|
|
t.Error(err)
|
|
|
|
}
|
|
|
|
if pin.IsUpgradeCompatible(upTag) {
|
|
|
|
t.Errorf("pin %s should not be upgradable to %s but returned true", test[0], test[1])
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-10-11 12:38:08 +00:00
|
|
|
func TestUpgradeDelta(t *testing.T) {
|
|
|
|
pairs := []struct {
|
|
|
|
t1 string
|
|
|
|
t2 string
|
|
|
|
expected string
|
|
|
|
throwsErr bool
|
|
|
|
}{
|
|
|
|
{"v1.0.0", "1.0.0", "", true},
|
|
|
|
{"1", "2", "1.0.0", false},
|
|
|
|
{"1.0", "1.1", "0.1.0", false},
|
|
|
|
{"1.1.0", "1.1.1", "0.0.1", false},
|
|
|
|
{"2", "1", "-1.0.0", false},
|
|
|
|
{"1.1", "1.0", "0.-1.0", false},
|
|
|
|
{"1.1.1", "1.1.0", "0.0.-1", false},
|
|
|
|
}
|
|
|
|
for _, p := range pairs {
|
|
|
|
p1, err := tagcmp.Parse(p.t1)
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("'%s' should have parsed", p.t1)
|
|
|
|
}
|
|
|
|
p2, err := tagcmp.Parse(p.t2)
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("'%s' should have parsed", p.t2)
|
|
|
|
}
|
|
|
|
pexpected, _ := tagcmp.ParseDelta(p.expected)
|
|
|
|
res, err := p1.UpgradeDelta(p2)
|
|
|
|
if p.throwsErr && (err == nil) {
|
|
|
|
t.Errorf("(%s).UpgradeDelta(%s) didn't throw an error but should have", p.t1, p.t2)
|
|
|
|
} else if !p.throwsErr && (err != nil) {
|
|
|
|
t.Errorf("(%s).UpgradeDelta(%s) threw an error but shouldn't have", p.t1, p.t2)
|
|
|
|
}
|
|
|
|
if res != pexpected {
|
|
|
|
t.Errorf("(%s).UpgradeDelta(%s) gave %s but expected %s", p.t1, p.t2, res.String(), p.expected)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestUpgradeType(t *testing.T) {
|
|
|
|
testSet := []struct {
|
|
|
|
in string
|
|
|
|
out int
|
|
|
|
}{
|
|
|
|
{"1.0.0", 4},
|
|
|
|
{"-1.0.0", -4},
|
|
|
|
{"1.2.0", 4},
|
|
|
|
{"-1.2.0", -4},
|
|
|
|
{"0.1.0", 2},
|
|
|
|
{"0.-1.0", -2},
|
|
|
|
{"0.1.2", 2},
|
|
|
|
{"0.-1.2", -2},
|
|
|
|
{"0.0.1", 1},
|
|
|
|
{"0.0.-1", -1},
|
|
|
|
{"0.0.0", 0},
|
|
|
|
{"-0.-0.-0", 0},
|
|
|
|
}
|
|
|
|
for _, test := range testSet {
|
|
|
|
tagDelta, err := tagcmp.ParseDelta(test.in)
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("tagcmp.ParseDelta couldn't parse '%s': '%s'", test.in, err)
|
|
|
|
}
|
|
|
|
upType := tagDelta.UpgradeType()
|
|
|
|
if upType != test.out {
|
|
|
|
t.Errorf("(%s).UpgradeType() returned '%d', expected '%d'", test.in, upType, test.out)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|