Add unit tests for version utility functions
Test coverage for pure functions in internal/updates/version.go: - Version.String() - 6 test cases - Version.Compare() - 14 test cases (major/minor/patch/prerelease) - Version.IsNewerThan() - 4 test cases - Version.IsPrerelease() - 4 test cases - compareInts() - 7 test cases - extractRCNumber() - 12 test cases - envBool() - 17 test cases - sanitizePrereleaseIdentifier() - 14 test cases Coverage: 35.2% -> 35.9%
This commit is contained in:
parent
9f2798cc96
commit
6267554b74
1 changed files with 377 additions and 0 deletions
|
|
@ -146,3 +146,380 @@ func TestDetectChannelFromVersion(t *testing.T) {
|
|||
t.Fatalf("detectChannelFromVersion stable = %s, expected stable", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestVersionString(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
version Version
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
name: "basic version",
|
||||
version: Version{Major: 4, Minor: 24, Patch: 0},
|
||||
expected: "4.24.0",
|
||||
},
|
||||
{
|
||||
name: "with prerelease",
|
||||
version: Version{Major: 4, Minor: 24, Patch: 0, Prerelease: "rc.3"},
|
||||
expected: "4.24.0-rc.3",
|
||||
},
|
||||
{
|
||||
name: "with build metadata",
|
||||
version: Version{Major: 4, Minor: 24, Patch: 0, Build: "build.123"},
|
||||
expected: "4.24.0+build.123",
|
||||
},
|
||||
{
|
||||
name: "with prerelease and build",
|
||||
version: Version{Major: 4, Minor: 24, Patch: 0, Prerelease: "rc.3", Build: "build.123"},
|
||||
expected: "4.24.0-rc.3+build.123",
|
||||
},
|
||||
{
|
||||
name: "zero version",
|
||||
version: Version{Major: 0, Minor: 0, Patch: 0},
|
||||
expected: "0.0.0",
|
||||
},
|
||||
{
|
||||
name: "large numbers",
|
||||
version: Version{Major: 100, Minor: 200, Patch: 300},
|
||||
expected: "100.200.300",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
tc := tc
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
if got := tc.version.String(); got != tc.expected {
|
||||
t.Fatalf("Version.String() = %q, expected %q", got, tc.expected)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestVersionCompare(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
v1 Version
|
||||
v2 Version
|
||||
expected int
|
||||
}{
|
||||
{
|
||||
name: "equal versions",
|
||||
v1: Version{Major: 4, Minor: 24, Patch: 0},
|
||||
v2: Version{Major: 4, Minor: 24, Patch: 0},
|
||||
expected: 0,
|
||||
},
|
||||
{
|
||||
name: "v1 major greater",
|
||||
v1: Version{Major: 5, Minor: 0, Patch: 0},
|
||||
v2: Version{Major: 4, Minor: 24, Patch: 0},
|
||||
expected: 1,
|
||||
},
|
||||
{
|
||||
name: "v1 major less",
|
||||
v1: Version{Major: 3, Minor: 99, Patch: 99},
|
||||
v2: Version{Major: 4, Minor: 0, Patch: 0},
|
||||
expected: -1,
|
||||
},
|
||||
{
|
||||
name: "v1 minor greater",
|
||||
v1: Version{Major: 4, Minor: 25, Patch: 0},
|
||||
v2: Version{Major: 4, Minor: 24, Patch: 0},
|
||||
expected: 1,
|
||||
},
|
||||
{
|
||||
name: "v1 minor less",
|
||||
v1: Version{Major: 4, Minor: 23, Patch: 99},
|
||||
v2: Version{Major: 4, Minor: 24, Patch: 0},
|
||||
expected: -1,
|
||||
},
|
||||
{
|
||||
name: "v1 patch greater",
|
||||
v1: Version{Major: 4, Minor: 24, Patch: 1},
|
||||
v2: Version{Major: 4, Minor: 24, Patch: 0},
|
||||
expected: 1,
|
||||
},
|
||||
{
|
||||
name: "v1 patch less",
|
||||
v1: Version{Major: 4, Minor: 24, Patch: 0},
|
||||
v2: Version{Major: 4, Minor: 24, Patch: 1},
|
||||
expected: -1,
|
||||
},
|
||||
{
|
||||
name: "release > prerelease",
|
||||
v1: Version{Major: 4, Minor: 24, Patch: 0},
|
||||
v2: Version{Major: 4, Minor: 24, Patch: 0, Prerelease: "rc.1"},
|
||||
expected: 1,
|
||||
},
|
||||
{
|
||||
name: "prerelease < release",
|
||||
v1: Version{Major: 4, Minor: 24, Patch: 0, Prerelease: "rc.1"},
|
||||
v2: Version{Major: 4, Minor: 24, Patch: 0},
|
||||
expected: -1,
|
||||
},
|
||||
{
|
||||
name: "RC comparison - rc.9 > rc.1",
|
||||
v1: Version{Major: 4, Minor: 24, Patch: 0, Prerelease: "rc.9"},
|
||||
v2: Version{Major: 4, Minor: 24, Patch: 0, Prerelease: "rc.1"},
|
||||
expected: 1,
|
||||
},
|
||||
{
|
||||
name: "RC comparison - rc.1 < rc.9",
|
||||
v1: Version{Major: 4, Minor: 24, Patch: 0, Prerelease: "rc.1"},
|
||||
v2: Version{Major: 4, Minor: 24, Patch: 0, Prerelease: "rc.9"},
|
||||
expected: -1,
|
||||
},
|
||||
{
|
||||
name: "RC comparison - rc9 format",
|
||||
v1: Version{Major: 4, Minor: 24, Patch: 0, Prerelease: "rc9"},
|
||||
v2: Version{Major: 4, Minor: 24, Patch: 0, Prerelease: "rc1"},
|
||||
expected: 1,
|
||||
},
|
||||
{
|
||||
name: "equal prereleases",
|
||||
v1: Version{Major: 4, Minor: 24, Patch: 0, Prerelease: "rc.3"},
|
||||
v2: Version{Major: 4, Minor: 24, Patch: 0, Prerelease: "rc.3"},
|
||||
expected: 0,
|
||||
},
|
||||
{
|
||||
name: "string prerelease comparison",
|
||||
v1: Version{Major: 4, Minor: 24, Patch: 0, Prerelease: "beta"},
|
||||
v2: Version{Major: 4, Minor: 24, Patch: 0, Prerelease: "alpha"},
|
||||
expected: 1, // "beta" > "alpha" lexically
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
tc := tc
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
if got := tc.v1.Compare(&tc.v2); got != tc.expected {
|
||||
t.Fatalf("(%v).Compare(%v) = %d, expected %d", tc.v1, tc.v2, got, tc.expected)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestVersionIsNewerThan(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
v1 Version
|
||||
v2 Version
|
||||
expected bool
|
||||
}{
|
||||
{
|
||||
name: "newer version",
|
||||
v1: Version{Major: 5, Minor: 0, Patch: 0},
|
||||
v2: Version{Major: 4, Minor: 24, Patch: 0},
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "older version",
|
||||
v1: Version{Major: 4, Minor: 0, Patch: 0},
|
||||
v2: Version{Major: 4, Minor: 24, Patch: 0},
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
name: "equal versions",
|
||||
v1: Version{Major: 4, Minor: 24, Patch: 0},
|
||||
v2: Version{Major: 4, Minor: 24, Patch: 0},
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
name: "release newer than prerelease",
|
||||
v1: Version{Major: 4, Minor: 24, Patch: 0},
|
||||
v2: Version{Major: 4, Minor: 24, Patch: 0, Prerelease: "rc.1"},
|
||||
expected: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
tc := tc
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
if got := tc.v1.IsNewerThan(&tc.v2); got != tc.expected {
|
||||
t.Fatalf("(%v).IsNewerThan(%v) = %v, expected %v", tc.v1, tc.v2, got, tc.expected)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestVersionIsPrerelease(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
version Version
|
||||
expected bool
|
||||
}{
|
||||
{
|
||||
name: "release version",
|
||||
version: Version{Major: 4, Minor: 24, Patch: 0},
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
name: "prerelease version",
|
||||
version: Version{Major: 4, Minor: 24, Patch: 0, Prerelease: "rc.1"},
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "alpha prerelease",
|
||||
version: Version{Major: 1, Minor: 0, Patch: 0, Prerelease: "alpha"},
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "build metadata only is not prerelease",
|
||||
version: Version{Major: 4, Minor: 24, Patch: 0, Build: "build.123"},
|
||||
expected: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
tc := tc
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
if got := tc.version.IsPrerelease(); got != tc.expected {
|
||||
t.Fatalf("(%v).IsPrerelease() = %v, expected %v", tc.version, got, tc.expected)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestCompareInts(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
a int
|
||||
b int
|
||||
expected int
|
||||
}{
|
||||
{name: "a < b", a: 1, b: 2, expected: -1},
|
||||
{name: "a > b", a: 2, b: 1, expected: 1},
|
||||
{name: "a == b", a: 1, b: 1, expected: 0},
|
||||
{name: "negative numbers a < b", a: -2, b: -1, expected: -1},
|
||||
{name: "negative numbers a > b", a: -1, b: -2, expected: 1},
|
||||
{name: "zero comparisons", a: 0, b: 1, expected: -1},
|
||||
{name: "large numbers", a: 1000000, b: 1000001, expected: -1},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
tc := tc
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
if got := compareInts(tc.a, tc.b); got != tc.expected {
|
||||
t.Fatalf("compareInts(%d, %d) = %d, expected %d", tc.a, tc.b, got, tc.expected)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestExtractRCNumber(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
prerelease string
|
||||
expected int
|
||||
}{
|
||||
{name: "rc.1", prerelease: "rc.1", expected: 1},
|
||||
{name: "rc.9", prerelease: "rc.9", expected: 9},
|
||||
{name: "rc1", prerelease: "rc1", expected: 1},
|
||||
{name: "rc9", prerelease: "rc9", expected: 9},
|
||||
{name: "RC.3 uppercase", prerelease: "RC.3", expected: 3},
|
||||
{name: "RC5 uppercase no dot", prerelease: "RC5", expected: 5},
|
||||
{name: "rc.10 double digit", prerelease: "rc.10", expected: 10},
|
||||
{name: "rc.123 triple digit", prerelease: "rc.123", expected: 123},
|
||||
{name: "alpha no RC", prerelease: "alpha", expected: -1},
|
||||
{name: "beta.1 no RC", prerelease: "beta.1", expected: -1},
|
||||
{name: "empty string", prerelease: "", expected: -1},
|
||||
{name: "just rc no number", prerelease: "rc", expected: -1},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
tc := tc
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
if got := extractRCNumber(tc.prerelease); got != tc.expected {
|
||||
t.Fatalf("extractRCNumber(%q) = %d, expected %d", tc.prerelease, got, tc.expected)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestEnvBool(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
value string
|
||||
expected bool
|
||||
}{
|
||||
{name: "1 is true", value: "1", expected: true},
|
||||
{name: "true is true", value: "true", expected: true},
|
||||
{name: "TRUE is true", value: "TRUE", expected: true},
|
||||
{name: "True is true", value: "True", expected: true},
|
||||
{name: "yes is true", value: "yes", expected: true},
|
||||
{name: "YES is true", value: "YES", expected: true},
|
||||
{name: "on is true", value: "on", expected: true},
|
||||
{name: "ON is true", value: "ON", expected: true},
|
||||
{name: "0 is false", value: "0", expected: false},
|
||||
{name: "false is false", value: "false", expected: false},
|
||||
{name: "FALSE is false", value: "FALSE", expected: false},
|
||||
{name: "no is false", value: "no", expected: false},
|
||||
{name: "off is false", value: "off", expected: false},
|
||||
{name: "empty is false", value: "", expected: false},
|
||||
{name: "random string is false", value: "random", expected: false},
|
||||
{name: "whitespace true", value: " true ", expected: true},
|
||||
{name: "whitespace 1", value: " 1 ", expected: true},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
key := "TEST_ENV_BOOL_" + tc.name
|
||||
t.Setenv(key, tc.value)
|
||||
if got := envBool(key); got != tc.expected {
|
||||
t.Fatalf("envBool(%q) with value %q = %v, expected %v", key, tc.value, got, tc.expected)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestSanitizePrereleaseIdentifier(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
input string
|
||||
expected string
|
||||
}{
|
||||
{name: "simple branch", input: "feature-x", expected: "feature-x"},
|
||||
{name: "branch with slash", input: "feature/new-api", expected: "feature-new-api"},
|
||||
{name: "branch with multiple slashes", input: "user/feature/test", expected: "user-feature-test"},
|
||||
{name: "uppercase converts to lowercase", input: "FEATURE-X", expected: "feature-x"},
|
||||
{name: "mixed case", input: "Feature-X", expected: "feature-x"},
|
||||
{name: "numbers preserved", input: "issue-123", expected: "issue-123"},
|
||||
{name: "dots preserved", input: "v1.2.3", expected: "v1.2.3"},
|
||||
{name: "special chars replaced", input: "feat@test#123", expected: "feat-test-123"},
|
||||
{name: "consecutive separators collapsed", input: "feature//test", expected: "feature-test"},
|
||||
{name: "leading separator trimmed", input: "-feature", expected: "feature"},
|
||||
{name: "trailing separator trimmed", input: "feature-", expected: "feature"},
|
||||
{name: "empty string", input: "", expected: "dev"},
|
||||
{name: "whitespace only", input: " ", expected: "dev"},
|
||||
{name: "only special chars", input: "@#$%", expected: "dev"},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
tc := tc
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
if got := sanitizePrereleaseIdentifier(tc.input); got != tc.expected {
|
||||
t.Fatalf("sanitizePrereleaseIdentifier(%q) = %q, expected %q", tc.input, got, tc.expected)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue