add version constraints
This commit is contained in:
@@ -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...
|
||||||
|
}
|
||||||
@@ -3,6 +3,19 @@ package version
|
|||||||
// List is a slice of versions that implements sort.Interface.
|
// List is a slice of versions that implements sort.Interface.
|
||||||
type List []*Version
|
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 {
|
func (list List) Len() int {
|
||||||
return len(list)
|
return len(list)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
@@ -40,6 +40,40 @@ func (a *Version) Compare(b *Version) int {
|
|||||||
return -1
|
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).
|
// 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.
|
// This function returns true if a is less than b, or false otherwise.
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user