فهرست منبع

add version constraints

Aneurin Barker Snook 11 ماه پیش
والد
کامیت
33d31f84be
5فایلهای تغییر یافته به همراه185 افزوده شده و 0 حذف شده
  1. 9 0
      constraint.go
  2. 13 0
      list.go
  3. 48 0
      list_test.go
  4. 34 0
      version.go
  5. 81 0
      version_test.go

+ 9 - 0
constraint.go

@@ -0,0 +1,9 @@
+package version
+
+// Constraint enables matching a version based on lower and upper bounds.
+type Constraint struct {
+	Gt  *Version // Greater than...
+	Gte *Version // Greater than or equal to...
+	Lt  *Version // Less than...
+	Lte *Version // Less than or equal to...
+}

+ 13 - 0
list.go

@@ -3,6 +3,19 @@ package version
 // List is a slice of versions that implements sort.Interface.
 type List []*Version
 
+// Match tests versions against a constraint and returns a new List of matching versions only.
+func (list List) Match(c *Constraint) List {
+	filtered := List{}
+
+	for _, v := range list {
+		if v.Match(c) {
+			filtered = append(filtered, v)
+		}
+	}
+
+	return filtered
+}
+
 func (list List) Len() int {
 	return len(list)
 }

+ 48 - 0
list_test.go

@@ -47,3 +47,51 @@ func TestListSort(t *testing.T) {
 		}
 	}
 }
+
+func TestList_Match(t *testing.T) {
+	type TestCase struct {
+		Input      List
+		Constraint *Constraint
+		Expected   List
+	}
+
+	testCases := []TestCase{
+		{
+			Input:    List{MustParse("1.0.0"), MustParse("1.1.0"), MustParse("2.0.2"), MustParse("3.4.5")},
+			Expected: List{MustParse("1.0.0"), MustParse("1.1.0"), MustParse("2.0.2"), MustParse("3.4.5")},
+		},
+		{
+			Input:      List{MustParse("1.0.0"), MustParse("1.1.0"), MustParse("2.0.2"), MustParse("3.4.5")},
+			Constraint: &Constraint{Gt: MustParse("1.0.0")},
+			Expected:   List{MustParse("1.1.0"), MustParse("2.0.2"), MustParse("3.4.5")},
+		},
+		{
+			Input:      List{MustParse("1.0.0"), MustParse("1.1.0"), MustParse("2.0.2"), MustParse("3.4.5")},
+			Constraint: &Constraint{Lt: MustParse("3.0.0")},
+			Expected:   List{MustParse("1.0.0"), MustParse("1.1.0"), MustParse("2.0.2")},
+		},
+		{
+			Input:      List{MustParse("1.0.0"), MustParse("1.1.0"), MustParse("2.0.2"), MustParse("3.4.5")},
+			Constraint: &Constraint{Gte: MustParse("2.0.2")},
+			Expected:   List{MustParse("2.0.2"), MustParse("3.4.5")},
+		},
+	}
+
+	for i, testCase := range testCases {
+		actual := testCase.Input.Match(testCase.Constraint)
+
+		ok := true
+		for j, v := range actual {
+			expected := testCase.Expected[j]
+			cmp := v.Compare(expected)
+			if cmp != 0 {
+				ok = false
+				t.Errorf("test %d failed at position %d (expected %s, got %s)", i, j, expected, actual)
+			}
+		}
+
+		if ok {
+			t.Logf("test %d passed", i)
+		}
+	}
+}

+ 34 - 0
version.go

@@ -40,6 +40,40 @@ func (a *Version) Compare(b *Version) int {
 	return -1
 }
 
+// Match tests the version against a constraint.
+// Gt and Lt take precedence over Gte and Lte.
+func (v *Version) Match(c *Constraint) bool {
+	if v == nil {
+		return false
+	}
+
+	if c == nil {
+		return true
+	}
+
+	if c.Gt != nil {
+		if v.Compare(c.Gt) <= 0 {
+			return false
+		}
+	} else if c.Gte != nil {
+		if v.Compare(c.Gte) < 0 {
+			return false
+		}
+	}
+
+	if c.Lt != nil {
+		if v.Compare(c.Lt) >= 0 {
+			return false
+		}
+	} else if c.Lte != nil {
+		if v.Compare(c.Lte) > 0 {
+			return false
+		}
+	}
+
+	return true
+}
+
 // Less performs a simple comparison of this version (a) with another version (b).
 // This function returns true if a is less than b, or false otherwise.
 //

+ 81 - 0
version_test.go

