Merge pull request #53 from hashicorp/f-lte-gte

Implement GreaterThanOrEqual + LessThanOrEqual
diff --git a/.travis.yml b/.travis.yml
index 542ca8b..01c5dc2 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,13 +1,13 @@
 language: go 
 
 go: 
-  - 1.0
-  - 1.1 
   - 1.2
   - 1.3
   - 1.4
   - 1.9
   - "1.10"
+  - 1.11
+  - 1.12
   
 script:
   - go test 
diff --git a/version.go b/version.go
index 186fd7c..1032c56 100644
--- a/version.go
+++ b/version.go
@@ -112,7 +112,7 @@
 // or larger than the other version, respectively.
 //
 // If you want boolean results, use the LessThan, Equal,
-// or GreaterThan methods.
+// GreaterThan, GreaterThanOrEqual or LessThanOrEqual methods.
 func (v *Version) Compare(other *Version) int {
 	// A quick, efficient equality check
 	if v.String() == other.String() {
@@ -288,11 +288,21 @@
 	return v.Compare(o) > 0
 }
 
+// GreaterThanOrEqualTo tests if this version is greater than or equal to another version.
+func (v *Version) GreaterThanOrEqual(o *Version) bool {
+	return v.Compare(o) >= 0
+}
+
 // LessThan tests if this version is less than another version.
 func (v *Version) LessThan(o *Version) bool {
 	return v.Compare(o) < 0
 }
 
+// LessThanOrEqualTo tests if this version is less than or equal to another version.
+func (v *Version) LessThanOrEqual(o *Version) bool {
+	return v.Compare(o) <= 0
+}
+
 // Metadata returns any metadata that was part of the version
 // string.
 //
diff --git a/version_test.go b/version_test.go
index 0e8ee27..bd3534a 100644
--- a/version_test.go
+++ b/version_test.go
@@ -361,3 +361,238 @@
 		}
 	}
 }
