github.com/snyk/vervet/v6@v6.2.4/version_test.go (about)

     1  package vervet_test
     2  
     3  import (
     4  	"fmt"
     5  	"testing"
     6  	"time"
     7  
     8  	qt "github.com/frankban/quicktest"
     9  
    10  	. "github.com/snyk/vervet/v6"
    11  )
    12  
    13  func TestParseVersion(t *testing.T) {
    14  	c := qt.New(t)
    15  	tests := []struct {
    16  		vs   string
    17  		d    string
    18  		stab Stability
    19  		err  string
    20  	}{{
    21  		vs:   "2021-01-01",
    22  		d:    "2021-01-01",
    23  		stab: StabilityGA,
    24  	}, {
    25  		vs:   "2021-02-02~beta",
    26  		d:    "2021-02-02",
    27  		stab: StabilityBeta,
    28  	}, {
    29  		vs:   "2021-03-03~experimental",
    30  		d:    "2021-03-03",
    31  		stab: StabilityExperimental,
    32  	}, {
    33  		vs:  "unknown",
    34  		err: `invalid version "unknown"`,
    35  	}}
    36  	for i := range tests {
    37  		c.Logf("parse version %q", tests[i].vs)
    38  		v, err := ParseVersion(tests[i].vs)
    39  		if tests[i].err != "" {
    40  			c.Assert(err, qt.ErrorMatches, tests[i].err)
    41  			c.Assert(func() { MustParseVersion(tests[i].vs) }, qt.PanicMatches, tests[i].err)
    42  		} else {
    43  			c.Assert(v.Date.Format("2006-01-02"), qt.Equals, tests[i].d)
    44  			c.Assert(v.Stability, qt.Equals, tests[i].stab)
    45  		}
    46  	}
    47  }
    48  
    49  func TestVersionStringPanics(t *testing.T) {
    50  	c := qt.New(t)
    51  	var v Version
    52  	c.Assert(func() {
    53  		c.Log(v.String())
    54  	}, qt.PanicMatches, "invalid stability.*")
    55  	var s Stability
    56  	c.Assert(func() {
    57  		c.Log(s.String())
    58  	}, qt.PanicMatches, "invalid stability.*")
    59  }
    60  
    61  func TestVersionOrder(t *testing.T) {
    62  	c := qt.New(t)
    63  	tests := []struct {
    64  		l, r string
    65  		cmp  int
    66  	}{{
    67  		// Compare some date versions
    68  		l: "2020-12-31", r: "2021-01-01", cmp: -1,
    69  	}, {
    70  		l: "2021-01-01", r: "2020-12-31", cmp: 1,
    71  	}, {
    72  		l: "2021-01-01", r: "2021-01-01", cmp: 0,
    73  	}, {
    74  		l: "9999-12-31", r: "9999-12-31~beta", cmp: 1,
    75  	}, {
    76  		// Compare date versions and special tags
    77  		l: "9999-12-31~beta", r: "9999-12-31", cmp: -1,
    78  	}, {
    79  		l: "9999-12-31", r: "9999-12-31~experimental", cmp: 1,
    80  	}, {
    81  		l: "9999-12-31~experimental", r: "9999-12-31", cmp: -1,
    82  		// Compare special tags
    83  	}, {
    84  		l: "2021-08-01~beta", r: "2021-08-01~experimental", cmp: 1,
    85  	}, {
    86  		l: "2021-08-01~experimental", r: "2021-08-01~beta", cmp: -1,
    87  	}, {
    88  		l: "2021-08-01~beta", r: "2021-08-01~beta", cmp: 0,
    89  	}, {
    90  		l: "2021-08-01~experimental", r: "2021-08-01~experimental", cmp: 0,
    91  	}, {
    92  		l: "2021-08-01~wip", r: "2021-08-01~experimental", cmp: -1,
    93  	}}
    94  	for i := range tests {
    95  		c.Logf("test %d %#v", i, tests[i])
    96  		lv, err := ParseVersion(tests[i].l)
    97  		c.Assert(err, qt.IsNil)
    98  		rv, err := ParseVersion(tests[i].r)
    99  		c.Assert(err, qt.IsNil)
   100  		c.Assert(lv.Compare(rv), qt.Equals, tests[i].cmp)
   101  	}
   102  }
   103  
   104  func TestVersionDateStrings(t *testing.T) {
   105  	c := qt.New(t)
   106  	c.Assert(VersionDateStrings([]Version{
   107  		MustParseVersion("2021-06-01~wip"),
   108  		MustParseVersion("2021-06-01~beta"),
   109  		MustParseVersion("2021-06-10~beta"),
   110  		MustParseVersion("2021-06-10"),
   111  		MustParseVersion("2021-07-12~wip"),
   112  		MustParseVersion("2021-07-12~experimental"),
   113  		MustParseVersion("2021-07-12~beta"),
   114  	}), qt.ContentEquals, []string{"2021-06-01", "2021-06-10", "2021-07-12"})
   115  }
   116  
   117  func TestVersionIndex(t *testing.T) {
   118  	type matchTest struct {
   119  		match       string
   120  		atStability string
   121  		mostStable  string
   122  		err         string
   123  	}
   124  	tests := []struct {
   125  		versions   VersionSlice
   126  		first      string
   127  		last       string
   128  		matchTests []matchTest
   129  	}{{
   130  		versions: VersionSlice{
   131  			MustParseVersion("2021-07-12~experimental"),
   132  			MustParseVersion("2021-06-01~beta"),
   133  			MustParseVersion("2021-07-12~beta"),
   134  			MustParseVersion("2021-06-10"),
   135  			MustParseVersion("2021-06-01~wip"),
   136  			MustParseVersion("2021-07-12~wip"),
   137  			MustParseVersion("2021-06-10~beta"),
   138  		},
   139  		first: "2021-06-01~wip",
   140  		last:  "2021-07-12~beta",
   141  		matchTests: []matchTest{{
   142  			match:       "2021-06-10",
   143  			atStability: "2021-06-10",
   144  			mostStable:  "2021-06-10",
   145  		}, {
   146  			match:       "2021-06-10~beta",
   147  			atStability: "2021-06-10~beta",
   148  			mostStable:  "2021-06-10",
   149  		}, {
   150  			match:       "2021-06-11~beta",
   151  			atStability: "2021-06-10~beta",
   152  			mostStable:  "2021-06-10",
   153  		}, {
   154  			match:       "2021-06-11",
   155  			atStability: "2021-06-10",
   156  			mostStable:  "2021-06-10",
   157  		}, {
   158  			match:       "2021-06-10~experimental",
   159  			atStability: "2021-06-10~beta",
   160  			mostStable:  "2021-06-10",
   161  		}, {
   162  			match:       "2021-06-11~experimental",
   163  			atStability: "2021-06-10~beta",
   164  			mostStable:  "2021-06-10",
   165  		}, {
   166  			match: "2021-01-01",
   167  			err:   "no matching version",
   168  		}, {
   169  			match:       "2022-01-01",
   170  			atStability: "2021-06-10",
   171  			mostStable:  "2021-06-10",
   172  		}, {
   173  			match:       "2022-01-01~experimental",
   174  			atStability: "2021-07-12~experimental",
   175  			mostStable:  "2021-07-12~beta",
   176  		}, {
   177  			match:       "2022-01-01~beta",
   178  			atStability: "2021-07-12~beta",
   179  			mostStable:  "2021-07-12~beta",
   180  		}},
   181  	}, {
   182  		versions: VersionSlice{
   183  			MustParseVersion("2021-06-10~beta"),
   184  		},
   185  		first: "2021-06-10~beta",
   186  		last:  "2021-06-10~beta",
   187  		matchTests: []matchTest{{
   188  			match: "2021-06-10",
   189  			err:   "no matching version",
   190  		}, {
   191  			match:       "2021-06-10~beta",
   192  			atStability: "2021-06-10~beta",
   193  			mostStable:  "2021-06-10~beta",
   194  		}, {
   195  			match:       "2021-06-10~experimental",
   196  			atStability: "2021-06-10~beta",
   197  			mostStable:  "2021-06-10~beta",
   198  		}, {
   199  			match:       "2021-06-11~wip",
   200  			atStability: "2021-06-10~beta",
   201  			mostStable:  "2021-06-10~beta",
   202  		}, {
   203  			match: "2021-01-01",
   204  			err:   "no matching version",
   205  		}, {
   206  			match:       "2022-01-01~wip",
   207  			atStability: "2021-06-10~beta",
   208  			mostStable:  "2021-06-10~beta",
   209  		}},
   210  	}, {
   211  		versions: VersionSlice{
   212  			MustParseVersion("2021-06-10~beta"),
   213  			MustParseVersion("2022-01-10~experimental"),
   214  		},
   215  		first: "2021-06-10~beta",
   216  		last:  "2022-01-10~experimental",
   217  		matchTests: []matchTest{{
   218  			match: "2021-04-10",
   219  			err:   "no matching version",
   220  		}, {
   221  			match:       "2021-08-10~beta",
   222  			atStability: "2021-06-10~beta",
   223  			mostStable:  "2021-06-10~beta",
   224  		}, {
   225  			match:       "2022-02-10~wip",
   226  			atStability: "2022-01-10~experimental",
   227  			mostStable:  "2022-01-10~experimental",
   228  		}, {
   229  			match: "2021-01-30",
   230  			err:   "no matching version",
   231  		}},
   232  	}, {
   233  		versions: VersionSlice{
   234  			MustParseVersion("2021-09-06"),
   235  			MustParseVersion("2021-10-06"),
   236  		},
   237  		first: "2021-09-06",
   238  		last:  "2021-10-06",
   239  		matchTests: []matchTest{{
   240  			match:       "2021-10-12~wip",
   241  			atStability: "2021-10-06",
   242  			mostStable:  "2021-10-06",
   243  		}},
   244  	}, {
   245  		versions: VersionSlice{
   246  			MustParseVersion("2021-09-06~beta"),
   247  			MustParseVersion("2021-09-07"),
   248  			MustParseVersion("2021-09-08~beta"),
   249  			MustParseVersion("2021-09-09~experimental"),
   250  		},
   251  		first: "2021-09-06~beta",
   252  		last:  "2021-09-09~experimental",
   253  		matchTests: []matchTest{{
   254  			match:       "2021-09-10",
   255  			atStability: "2021-09-07",
   256  			mostStable:  "2021-09-07",
   257  		}},
   258  	}}
   259  	c := qt.New(t)
   260  	for _, t := range tests {
   261  		index := NewVersionIndex(t.versions)
   262  		c.Log(t.versions)
   263  		c.Assert(t.versions[0].String(), qt.Equals, t.first)
   264  		c.Assert(t.versions[len(t.versions)-1].String(), qt.Equals, t.last)
   265  		for _, mt := range t.matchTests {
   266  			c.Log(mt)
   267  			match := MustParseVersion(mt.match)
   268  			atStability, err := index.Resolve(match)
   269  			if err != nil {
   270  				c.Assert(err, qt.ErrorMatches, mt.err)
   271  			} else {
   272  				c.Assert(atStability.String(), qt.Equals, mt.atStability)
   273  			}
   274  			mostStable, err := index.ResolveForBuild(match)
   275  			if err != nil {
   276  				c.Assert(err, qt.ErrorMatches, mt.err)
   277  			} else {
   278  				c.Assert(mostStable.String(), qt.Equals, mt.mostStable)
   279  			}
   280  		}
   281  	}
   282  }
   283  
   284  func TestVersionIndexResolveEmpty(t *testing.T) {
   285  	c := qt.New(t)
   286  	vi := NewVersionIndex(VersionSlice{})
   287  	_, err := vi.Resolve(MustParseVersion("2021-10-31"))
   288  	c.Assert(err, qt.ErrorMatches, "no matching version")
   289  	_, err = vi.ResolveForBuild(MustParseVersion("2021-10-31"))
   290  	c.Assert(err, qt.ErrorMatches, "no matching version")
   291  }
   292  
   293  func TestDeprecatedBy(t *testing.T) {
   294  	c := qt.New(t)
   295  	tests := []struct {
   296  		base, deprecatedBy string
   297  		result             bool
   298  	}{{
   299  		"2021-06-01", "2021-02-01", false,
   300  	}, {
   301  		"2021-06-01", "2021-02-01~experimental", false,
   302  	}, {
   303  		"2021-06-01", "2021-02-01~beta", false,
   304  	}, {
   305  		"2021-06-01", "2022-02-01~beta", false,
   306  	}, {
   307  		"2021-06-01", "2022-02-01~experimental", false,
   308  	}, {
   309  		"2021-06-01", "2021-06-01", false,
   310  	}, {
   311  		"2021-06-01", "2021-06-02", true,
   312  	}, {
   313  		"2021-06-01~experimental", "2021-06-02~beta", true,
   314  	}, {
   315  		"2021-06-01~beta", "2021-06-02", true,
   316  	}, {
   317  		"2021-06-01", "2021-06-01", false,
   318  	}}
   319  	for i, test := range tests {
   320  		c.Logf("test#%d: %#v", i, test)
   321  		base, deprecatedBy := MustParseVersion(test.base), MustParseVersion(test.deprecatedBy)
   322  		c.Assert(base.DeprecatedBy(deprecatedBy), qt.Equals, test.result)
   323  	}
   324  }
   325  
   326  func TestDeprecates(t *testing.T) {
   327  	c := qt.New(t)
   328  	versions := NewVersionIndex(VersionSlice{
   329  		MustParseVersion("2021-06-01~experimental"),
   330  		MustParseVersion("2021-06-07~beta"),
   331  		MustParseVersion("2021-07-01"),
   332  		MustParseVersion("2021-08-12~experimental"),
   333  		MustParseVersion("2021-09-16~beta"),
   334  		MustParseVersion("2021-10-31"),
   335  	})
   336  	tests := []struct {
   337  		name         string
   338  		target       Version
   339  		deprecatedBy Version
   340  		isDeprecated bool
   341  		sunset       time.Time
   342  	}{{
   343  		name:         "beta deprecates experimental",
   344  		target:       MustParseVersion("2021-06-01~experimental"),
   345  		deprecatedBy: MustParseVersion("2021-06-07~beta"),
   346  		isDeprecated: true,
   347  		sunset:       time.Date(2021, time.June, 8, 0, 0, 0, 0, time.UTC),
   348  	}, {
   349  		name:         "ga deprecates beta",
   350  		target:       MustParseVersion("2021-06-07~beta"),
   351  		deprecatedBy: MustParseVersion("2021-07-01"),
   352  		isDeprecated: true,
   353  		sunset:       time.Date(2021, time.September, 30, 0, 0, 0, 0, time.UTC),
   354  	}, {
   355  		name:         "ga deprecates ga",
   356  		target:       MustParseVersion("2021-07-01"),
   357  		deprecatedBy: MustParseVersion("2021-10-31"),
   358  		isDeprecated: true,
   359  		sunset:       time.Date(2022, time.April, 30, 0, 0, 0, 0, time.UTC),
   360  	}}
   361  	for i, test := range tests {
   362  		c.Logf("test#%d: %s", i, test.name)
   363  		deprecates, ok := versions.Deprecates(test.target)
   364  		c.Assert(ok, qt.Equals, test.isDeprecated)
   365  		if test.isDeprecated {
   366  			c.Assert(test.deprecatedBy, qt.DeepEquals, deprecates)
   367  			sunset, ok := test.target.Sunset(deprecates)
   368  			c.Assert(ok, qt.IsTrue)
   369  			c.Assert(test.sunset, qt.Equals, sunset)
   370  		}
   371  	}
   372  }
   373  
   374  func TestLifecycleAtEnv(t *testing.T) {
   375  	c := qt.New(t)
   376  	tests := []struct {
   377  		version   Version
   378  		lifecycle string
   379  		at        string
   380  	}{{
   381  		version:   MustParseVersion("2022-08-16~wip"),
   382  		lifecycle: "sunset",
   383  		at:        "2022-08-16",
   384  	}, {
   385  		version:   MustParseVersion("2022-08-16~experimental"),
   386  		lifecycle: "deprecated",
   387  		at:        "2022-08-16",
   388  	}, {
   389  		version:   MustParseVersion("2022-08-16~experimental"),
   390  		lifecycle: "sunset",
   391  		at:        "2022-11-16",
   392  	}, {
   393  		version:   MustParseVersion("2022-08-16~beta"),
   394  		lifecycle: "released",
   395  		at:        "2022-08-16",
   396  	}, {
   397  		version:   MustParseVersion("2022-08-16~beta"),
   398  		lifecycle: "released",
   399  		at:        "2022-11-16",
   400  	}}
   401  	for _, test := range tests {
   402  		c.Run(fmt.Sprintf("test %v", test.version), func(c *qt.C) {
   403  			c.Setenv("VERVET_LIFECYCLE_AT", test.at)
   404  			lifecycle := test.version.LifecycleAt(time.Time{})
   405  			c.Assert(lifecycle.String(), qt.Equals, test.lifecycle)
   406  		})
   407  	}
   408  }
   409  
   410  func TestLifecycleAtDefaultDate(t *testing.T) {
   411  	c := qt.New(t)
   412  	tests := []struct {
   413  		version   Version
   414  		lifecycle string
   415  		at        string
   416  	}{{
   417  		version:   MustParseVersion("2022-08-16~wip"),
   418  		lifecycle: "sunset",
   419  	}, {
   420  		version:   MustParseVersion("2022-08-16~experimental"),
   421  		lifecycle: "deprecated",
   422  	}, {
   423  		version:   MustParseVersion("2022-05-16~experimental"),
   424  		lifecycle: "sunset",
   425  	}, {
   426  		version:   MustParseVersion("2022-08-16~beta"),
   427  		lifecycle: "released",
   428  	}, {
   429  		version:   MustParseVersion("2022-08-16~beta"),
   430  		lifecycle: "released",
   431  	}}
   432  	for _, test := range tests {
   433  		c.Run(fmt.Sprintf("test %v", test.version), func(c *qt.C) {
   434  			c.Patch(TimeNow, func() time.Time { return time.Date(2022, time.September, 6, 14, 49, 50, 0, time.UTC) })
   435  			lifecycle := test.version.LifecycleAt(time.Time{})
   436  			c.Assert(lifecycle.String(), qt.Equals, test.lifecycle)
   437  		})
   438  	}
   439  }
   440  
   441  func TestLifecycleAtUnreleasedVersionStringPanics(t *testing.T) {
   442  	c := qt.New(t)
   443  	c.Patch(TimeNow, func() time.Time { return time.Date(2022, time.June, 6, 14, 49, 50, 0, time.UTC) })
   444  	version := MustParseVersion("2022-10-16~wip")
   445  	lifecycle := version.LifecycleAt(time.Time{})
   446  	c.Assert(func() {
   447  		c.Log(lifecycle.String())
   448  	}, qt.PanicMatches, "invalid lifecycle.*")
   449  }