summaryrefslogtreecommitdiffstats
path: root/client
diff options
context:
space:
mode:
authorMartin Polden <mpolden@mpolden.no>2021-09-17 15:05:19 +0200
committerMartin Polden <mpolden@mpolden.no>2021-09-20 14:35:29 +0200
commitc561c995b715c73e83c90b66904a2de70c737c71 (patch)
tree2e608751586a6ab5efc233857f9dca78c0af24d9 /client
parent0dd24fccd012608867b9ff0c7378044855d99cdb (diff)
Implement version package
Diffstat (limited to 'client')
-rw-r--r--client/go/version/version.go61
-rw-r--r--client/go/version/version_test.go59
2 files changed, 120 insertions, 0 deletions
diff --git a/client/go/version/version.go b/client/go/version/version.go
new file mode 100644
index 00000000000..e0dc8bf39ae
--- /dev/null
+++ b/client/go/version/version.go
@@ -0,0 +1,61 @@
+package version
+
+import (
+ "fmt"
+ "strconv"
+ "strings"
+)
+
+// Version represents a semantic version number.
+type Version struct {
+ Major int
+ Minor int
+ Patch int
+}
+
+func (v Version) String() string { return fmt.Sprintf("%d.%d.%d", v.Major, v.Minor, v.Patch) }
+
+// Compare returns a positive integer if v1 is greater than v2, a negative integer if v1 is less than v2 and zero if they
+// are equal.
+func (v1 Version) Compare(v2 Version) int {
+ result := v1.Major - v2.Major
+ if result != 0 {
+ return result
+ }
+ result = v1.Minor - v2.Minor
+ if result != 0 {
+ return result
+ }
+ result = v1.Patch - v2.Patch
+ if result != 0 {
+ return result
+ }
+ return 0
+}
+
+// Less returns true if v1 is lower than v2.
+func (v1 Version) Less(v2 Version) bool { return v1.Compare(v2) < 0 }
+
+// Parse parses a semantic version number from string s.
+func Parse(s string) (Version, error) {
+ if len(s) > 0 && s[0] == 'v' {
+ s = s[1:] // Trim v prefix
+ }
+ parts := strings.Split(s, ".")
+ if len(parts) != 3 {
+ return Version{}, fmt.Errorf("invalid version number: %s", s)
+ }
+ major, err := strconv.Atoi(parts[0])
+ if err != nil {
+ return Version{}, fmt.Errorf("invalid major version: %s", parts[0])
+ }
+ minor, err := strconv.Atoi(parts[1])
+ if err != nil {
+ return Version{}, fmt.Errorf("invalid minor version: %s", parts[1])
+ }
+ patch, err := strconv.Atoi(parts[2])
+ if err != nil {
+ return Version{}, fmt.Errorf("invalid patch version: %s", parts[2])
+ }
+ return Version{Major: major, Minor: minor, Patch: patch}, nil
+}
diff --git a/client/go/version/version_test.go b/client/go/version/version_test.go
new file mode 100644
index 00000000000..6cfb82ed802
--- /dev/null
+++ b/client/go/version/version_test.go
@@ -0,0 +1,59 @@
+package version
+
+import (
+ "fmt"
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+)
+
+func TestParse(t *testing.T) {
+ _, err := Parse("foo")
+ assert.NotNil(t, err)
+
+ _, err = Parse("1.2.3-foo") // Labels are unsupported
+ assert.NotNil(t, err)
+
+ v, err := Parse("1.2.3")
+ assert.Nil(t, err)
+ assert.Equal(t, "1.2.3", v.String())
+
+ v, err = Parse("v4.5.6")
+ assert.Nil(t, err)
+ assert.Equal(t, "4.5.6", v.String())
+}
+
+func TestCompare(t *testing.T) {
+ assertComparison(t, "1.2.3", '>', "1.0.0")
+ assertComparison(t, "1.0.0", '<', "1.2.3")
+
+ assertComparison(t, "1.2.3", '=', "1.2.3")
+ assertComparison(t, "1.2.3", '>', "1.2.0")
+ assertComparison(t, "1.2.0", '<', "1.2.3")
+ assertComparison(t, "1.2.3", '>', "1.2.0")
+ assertComparison(t, "1.0.3", '<', "1.2.3")
+
+ assertComparison(t, "1.2.3", '>', "1.1.4")
+ assertComparison(t, "1.1.4", '<', "1.2.3")
+
+ assertComparison(t, "2.0.0", '>', "1.2.3")
+ assertComparison(t, "1.2.3", '<', "2.0.0")
+}
+
+func assertComparison(t *testing.T, s1 string, cmp rune, s2 string) {
+ v1, err := Parse(s1)
+ assert.Nil(t, err)
+ v2, err := Parse(s2)
+ assert.Nil(t, err)
+ result := v1.Compare(v2)
+ switch cmp {
+ case '<':
+ assert.True(t, result < 0, fmt.Sprintf("%s is less than %s", v1, v2))
+ case '>':
+ assert.True(t, result > 0, fmt.Sprintf("%s is greater than %s", v1, v2))
+ case '=':
+ assert.True(t, result == 0, fmt.Sprintf("%s is equal to %s", v1, v2))
+ default:
+ t.Fatal("invalid comparator: %r", cmp)
+ }
+}