+
+func TestEqual(t *testing.T) {
+	cases := []struct {
+		v1       string
+		v2       string
+		expected bool
+	}{
+		{"1.2.3", "1.4.5", false},
+		{"1.2-beta", "1.2-beta", true},
+		{"1.2", "1.1.4", false},
+		{"1.2", "1.2-beta", false},
+		{"1.2+foo", "1.2+beta", true},
+		{"v1.2", "v1.2-beta", false},
+		{"v1.2+foo", "v1.2+beta", true},
+		{"v1.2.3.4", "v1.2.3.4", true},
+		{"v1.2.0.0", "v1.2", true},
+		{"v1.2.0.0.1", "v1.2", false},
+		{"v1.2", "v1.2.0.0", true},
+		{"v1.2", "v1.2.0.0.1", false},
+		{"v1.2.0.0", "v1.2.0.0.1", false},
+		{"v1.2.3.0", "v1.2.3.4", false},
+		{"1.7rc2", "1.7rc1", false},
+		{"1.7rc2", "1.7", false},
+		{"1.2.0", "1.2.0-X-1.2.0+metadata~dist", false},
+	}
+
+	for _, tc := range cases {
+		v1, err := NewVersion(tc.v1)
+		if err != nil {
+			t.Fatalf("err: %s", err)
+		}
+
+		v2, err := NewVersion(tc.v2)
+		if err != nil {
+			t.Fatalf("err: %s", err)
+		}
+
+		actual := v1.Equal(v2)
+		expected := tc.expected
+		if actual != expected {
+			t.Fatalf(
+				"%s <=> %s\nexpected: %t\nactual: %t",
+				tc.v1, tc.v2,
+				expected, actual)
+		}
+	}
+}
+
+func TestGreaterThan(t *testing.T) {
+	cases := []struct {
+		v1       string
+		v2       string
+		expected bool
+	}{
+		{"1.2.3", "1.4.5", false},
+		{"1.2-beta", "1.2-beta", false},
+		{"1.2", "1.1.4", true},
+		{"1.2", "1.2-beta", true},
+		{"1.2+foo", "1.2+beta", false},
+		{"v1.2", "v1.2-beta", true},
+		{"v1.2+foo", "v1.2+beta", false},
+		{"v1.2.3.4", "v1.2.3.4", false},
+		{"v1.2.0.0", "v1.2", false},
+		{"v1.2.0.0.1", "v1.2", true},
+		{"v1.2", "v1.2.0.0", false},
+		{"v1.2", "v1.2.0.0.1", false},
+		{"v1.2.0.0", "v1.2.0.0.1", false},
+		{"v1.2.3.0", "v1.2.3.4", false},
+		{"1.7rc2", "1.7rc1", true},
+		{"1.7rc2", "1.7", false},
+		{"1.2.0", "1.2.0-X-1.2.0+metadata~dist", true},
+	}
+
+	for _, tc := range cases {
+		v1, err := NewVersion(tc.v1)
+		if err != nil {
+			t.Fatalf("err: %s", err)
+		}
+
+		v2, err := NewVersion(tc.v2)
+		if err != nil {
+			t.Fatalf("err: %s", err)
+		}
+
+		actual := v1.GreaterThan(v2)
+		expected := tc.expected
+		if actual != expected {
+			t.Fatalf(
+				"%s > %s\nexpected: %t\nactual: %t",
+				tc.v1, tc.v2,
+				expected, actual)
+		}
+	}
+}
+
+func TestLessThan(t *testing.T) {
+	cases := []struct {
+		v1       string
+		v2       string
+		expected bool
+	}{
+		{"1.2.3", "1.4.5", true},
+		{"1.2-beta", "1.2-beta", false},
+		{"1.2", "1.1.4", false},
+		{"1.2", "1.2-beta", false},
+		{"1.2+foo", "1.2+beta", false},
+		{"v1.2", "v1.2-beta", false},
+		{"v1.2+foo", "v1.2+beta", false},
+		{"v1.2.3.4", "v1.2.3.4", false},
+		{"v1.2.0.0", "v1.2", false},
+		{"v1.2.0.0.1", "v1.2", false},
+		{"v1.2", "v1.2.0.0", false},
+		{"v1.2", "v1.2.0.0.1", true},
+		{"v1.2.0.0", "v1.2.0.0.1", true},
+		{"v1.2.3.0", "v1.2.3.4", true},
+		{"1.7rc2", "1.7rc1", false},
+		{"1.7rc2", "1.7", true},
+		{"1.2.0", "1.2.0-X-1.2.0+metadata~dist", false},
+	}
+
+	for _, tc := range cases {
+		v1, err := NewVersion(tc.v1)
+		if err != nil {
+			t.Fatalf("err: %s", err)
+		}
+
+		v2, err := NewVersion(tc.v2)
+		if err != nil {
+			t.Fatalf("err: %s", err)
+		}
+
+		actual := v1.LessThan(v2)
+		expected := tc.expected
+		if actual != expected {
+			t.Fatalf(
+				"%s < %s\nexpected: %t\nactual: %t",
+				tc.v1, tc.v2,
+				expected, actual)
+		}
+	}
+}
+
+func TestGreaterThanOrEqual(t *testing.T) {
+	cases := []struct {
+		v1       string
+		v2       string
+		expected bool
+	}{
+		{"1.2.3", "1.4.5", false},
+		{"1.2-beta", "1.2-beta", true},
+		{"1.2", "1.1.4", true},
+		{"1.2", "1.2-beta", true},
+		{"1.2+foo", "1.2+beta", true},
+		{"v1.2", "v1.2-beta", true},
+		{"v1.2+foo", "v1.2+beta", true},
+		{"v1.2.3.4", "v1.2.3.4", true},
+		{"v1.2.0.0", "v1.2", true},
+		{"v1.2.0.0.1", "v1.2", true},
+		{"v1.2", "v1.2.0.0", true},
+		{"v1.2", "v1.2.0.0.1", false},
+		{"v1.2.0.0", "v1.2.0.0.1", false},
+		{"v1.2.3.0", "v1.2.3.4", false},
+		{"1.7rc2", "1.7rc1", true},
+		{"1.7rc2", "1.7", false},
+		{"1.2.0", "1.2.0-X-1.2.0+metadata~dist", true},
+	}
+
+	for _, tc := range cases {
+		v1, err := NewVersion(tc.v1)
+		if err != nil {
+			t.Fatalf("err: %s", err)
+		}
+
+		v2, err := NewVersion(tc.v2)
+		if err != nil {
+			t.Fatalf("err: %s", err)
+		}
+
+		actual := v1.GreaterThanOrEqual(v2)
+		expected := tc.expected
+		if actual != expected {
+			t.Fatalf(
+				"%s >= %s\nexpected: %t\nactual: %t",
+				tc.v1, tc.v2,
+				expected, actual)
+		}
+	}
+}
+
+func TestLessThanOrEqual(t *testing.T) {
+	cases := []struct {
+		v1       string
+		v2       string
+		expected bool
+	}{
+		{"1.2.3", "1.4.5", true},
+		{"1.2-beta", "1.2-beta", true},
+		{"1.2", "1.1.4", false},
+		{"1.2", "1.2-beta", false},
+		{"1.2+foo", "1.2+beta", true},
+		{"v1.2", "v1.2-beta", false},
+		{"v1.2+foo", "v1.2+beta", true},
+		{"v1.2.3.4", "v1.2.3.4", true},
+		{"v1.2.0.0", "v1.2", true},
+		{"v1.2.0.0.1", "v1.2", false},
+		{"v1.2", "v1.2.0.0", true},
+		{"v1.2", "v1.2.0.0.1", true},
+		{"v1.2.0.0", "v1.2.0.0.1", true},
+		{"v1.2.3.0", "v1.2.3.4", true},
+		{"1.7rc2", "1.7rc1", false},
+		{"1.7rc2", "1.7", true},
+		{"1.2.0", "1.2.0-X-1.2.0+metadata~dist", false},
+	}
+
+	for _, tc := range cases {
+		v1, err := NewVersion(tc.v1)
+		if err != nil {
+			t.Fatalf("err: %s", err)
+		}
+
+		v2, err := NewVersion(tc.v2)
+		if err != nil {
+			t.Fatalf("err: %s", err)
+		}
+
+		actual := v1.LessThanOrEqual(v2)
+		expected := tc.expected
+		if actual != expected {
+			t.Fatalf(
+				"%s <= %s\nexpected: %t\nactual: %t",
+				tc.v1, tc.v2,
+				expected, actual)
+		}
+	}
+}