...

Source file src/github.com/blang/semver/v4/range_test.go

Documentation: github.com/blang/semver/v4

     1  package semver
     2  
     3  import (
     4  	"reflect"
     5  	"strings"
     6  	"testing"
     7  )
     8  
     9  type wildcardTypeTest struct {
    10  	input        string
    11  	wildcardType wildcardType
    12  }
    13  
    14  type comparatorTest struct {
    15  	input      string
    16  	comparator func(comparator) bool
    17  }
    18  
    19  func TestParseComparator(t *testing.T) {
    20  	compatorTests := []comparatorTest{
    21  		{">", testGT},
    22  		{">=", testGE},
    23  		{"<", testLT},
    24  		{"<=", testLE},
    25  		{"", testEQ},
    26  		{"=", testEQ},
    27  		{"==", testEQ},
    28  		{"!=", testNE},
    29  		{"!", testNE},
    30  		{"-", nil},
    31  		{"<==", nil},
    32  		{"<<", nil},
    33  		{">>", nil},
    34  	}
    35  
    36  	for _, tc := range compatorTests {
    37  		if c := parseComparator(tc.input); c == nil {
    38  			if tc.comparator != nil {
    39  				t.Errorf("Comparator nil for case %q\n", tc.input)
    40  			}
    41  		} else if !tc.comparator(c) {
    42  			t.Errorf("Invalid comparator for case %q\n", tc.input)
    43  		}
    44  	}
    45  }
    46  
    47  var (
    48  	v1 = MustParse("1.2.2")
    49  	v2 = MustParse("1.2.3")
    50  	v3 = MustParse("1.2.4")
    51  )
    52  
    53  func testEQ(f comparator) bool {
    54  	return f(v1, v1) && !f(v1, v2)
    55  }
    56  
    57  func testNE(f comparator) bool {
    58  	return !f(v1, v1) && f(v1, v2)
    59  }
    60  
    61  func testGT(f comparator) bool {
    62  	return f(v2, v1) && f(v3, v2) && !f(v1, v2) && !f(v1, v1)
    63  }
    64  
    65  func testGE(f comparator) bool {
    66  	return f(v2, v1) && f(v3, v2) && !f(v1, v2)
    67  }
    68  
    69  func testLT(f comparator) bool {
    70  	return f(v1, v2) && f(v2, v3) && !f(v2, v1) && !f(v1, v1)
    71  }
    72  
    73  func testLE(f comparator) bool {
    74  	return f(v1, v2) && f(v2, v3) && !f(v2, v1)
    75  }
    76  
    77  func TestSplitAndTrim(t *testing.T) {
    78  	tests := []struct {
    79  		i string
    80  		s []string
    81  	}{
    82  		{"1.2.3 1.2.3", []string{"1.2.3", "1.2.3"}},
    83  		{"     1.2.3     1.2.3     ", []string{"1.2.3", "1.2.3"}},       // Spaces
    84  		{"  >=   1.2.3   <=  1.2.3   ", []string{">=1.2.3", "<=1.2.3"}}, // Spaces between operator and version
    85  		{"1.2.3 || >=1.2.3 <1.2.3", []string{"1.2.3", "||", ">=1.2.3", "<1.2.3"}},
    86  		{"      1.2.3      ||     >=1.2.3     <1.2.3    ", []string{"1.2.3", "||", ">=1.2.3", "<1.2.3"}},
    87  	}
    88  
    89  	for _, tc := range tests {
    90  		p := splitAndTrim(tc.i)
    91  		if !reflect.DeepEqual(p, tc.s) {
    92  			t.Errorf("Invalid for case %q: Expected %q, got: %q", tc.i, tc.s, p)
    93  		}
    94  	}
    95  }
    96  
    97  func TestSplitComparatorVersion(t *testing.T) {
    98  	tests := []struct {
    99  		i string
   100  		p []string
   101  	}{
   102  		{">1.2.3", []string{">", "1.2.3"}},
   103  		{">=1.2.3", []string{">=", "1.2.3"}},
   104  		{"<1.2.3", []string{"<", "1.2.3"}},
   105  		{"<=1.2.3", []string{"<=", "1.2.3"}},
   106  		{"1.2.3", []string{"", "1.2.3"}},
   107  		{"=1.2.3", []string{"=", "1.2.3"}},
   108  		{"==1.2.3", []string{"==", "1.2.3"}},
   109  		{"!=1.2.3", []string{"!=", "1.2.3"}},
   110  		{"!1.2.3", []string{"!", "1.2.3"}},
   111  		{"error", nil},
   112  	}
   113  	for _, tc := range tests {
   114  		if op, v, err := splitComparatorVersion(tc.i); err != nil {
   115  			if tc.p != nil {
   116  				t.Errorf("Invalid for case %q: Expected %q, got error %q", tc.i, tc.p, err)
   117  			}
   118  		} else if op != tc.p[0] {
   119  			t.Errorf("Invalid operator for case %q: Expected %q, got: %q", tc.i, tc.p[0], op)
   120  		} else if v != tc.p[1] {
   121  			t.Errorf("Invalid version for case %q: Expected %q, got: %q", tc.i, tc.p[1], v)
   122  		}
   123  
   124  	}
   125  }
   126  
   127  func TestBuildVersionRange(t *testing.T) {
   128  	tests := []struct {
   129  		opStr string
   130  		vStr  string
   131  		c     func(comparator) bool
   132  		v     string
   133  	}{
   134  		{">", "1.2.3", testGT, "1.2.3"},
   135  		{">=", "1.2.3", testGE, "1.2.3"},
   136  		{"<", "1.2.3", testLT, "1.2.3"},
   137  		{"<=", "1.2.3", testLE, "1.2.3"},
   138  		{"", "1.2.3", testEQ, "1.2.3"},
   139  		{"=", "1.2.3", testEQ, "1.2.3"},
   140  		{"==", "1.2.3", testEQ, "1.2.3"},
   141  		{"!=", "1.2.3", testNE, "1.2.3"},
   142  		{"!", "1.2.3", testNE, "1.2.3"},
   143  		{">>", "1.2.3", nil, ""},  // Invalid comparator
   144  		{"=", "invalid", nil, ""}, // Invalid version
   145  	}
   146  
   147  	for _, tc := range tests {
   148  		if r, err := buildVersionRange(tc.opStr, tc.vStr); err != nil {
   149  			if tc.c != nil {
   150  				t.Errorf("Invalid for case %q: Expected %q, got error %q", strings.Join([]string{tc.opStr, tc.vStr}, ""), tc.v, err)
   151  			}
   152  		} else if r == nil {
   153  			t.Errorf("Invalid for case %q: got nil", strings.Join([]string{tc.opStr, tc.vStr}, ""))
   154  		} else {
   155  			// test version
   156  			if tv := MustParse(tc.v); !r.v.EQ(tv) {
   157  				t.Errorf("Invalid for case %q: Expected version %q, got: %q", strings.Join([]string{tc.opStr, tc.vStr}, ""), tv, r.v)
   158  			}
   159  			// test comparator
   160  			if r.c == nil {
   161  				t.Errorf("Invalid for case %q: got nil comparator", strings.Join([]string{tc.opStr, tc.vStr}, ""))
   162  				continue
   163  			}
   164  			if !tc.c(r.c) {
   165  				t.Errorf("Invalid comparator for case %q\n", strings.Join([]string{tc.opStr, tc.vStr}, ""))
   166  			}
   167  		}
   168  	}
   169  
   170  }
   171  
   172  func TestSplitORParts(t *testing.T) {
   173  	tests := []struct {
   174  		i []string
   175  		o [][]string
   176  	}{
   177  		{[]string{">1.2.3", "||", "<1.2.3", "||", "=1.2.3"}, [][]string{
   178  			{">1.2.3"},
   179  			{"<1.2.3"},
   180  			{"=1.2.3"},
   181  		}},
   182  		{[]string{">1.2.3", "<1.2.3", "||", "=1.2.3"}, [][]string{
   183  			{">1.2.3", "<1.2.3"},
   184  			{"=1.2.3"},
   185  		}},
   186  		{[]string{">1.2.3", "||"}, nil},
   187  		{[]string{"||", ">1.2.3"}, nil},
   188  	}
   189  	for _, tc := range tests {
   190  		o, err := splitORParts(tc.i)
   191  		if err != nil && tc.o != nil {
   192  			t.Errorf("Unexpected error for case %q: %s", tc.i, err)
   193  		}
   194  		if !reflect.DeepEqual(tc.o, o) {
   195  			t.Errorf("Invalid for case %q: Expected %q, got: %q", tc.i, tc.o, o)
   196  		}
   197  	}
   198  }
   199  
   200  func TestGetWildcardType(t *testing.T) {
   201  	wildcardTypeTests := []wildcardTypeTest{
   202  		{"x", majorWildcard},
   203  		{"1.x", minorWildcard},
   204  		{"1.2.x", patchWildcard},
   205  		{"fo.o.b.ar", noneWildcard},
   206  	}
   207  
   208  	for _, tc := range wildcardTypeTests {
   209  		o := getWildcardType(tc.input)
   210  		if o != tc.wildcardType {
   211  			t.Errorf("Invalid for case: %q: Expected %q, got: %q", tc.input, tc.wildcardType, o)
   212  		}
   213  	}
   214  }
   215  
   216  func TestCreateVersionFromWildcard(t *testing.T) {
   217  	tests := []struct {
   218  		i string
   219  		s string
   220  	}{
   221  		{"1.2.x", "1.2.0"},
   222  		{"1.x", "1.0.0"},
   223  	}
   224  
   225  	for _, tc := range tests {
   226  		p := createVersionFromWildcard(tc.i)
   227  		if p != tc.s {
   228  			t.Errorf("Invalid for case %q: Expected %q, got: %q", tc.i, tc.s, p)
   229  		}
   230  	}
   231  }
   232  
   233  func TestIncrementMajorVersion(t *testing.T) {
   234  	tests := []struct {
   235  		i string
   236  		s string
   237  	}{
   238  		{"1.2.3", "2.2.3"},
   239  		{"1.2", "2.2"},
   240  		{"foo.bar", ""},
   241  	}
   242  
   243  	for _, tc := range tests {
   244  		p, _ := incrementMajorVersion(tc.i)
   245  		if p != tc.s {
   246  			t.Errorf("Invalid for case %q: Expected %q, got: %q", tc.i, tc.s, p)
   247  		}
   248  	}
   249  }
   250  
   251  func TestIncrementMinorVersion(t *testing.T) {
   252  	tests := []struct {
   253  		i string
   254  		s string
   255  	}{
   256  		{"1.2.3", "1.3.3"},
   257  		{"1.2", "1.3"},
   258  		{"foo.bar", ""},
   259  	}
   260  
   261  	for _, tc := range tests {
   262  		p, _ := incrementMinorVersion(tc.i)
   263  		if p != tc.s {
   264  			t.Errorf("Invalid for case %q: Expected %q, got: %q", tc.i, tc.s, p)
   265  		}
   266  	}
   267  }
   268  
   269  func TestExpandWildcardVersion(t *testing.T) {
   270  	tests := []struct {
   271  		i [][]string
   272  		o [][]string
   273  	}{
   274  		{[][]string{{"foox"}}, nil},
   275  		{[][]string{{">=1.2.x"}}, [][]string{{">=1.2.0"}}},
   276  		{[][]string{{"<=1.2.x"}}, [][]string{{"<1.3.0"}}},
   277  		{[][]string{{">1.2.x"}}, [][]string{{">=1.3.0"}}},
   278  		{[][]string{{"<1.2.x"}}, [][]string{{"<1.2.0"}}},
   279  		{[][]string{{"!=1.2.x"}}, [][]string{{"<1.2.0", ">=1.3.0"}}},
   280  		{[][]string{{">=1.x"}}, [][]string{{">=1.0.0"}}},
   281  		{[][]string{{"<=1.x"}}, [][]string{{"<2.0.0"}}},
   282  		{[][]string{{">1.x"}}, [][]string{{">=2.0.0"}}},
   283  		{[][]string{{"<1.x"}}, [][]string{{"<1.0.0"}}},
   284  		{[][]string{{"!=1.x"}}, [][]string{{"<1.0.0", ">=2.0.0"}}},
   285  		{[][]string{{"1.2.x"}}, [][]string{{">=1.2.0", "<1.3.0"}}},
   286  		{[][]string{{"1.x"}}, [][]string{{">=1.0.0", "<2.0.0"}}},
   287  	}
   288  
   289  	for _, tc := range tests {
   290  		o, _ := expandWildcardVersion(tc.i)
   291  		if !reflect.DeepEqual(tc.o, o) {
   292  			t.Errorf("Invalid for case %q: Expected %q, got: %q", tc.i, tc.o, o)
   293  		}
   294  	}
   295  }
   296  
   297  func TestVersionRangeToRange(t *testing.T) {
   298  	vr := versionRange{
   299  		v: MustParse("1.2.3"),
   300  		c: compLT,
   301  	}
   302  	rf := vr.rangeFunc()
   303  	if !rf(MustParse("1.2.2")) || rf(MustParse("1.2.3")) {
   304  		t.Errorf("Invalid conversion to range func")
   305  	}
   306  }
   307  
   308  func TestRangeAND(t *testing.T) {
   309  	v := MustParse("1.2.2")
   310  	v1 := MustParse("1.2.1")
   311  	v2 := MustParse("1.2.3")
   312  	rf1 := Range(func(v Version) bool {
   313  		return v.GT(v1)
   314  	})
   315  	rf2 := Range(func(v Version) bool {
   316  		return v.LT(v2)
   317  	})
   318  	rf := rf1.AND(rf2)
   319  	if rf(v1) {
   320  		t.Errorf("Invalid rangefunc, accepted: %s", v1)
   321  	}
   322  	if rf(v2) {
   323  		t.Errorf("Invalid rangefunc, accepted: %s", v2)
   324  	}
   325  	if !rf(v) {
   326  		t.Errorf("Invalid rangefunc, did not accept: %s", v)
   327  	}
   328  }
   329  
   330  func TestRangeOR(t *testing.T) {
   331  	tests := []struct {
   332  		v Version
   333  		b bool
   334  	}{
   335  		{MustParse("1.2.0"), true},
   336  		{MustParse("1.2.2"), false},
   337  		{MustParse("1.2.4"), true},
   338  	}
   339  	v1 := MustParse("1.2.1")
   340  	v2 := MustParse("1.2.3")
   341  	rf1 := Range(func(v Version) bool {
   342  		return v.LT(v1)
   343  	})
   344  	rf2 := Range(func(v Version) bool {
   345  		return v.GT(v2)
   346  	})
   347  	rf := rf1.OR(rf2)
   348  	for _, tc := range tests {
   349  		if r := rf(tc.v); r != tc.b {
   350  			t.Errorf("Invalid for case %q: Expected %t, got %t", tc.v, tc.b, r)
   351  		}
   352  	}
   353  }
   354  
   355  func TestParseRange(t *testing.T) {
   356  	type tv struct {
   357  		v string
   358  		b bool
   359  	}
   360  	tests := []struct {
   361  		i string
   362  		t []tv
   363  	}{
   364  		// Simple expressions
   365  		{">1.2.3", []tv{
   366  			{"1.2.2", false},
   367  			{"1.2.3", false},
   368  			{"1.2.4", true},
   369  		}},
   370  		{">=1.2.3", []tv{
   371  			{"1.2.3", true},
   372  			{"1.2.4", true},
   373  			{"1.2.2", false},
   374  		}},
   375  		{"<1.2.3", []tv{
   376  			{"1.2.2", true},
   377  			{"1.2.3", false},
   378  			{"1.2.4", false},
   379  		}},
   380  		{"<=1.2.3", []tv{
   381  			{"1.2.2", true},
   382  			{"1.2.3", true},
   383  			{"1.2.4", false},
   384  		}},
   385  		{"1.2.3", []tv{
   386  			{"1.2.2", false},
   387  			{"1.2.3", true},
   388  			{"1.2.4", false},
   389  		}},
   390  		{"=1.2.3", []tv{
   391  			{"1.2.2", false},
   392  			{"1.2.3", true},
   393  			{"1.2.4", false},
   394  		}},
   395  		{"==1.2.3", []tv{
   396  			{"1.2.2", false},
   397  			{"1.2.3", true},
   398  			{"1.2.4", false},
   399  		}},
   400  		{"!=1.2.3", []tv{
   401  			{"1.2.2", true},
   402  			{"1.2.3", false},
   403  			{"1.2.4", true},
   404  		}},
   405  		{"!1.2.3", []tv{
   406  			{"1.2.2", true},
   407  			{"1.2.3", false},
   408  			{"1.2.4", true},
   409  		}},
   410  		// Simple Expression errors
   411  		{">>1.2.3", nil},
   412  		{"!1.2.3", nil},
   413  		{"1.0", nil},
   414  		{"string", nil},
   415  		{"", nil},
   416  		{"fo.ob.ar.x", nil},
   417  		// AND Expressions
   418  		{">1.2.2 <1.2.4", []tv{
   419  			{"1.2.2", false},
   420  			{"1.2.3", true},
   421  			{"1.2.4", false},
   422  		}},
   423  		{"<1.2.2 <1.2.4", []tv{
   424  			{"1.2.1", true},
   425  			{"1.2.2", false},
   426  			{"1.2.3", false},
   427  			{"1.2.4", false},
   428  		}},
   429  		{">1.2.2 <1.2.5 !=1.2.4", []tv{
   430  			{"1.2.2", false},
   431  			{"1.2.3", true},
   432  			{"1.2.4", false},
   433  			{"1.2.5", false},
   434  		}},
   435  		{">1.2.2 <1.2.5 !1.2.4", []tv{
   436  			{"1.2.2", false},
   437  			{"1.2.3", true},
   438  			{"1.2.4", false},
   439  			{"1.2.5", false},
   440  		}},
   441  		// OR Expressions
   442  		{">1.2.2 || <1.2.4", []tv{
   443  			{"1.2.2", true},
   444  			{"1.2.3", true},
   445  			{"1.2.4", true},
   446  		}},
   447  		{"<1.2.2 || >1.2.4", []tv{
   448  			{"1.2.2", false},
   449  			{"1.2.3", false},
   450  			{"1.2.4", false},
   451  		}},
   452  		// Wildcard expressions
   453  		{">1.x", []tv{
   454  			{"0.1.9", false},
   455  			{"1.2.6", false},
   456  			{"1.9.0", false},
   457  			{"2.0.0", true},
   458  		}},
   459  		{">1.2.x", []tv{
   460  			{"1.1.9", false},
   461  			{"1.2.6", false},
   462  			{"1.3.0", true},
   463  		}},
   464  		// Combined Expressions
   465  		{">1.2.2 <1.2.4 || >=2.0.0", []tv{
   466  			{"1.2.2", false},
   467  			{"1.2.3", true},
   468  			{"1.2.4", false},
   469  			{"2.0.0", true},
   470  			{"2.0.1", true},
   471  		}},
   472  		{"1.x || >=2.0.x <2.2.x", []tv{
   473  			{"0.9.2", false},
   474  			{"1.2.2", true},
   475  			{"2.0.0", true},
   476  			{"2.1.8", true},
   477  			{"2.2.0", false},
   478  		}},
   479  		{">1.2.2 <1.2.4 || >=2.0.0 <3.0.0", []tv{
   480  			{"1.2.2", false},
   481  			{"1.2.3", true},
   482  			{"1.2.4", false},
   483  			{"2.0.0", true},
   484  			{"2.0.1", true},
   485  			{"2.9.9", true},
   486  			{"3.0.0", false},
   487  		}},
   488  	}
   489  
   490  	for _, tc := range tests {
   491  		r, err := ParseRange(tc.i)
   492  		if err != nil && tc.t != nil {
   493  			t.Errorf("Error parsing range %q: %s", tc.i, err)
   494  			continue
   495  		}
   496  		for _, tvc := range tc.t {
   497  			v := MustParse(tvc.v)
   498  			if res := r(v); res != tvc.b {
   499  				t.Errorf("Invalid for case %q matching %q: Expected %t, got: %t", tc.i, tvc.v, tvc.b, res)
   500  			}
   501  		}
   502  
   503  	}
   504  }
   505  
   506  func TestMustParseRange(t *testing.T) {
   507  	testCase := ">1.2.2 <1.2.4 || >=2.0.0 <3.0.0"
   508  	r := MustParseRange(testCase)
   509  	if !r(MustParse("1.2.3")) {
   510  		t.Errorf("Unexpected range behavior on MustParseRange")
   511  	}
   512  }
   513  
   514  func TestMustParseRange_panic(t *testing.T) {
   515  	defer func() {
   516  		if recover() == nil {
   517  			t.Errorf("Should have panicked")
   518  		}
   519  	}()
   520  	_ = MustParseRange("invalid version")
   521  }
   522  
   523  func BenchmarkRangeParseSimple(b *testing.B) {
   524  	const VERSION = ">1.0.0"
   525  	b.ReportAllocs()
   526  	b.ResetTimer()
   527  	for n := 0; n < b.N; n++ {
   528  		_, _ = ParseRange(VERSION)
   529  	}
   530  }
   531  
   532  func BenchmarkRangeParseAverage(b *testing.B) {
   533  	const VERSION = ">=1.0.0 <2.0.0"
   534  	b.ReportAllocs()
   535  	b.ResetTimer()
   536  	for n := 0; n < b.N; n++ {
   537  		_, _ = ParseRange(VERSION)
   538  	}
   539  }
   540  
   541  func BenchmarkRangeParseComplex(b *testing.B) {
   542  	const VERSION = ">=1.0.0 <2.0.0 || >=3.0.1 <4.0.0 !=3.0.3 || >=5.0.0"
   543  	b.ReportAllocs()
   544  	b.ResetTimer()
   545  	for n := 0; n < b.N; n++ {
   546  		_, _ = ParseRange(VERSION)
   547  	}
   548  }
   549  
   550  func BenchmarkRangeMatchSimple(b *testing.B) {
   551  	const VERSION = ">1.0.0"
   552  	r, _ := ParseRange(VERSION)
   553  	v := MustParse("2.0.0")
   554  	b.ReportAllocs()
   555  	b.ResetTimer()
   556  	for n := 0; n < b.N; n++ {
   557  		r(v)
   558  	}
   559  }
   560  
   561  func BenchmarkRangeMatchAverage(b *testing.B) {
   562  	const VERSION = ">=1.0.0 <2.0.0"
   563  	r, _ := ParseRange(VERSION)
   564  	v := MustParse("1.2.3")
   565  	b.ReportAllocs()
   566  	b.ResetTimer()
   567  	for n := 0; n < b.N; n++ {
   568  		r(v)
   569  	}
   570  }
   571  
   572  func BenchmarkRangeMatchComplex(b *testing.B) {
   573  	const VERSION = ">=1.0.0 <2.0.0 || >=3.0.1 <4.0.0 !=3.0.3 || >=5.0.0"
   574  	r, _ := ParseRange(VERSION)
   575  	v := MustParse("5.0.1")
   576  	b.ReportAllocs()
   577  	b.ResetTimer()
   578  	for n := 0; n < b.N; n++ {
   579  		r(v)
   580  	}
   581  }
   582  

View as plain text