@@ -102,3 +102,84 @@ func TestVersion_Less(t *testing.T) {
 		}
 	}
 }
+
+func TestVersion_Match(t *testing.T) {
+	type TestCase struct {
+		V        *Version
+		C        *Constraint
+		Expected bool
+	}
+
+	testCases := []TestCase{
+		{V: MustParse("1.0.0"), Expected: true},
+		{V: MustParse("1.0.0"), C: &Constraint{Gt: MustParse("0.1.0")}, Expected: true},
+		{V: MustParse("1.0.0"), C: &Constraint{Gt: MustParse("1.0.0")}, Expected: false},
+		{V: MustParse("1.0.0"), C: &Constraint{Gt: MustParse("1.1.0")}, Expected: false},
+		{V: MustParse("1.0.0"), C: &Constraint{Gte: MustParse("0.1.0")}, Expected: true},
+		{V: MustParse("1.0.0"), C: &Constraint{Gte: MustParse("1.0.0")}, Expected: true},
+		{V: MustParse("1.0.0"), C: &Constraint{Gte: MustParse("1.1.0")}, Expected: false},
+		{V: MustParse("1.0.0"), C: &Constraint{Lt: MustParse("0.1.0")}, Expected: false},
+		{V: MustParse("1.0.0"), C: &Constraint{Lt: MustParse("1.0.0")}, Expected: false},
+		{V: MustParse("1.0.0"), C: &Constraint{Lt: MustParse("1.1.0")}, Expected: true},
+		{V: MustParse("1.0.0"), C: &Constraint{Lte: MustParse("0.1.0")}, Expected: false},
+		{V: MustParse("1.0.0"), C: &Constraint{Lte: MustParse("1.0.0")}, Expected: true},
+		{V: MustParse("1.0.0"), C: &Constraint{Lte: MustParse("1.1.0")}, Expected: true},
+
+		{V: MustParse("1.0.0"), C: &Constraint{Gt: MustParse("0.1.0"), Lt: MustParse("0.1.0")}, Expected: false},
+		{V: MustParse("1.0.0"), C: &Constraint{Gt: MustParse("0.1.0"), Lt: MustParse("1.0.0")}, Expected: false},
+		{V: MustParse("1.0.0"), C: &Constraint{Gt: MustParse("0.1.0"), Lt: MustParse("1.1.0")}, Expected: true},
+		{V: MustParse("1.0.0"), C: &Constraint{Gt: MustParse("1.0.0"), Lt: MustParse("0.1.0")}, Expected: false},
+		{V: MustParse("1.0.0"), C: &Constraint{Gt: MustParse("1.0.0"), Lt: MustParse("1.0.0")}, Expected: false},
+		{V: MustParse("1.0.0"), C: &Constraint{Gt: MustParse("1.0.0"), Lt: MustParse("1.1.0")}, Expected: false},
+		{V: MustParse("1.0.0"), C: &Constraint{Gt: MustParse("1.1.0"), Lt: MustParse("0.1.0")}, Expected: false},
+		{V: MustParse("1.0.0"), C: &Constraint{Gt: MustParse("1.1.0"), Lt: MustParse("1.0.0")}, Expected: false},
+		{V: MustParse("1.0.0"), C: &Constraint{Gt: MustParse("1.1.0"), Lt: MustParse("1.1.0")}, Expected: false},
+
+		{V: MustParse("1.0.0"), C: &Constraint{Gt: MustParse("0.1.0"), Lte: MustParse("0.1.0")}, Expected: false},
+		{V: MustParse("1.0.0"), C: &Constraint{Gt: MustParse("0.1.0"), Lte: MustParse("1.0.0")}, Expected: true},
+		{V: MustParse("1.0.0"), C: &Constraint{Gt: MustParse("0.1.0"), Lte: MustParse("1.1.0")}, Expected: true},
+		{V: MustParse("1.0.0"), C: &Constraint{Gt: MustParse("1.0.0"), Lte: MustParse("0.1.0")}, Expected: false},
+		{V: MustParse("1.0.0"), C: &Constraint{Gt: MustParse("1.0.0"), Lte: MustParse("1.0.0")}, Expected: false},
+		{V: MustParse("1.0.0"), C: &Constraint{Gt: MustParse("1.0.0"), Lte: MustParse("1.1.0")}, Expected: false},
+		{V: MustParse("1.0.0"), C: &Constraint{Gt: MustParse("1.1.0"), Lte: MustParse("0.1.0")}, Expected: false},
+		{V: MustParse("1.0.0"), C: &Constraint{Gt: MustParse("1.1.0"), Lte: MustParse("1.0.0")}, Expected: false},
+		{V: MustParse("1.0.0"), C: &Constraint{Gt: MustParse("1.1.0"), Lte: MustParse("1.1.0")}, Expected: false},
+
+		{V: MustParse("1.0.0"), C: &Constraint{Gte: MustParse("0.1.0"), Lt: MustParse("0.1.0")}, Expected: false},
+		{V: MustParse("1.0.0"), C: &Constraint{Gte: MustParse("0.1.0"), Lt: MustParse("1.0.0")}, Expected: false},
+		{V: MustParse("1.0.0"), C: &Constraint{Gte: MustParse("0.1.0"), Lt: MustParse("1.1.0")}, Expected: true},
+		{V: MustParse("1.0.0"), C: &Constraint{Gte: MustParse("1.0.0"), Lt: MustParse("0.1.0")}, Expected: false},
+		{V: MustParse("1.0.0"), C: &Constraint{Gte: MustParse("1.0.0"), Lt: MustParse("1.0.0")}, Expected: false},
+		{V: MustParse("1.0.0"), C: &Constraint{Gte: MustParse("1.0.0"), Lt: MustParse("1.1.0")}, Expected: true},
+		{V: MustParse("1.0.0"), C: &Constraint{Gte: MustParse("1.1.0"), Lt: MustParse("0.1.0")}, Expected: false},
+		{V: MustParse("1.0.0"), C: &Constraint{Gte: MustParse("1.1.0"), Lt: MustParse("1.0.0")}, Expected: false},
+		{V: MustParse("1.0.0"), C: &Constraint{Gte: MustParse("1.1.0"), Lt: MustParse("1.1.0")}, Expected: false},
+
+		{V: MustParse("1.0.0"), C: &Constraint{Gte: MustParse("0.1.0"), Lte: MustParse("0.1.0")}, Expected: false},
+		{V: MustParse("1.0.0"), C: &Constraint{Gte: MustParse("0.1.0"), Lte: MustParse("1.0.0")}, Expected: true},
+		{V: MustParse("1.0.0"), C: &Constraint{Gte: MustParse("0.1.0"), Lte: MustParse("1.1.0")}, Expected: true},
+		{V: MustParse("1.0.0"), C: &Constraint{Gte: MustParse("1.0.0"), Lte: MustParse("0.1.0")}, Expected: false},
+		{V: MustParse("1.0.0"), C: &Constraint{Gte: MustParse("1.0.0"), Lte: MustParse("1.0.0")}, Expected: true},
+		{V: MustParse("1.0.0"), C: &Constraint{Gte: MustParse("1.0.0"), Lte: MustParse("1.1.0")}, Expected: true},
+		{V: MustParse("1.0.0"), C: &Constraint{Gte: MustParse("1.1.0"), Lte: MustParse("0.1.0")}, Expected: false},
+		{V: MustParse("1.0.0"), C: &Constraint{Gte: MustParse("1.1.0"), Lte: MustParse("1.0.0")}, Expected: false},
+		{V: MustParse("1.0.0"), C: &Constraint{Gte: MustParse("1.1.0"), Lte: MustParse("1.1.0")}, Expected: false},
+
+		{V: MustParse("1.0.0"), C: &Constraint{Gt: MustParse("1.0.0"), Gte: MustParse("1.0.0")}, Expected: false},
+		{V: MustParse("1.0.0"), C: &Constraint{Gt: MustParse("0.1.0"), Gte: MustParse("1.1.0")}, Expected: true},
+		{V: MustParse("1.0.0"), C: &Constraint{Gt: MustParse("1.1.0"), Gte: MustParse("0.1.0")}, Expected: false},
+
+		{V: MustParse("1.0.0"), C: &Constraint{Lt: MustParse("1.0.0"), Lte: MustParse("1.0.0")}, Expected: false},
+		{V: MustParse("1.0.0"), C: &Constraint{Lt: MustParse("0.1.0"), Lte: MustParse("1.1.0")}, Expected: false},
+		{V: MustParse("1.0.0"), C: &Constraint{Lt: MustParse("1.1.0"), Lte: MustParse("0.1.0")}, Expected: true},
+	}
+
+	for i, testCase := range testCases {
+		actual := testCase.V.Match(testCase.C)
+		if actual != testCase.Expected {
+			t.Errorf("test %d failed (expected %v, actual %v)", i, testCase.Expected, actual)
+		} else {
+			t.Logf("test %d passed with %v", i, actual)
+		}
+	}
+}