github.com/tilt-dev/tilt@v0.33.15-0.20240515162809-0a22ed45d8a0/internal/timecmp/cmp_test.go (about)

     1  package timecmp
     2  
     3  import (
     4  	"testing"
     5  	"time"
     6  
     7  	"github.com/stretchr/testify/assert"
     8  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
     9  )
    10  
    11  type cmpFunc func(a, b commonTime) bool
    12  type timeFn func() *time.Time
    13  
    14  type tc struct {
    15  	x   *time.Time
    16  	y   *time.Time
    17  	cmp cmpFunc
    18  
    19  	second      bool
    20  	microsecond bool
    21  	nanosecond  bool
    22  }
    23  
    24  func now() *time.Time {
    25  	v := time.Unix(1619635910, 450240689)
    26  	return &v
    27  }
    28  
    29  func TestEqual(t *testing.T) {
    30  	runReflexiveTest(t, Equal, true, now)
    31  
    32  	t.Run("NanosecondDifference", func(t *testing.T) {
    33  		// truncate to avoid potential roll-over
    34  		now := now().Truncate(time.Nanosecond)
    35  		x := now
    36  		y := now.Add(time.Nanosecond)
    37  
    38  		runTest(t, tc{
    39  			x:           &x,
    40  			y:           &y,
    41  			cmp:         Equal,
    42  			nanosecond:  false,
    43  			microsecond: true,
    44  			second:      true,
    45  		})
    46  	})
    47  
    48  	t.Run("MicrosecondDifference", func(t *testing.T) {
    49  		// truncate to avoid potential roll-over
    50  		now := now().Truncate(time.Microsecond)
    51  		x := now
    52  		y := now.Add(time.Microsecond)
    53  
    54  		runTest(t, tc{
    55  			x:           &x,
    56  			y:           &y,
    57  			cmp:         Equal,
    58  			nanosecond:  false,
    59  			microsecond: false,
    60  			second:      true,
    61  		})
    62  	})
    63  
    64  	t.Run("SecondDifference", func(t *testing.T) {
    65  		// truncate to avoid potential roll-over
    66  		now := now().Truncate(time.Second)
    67  		x := now
    68  		y := now.Add(time.Second)
    69  
    70  		runTest(t, tc{
    71  			x:           &x,
    72  			y:           &y,
    73  			cmp:         Equal,
    74  			nanosecond:  false,
    75  			microsecond: false,
    76  			second:      false,
    77  		})
    78  	})
    79  
    80  	t.Run("Nil", func(t *testing.T) {
    81  		nilTime := func() *time.Time {
    82  			return nil
    83  		}
    84  
    85  		runReflexiveTest(t, Equal, true, nilTime)
    86  
    87  		t.Run("X", func(t *testing.T) {
    88  			// use a typed nil to mimic K8s API objects
    89  			x := (*time.Time)(nil)
    90  			y := now()
    91  			runTest(t, tc{
    92  				x:           x,
    93  				y:           y,
    94  				cmp:         Equal,
    95  				nanosecond:  false,
    96  				microsecond: false,
    97  				second:      false,
    98  			})
    99  		})
   100  
   101  		t.Run("Y", func(t *testing.T) {
   102  			x := now()
   103  			runTest(t, tc{
   104  				x:           x,
   105  				y:           nil,
   106  				cmp:         Equal,
   107  				nanosecond:  false,
   108  				microsecond: false,
   109  				second:      false,
   110  			})
   111  		})
   112  	})
   113  }
   114  
   115  func TestBefore(t *testing.T) {
   116  	runReflexiveTest(t, Before, false, now)
   117  
   118  	t.Run("NanosecondDifference", func(t *testing.T) {
   119  		a := now().Truncate(time.Nanosecond).Add(-5 * time.Nanosecond)
   120  		b := a.Add(time.Nanosecond)
   121  
   122  		// x before y
   123  		runTest(t, tc{
   124  			x:           &a,
   125  			y:           &b,
   126  			cmp:         Before,
   127  			nanosecond:  true,
   128  			microsecond: false,
   129  			second:      false,
   130  		})
   131  
   132  		// x after y
   133  		runTest(t, tc{
   134  			x:           &b,
   135  			y:           &a,
   136  			cmp:         Before,
   137  			nanosecond:  false,
   138  			microsecond: false,
   139  			second:      false,
   140  		})
   141  	})
   142  
   143  	t.Run("MicrosecondDifference", func(t *testing.T) {
   144  		a := now().Truncate(time.Microsecond).Add(-5 * time.Microsecond)
   145  		b := a.Add(time.Microsecond)
   146  
   147  		// x before y
   148  		runTest(t, tc{
   149  			x:           &a,
   150  			y:           &b,
   151  			cmp:         Before,
   152  			nanosecond:  true,
   153  			microsecond: true,
   154  			second:      false,
   155  		})
   156  
   157  		// x after y
   158  		runTest(t, tc{
   159  			x:           &b,
   160  			y:           &a,
   161  			cmp:         Before,
   162  			nanosecond:  false,
   163  			microsecond: false,
   164  			second:      false,
   165  		})
   166  	})
   167  
   168  	t.Run("SecondDifference", func(t *testing.T) {
   169  		a := now().Truncate(time.Second).Add(-5 * time.Second)
   170  		b := a.Add(time.Second)
   171  
   172  		// x before y
   173  		runTest(t, tc{
   174  			x:           &a,
   175  			y:           &b,
   176  			cmp:         Before,
   177  			nanosecond:  true,
   178  			microsecond: true,
   179  			second:      true,
   180  		})
   181  
   182  		// x after y
   183  		runTest(t, tc{
   184  			x:           &b,
   185  			y:           &a,
   186  			cmp:         Before,
   187  			nanosecond:  false,
   188  			microsecond: false,
   189  			second:      false,
   190  		})
   191  	})
   192  }
   193  
   194  func TestBeforeOrEqual(t *testing.T) {
   195  	runReflexiveTest(t, BeforeOrEqual, true, now)
   196  
   197  	t.Run("NanosecondDifference", func(t *testing.T) {
   198  		a := now().Truncate(time.Nanosecond).Add(-5 * time.Nanosecond)
   199  		b := a.Add(time.Nanosecond)
   200  
   201  		// x before y
   202  		runTest(t, tc{
   203  			x:           &a,
   204  			y:           &b,
   205  			cmp:         BeforeOrEqual,
   206  			nanosecond:  true,
   207  			microsecond: true,
   208  			second:      true,
   209  		})
   210  
   211  		// x after y
   212  		runTest(t, tc{
   213  			x:           &b,
   214  			y:           &a,
   215  			cmp:         BeforeOrEqual,
   216  			nanosecond:  false,
   217  			microsecond: true,
   218  			second:      true,
   219  		})
   220  	})
   221  
   222  	t.Run("MicrosecondDifference", func(t *testing.T) {
   223  		a := now().Truncate(time.Microsecond).Add(-5 * time.Microsecond)
   224  		b := a.Add(time.Microsecond)
   225  
   226  		// x before y
   227  		runTest(t, tc{
   228  			x:           &a,
   229  			y:           &b,
   230  			cmp:         BeforeOrEqual,
   231  			nanosecond:  true,
   232  			microsecond: true,
   233  			second:      true,
   234  		})
   235  
   236  		// x after y
   237  		runTest(t, tc{
   238  			x:           &b,
   239  			y:           &a,
   240  			cmp:         BeforeOrEqual,
   241  			nanosecond:  false,
   242  			microsecond: false,
   243  			second:      true,
   244  		})
   245  	})
   246  
   247  	t.Run("SecondDifference", func(t *testing.T) {
   248  		a := now().Truncate(time.Second).Add(-5 * time.Second)
   249  		b := a.Add(time.Second)
   250  
   251  		// x before y
   252  		runTest(t, tc{
   253  			x:           &a,
   254  			y:           &b,
   255  			cmp:         BeforeOrEqual,
   256  			nanosecond:  true,
   257  			microsecond: true,
   258  			second:      true,
   259  		})
   260  
   261  		// x after y
   262  		runTest(t, tc{
   263  			x:           &b,
   264  			y:           &a,
   265  			cmp:         BeforeOrEqual,
   266  			nanosecond:  false,
   267  			microsecond: false,
   268  			second:      false,
   269  		})
   270  	})
   271  }
   272  
   273  func TestAfter(t *testing.T) {
   274  	runReflexiveTest(t, After, false, now)
   275  
   276  	t.Run("NanosecondDifference", func(t *testing.T) {
   277  		a := now().Truncate(time.Nanosecond).Add(-5 * time.Nanosecond)
   278  		b := a.Add(time.Nanosecond)
   279  
   280  		// x before y
   281  		runTest(t, tc{
   282  			x:           &a,
   283  			y:           &b,
   284  			cmp:         After,
   285  			nanosecond:  false,
   286  			microsecond: false,
   287  			second:      false,
   288  		})
   289  
   290  		// x after y
   291  		runTest(t, tc{
   292  			x:           &b,
   293  			y:           &a,
   294  			cmp:         After,
   295  			nanosecond:  true,
   296  			microsecond: false,
   297  			second:      false,
   298  		})
   299  	})
   300  
   301  	t.Run("MicrosecondDifference", func(t *testing.T) {
   302  		a := now().Truncate(time.Microsecond).Add(-5 * time.Microsecond)
   303  		b := a.Add(time.Microsecond)
   304  
   305  		// x before y
   306  		runTest(t, tc{
   307  			x:           &a,
   308  			y:           &b,
   309  			cmp:         After,
   310  			nanosecond:  false,
   311  			microsecond: false,
   312  			second:      false,
   313  		})
   314  
   315  		// x after y
   316  		runTest(t, tc{
   317  			x:           &b,
   318  			y:           &a,
   319  			cmp:         After,
   320  			nanosecond:  true,
   321  			microsecond: true,
   322  			second:      false,
   323  		})
   324  	})
   325  
   326  	t.Run("SecondDifference", func(t *testing.T) {
   327  		a := now().Truncate(time.Second).Add(-5 * time.Second)
   328  		b := a.Add(time.Second)
   329  
   330  		// x before y
   331  		runTest(t, tc{
   332  			x:           &a,
   333  			y:           &b,
   334  			cmp:         After,
   335  			nanosecond:  false,
   336  			microsecond: false,
   337  			second:      false,
   338  		})
   339  
   340  		// x after y
   341  		runTest(t, tc{
   342  			x:           &b,
   343  			y:           &a,
   344  			cmp:         After,
   345  			nanosecond:  true,
   346  			microsecond: true,
   347  			second:      true,
   348  		})
   349  	})
   350  }
   351  
   352  func TestAfterOrEqual(t *testing.T) {
   353  	runReflexiveTest(t, AfterOrEqual, true, now)
   354  
   355  	t.Run("NanosecondDifference", func(t *testing.T) {
   356  		a := now().Truncate(time.Nanosecond).Add(-5 * time.Nanosecond)
   357  		b := a.Add(time.Nanosecond)
   358  
   359  		// x before y
   360  		runTest(t, tc{
   361  			x:           &a,
   362  			y:           &b,
   363  			cmp:         AfterOrEqual,
   364  			nanosecond:  false,
   365  			microsecond: true,
   366  			second:      true,
   367  		})
   368  
   369  		// x after y
   370  		runTest(t, tc{
   371  			x:           &b,
   372  			y:           &a,
   373  			cmp:         AfterOrEqual,
   374  			nanosecond:  true,
   375  			microsecond: true,
   376  			second:      true,
   377  		})
   378  	})
   379  
   380  	t.Run("MicrosecondDifference", func(t *testing.T) {
   381  		a := now().Truncate(time.Microsecond).Add(-5 * time.Microsecond)
   382  		b := a.Add(time.Microsecond)
   383  
   384  		// x before y
   385  		runTest(t, tc{
   386  			x:           &a,
   387  			y:           &b,
   388  			cmp:         AfterOrEqual,
   389  			nanosecond:  false,
   390  			microsecond: false,
   391  			second:      true,
   392  		})
   393  
   394  		// x after y
   395  		runTest(t, tc{
   396  			x:           &b,
   397  			y:           &a,
   398  			cmp:         AfterOrEqual,
   399  			nanosecond:  true,
   400  			microsecond: true,
   401  			second:      true,
   402  		})
   403  	})
   404  
   405  	t.Run("SecondDifference", func(t *testing.T) {
   406  		a := now().Truncate(time.Second).Add(-5 * time.Second)
   407  		b := a.Add(time.Second)
   408  
   409  		// x before y
   410  		runTest(t, tc{
   411  			x:           &a,
   412  			y:           &b,
   413  			cmp:         AfterOrEqual,
   414  			nanosecond:  false,
   415  			microsecond: false,
   416  			second:      false,
   417  		})
   418  
   419  		// x after y
   420  		runTest(t, tc{
   421  			x:           &b,
   422  			y:           &a,
   423  			cmp:         AfterOrEqual,
   424  			nanosecond:  true,
   425  			microsecond: true,
   426  			second:      true,
   427  		})
   428  	})
   429  }
   430  
   431  func runReflexiveTest(t *testing.T, cmp cmpFunc, isReflexive bool, timeVal timeFn) {
   432  	t.Run("Reflexive", func(t *testing.T) {
   433  		v := timeVal()
   434  		runTest(t, tc{
   435  			x:           v,
   436  			y:           v,
   437  			cmp:         cmp,
   438  			nanosecond:  isReflexive,
   439  			microsecond: isReflexive,
   440  			second:      isReflexive,
   441  		})
   442  	})
   443  }
   444  
   445  func runTest(t testing.TB, tc tc) {
   446  	t.Helper()
   447  
   448  	assert.Equal(t, tc.nanosecond, tc.cmp(tc.x, tc.y), "Nanosecond (stdlib <> stdlib) comparison failed")
   449  
   450  	assert.Equal(t, tc.microsecond, tc.cmp(apiMicroTime(tc.x), apiMicroTime(tc.y)),
   451  		"Microsecond (metav1.MicroTime <> metav1.MicroTime) comparison failed. Values:\n- x: %v\n- y: %v",
   452  		tc.x, tc.y)
   453  	assert.Equal(t, tc.microsecond, tc.cmp(apiMicroTime(tc.x), tc.y),
   454  		"Microsecond (metav1.MicroTime <> stdlib) comparison failed. Values:\n- x: %v\n- y: %v",
   455  		tc.x, tc.y)
   456  	assert.Equal(t, tc.microsecond, tc.cmp(tc.x, apiMicroTime(tc.y)),
   457  		"Microsecond (stdlib <> metav1.MicroTime) comparison failed. Values:\n- x: %v\n- y: %v",
   458  		tc.x, tc.y)
   459  
   460  	assert.Equal(t, tc.second, tc.cmp(apiTime(tc.x), apiTime(tc.y)),
   461  		"Second (metav1.Time <> metav1.Time) comparison failed. Values:\n- x: %v\n- y: %v",
   462  		tc.x, tc.y)
   463  	assert.Equal(t, tc.second, tc.cmp(apiTime(tc.x), tc.y),
   464  		"Second (metav1.Time <> stdlib) comparison failed. Values:\n- x: %v\n- y: %v",
   465  		tc.x, tc.y)
   466  	assert.Equal(t, tc.second, tc.cmp(tc.x, apiTime(tc.y)),
   467  		"Second (stdlib <> metav1.Time) comparison failed. Values:\n- x: %v\n- y: %v",
   468  		tc.x, tc.y)
   469  	assert.Equal(t, tc.second, tc.cmp(apiTime(tc.x), apiMicroTime(tc.y)),
   470  		"Second (metav1.Time <> metav1.MicroTime) comparison failed. Values:\n- x: %v\n- y: %v",
   471  		tc.x, tc.y)
   472  	assert.Equal(t, tc.second, tc.cmp(apiMicroTime(tc.x), apiTime(tc.y)),
   473  		"Second (metav1.MicroTime <> metav1.Time) comparison failed. Values:\n- x: %v\n- y: %v",
   474  		tc.x, tc.y)
   475  
   476  	// pointer test cases (non-exhaustive)
   477  	xAPITime := apiTimeP(tc.x)
   478  	yMicroTime := apiMicroTimeP(tc.y)
   479  	assert.Equal(t, tc.second, tc.cmp(xAPITime, yMicroTime),
   480  		"Second (*metav1.Time <> *metav1.MicroTime) comparison failed. Values:\n- x: %v\n- y: %v",
   481  		tc.x, tc.y)
   482  	assert.Equal(t, tc.second, tc.cmp(xAPITime, tc.y),
   483  		"Second (metav1.Time <> *stdlib) comparison failed. Values:\n- x: %v\n- y: %v",
   484  		tc.x, tc.y)
   485  }
   486  
   487  func apiMicroTime(v *time.Time) commonTime {
   488  	if v == nil {
   489  		return nil
   490  	}
   491  	return metav1.NewMicroTime(*v)
   492  }
   493  
   494  func apiMicroTimeP(v *time.Time) *metav1.MicroTime {
   495  	if v == nil {
   496  		return nil
   497  	}
   498  	t := metav1.NewMicroTime(*v)
   499  	return &t
   500  }
   501  
   502  func apiTime(v *time.Time) commonTime {
   503  	if v == nil {
   504  		return nil
   505  	}
   506  	return metav1.NewTime(*v)
   507  }
   508  
   509  func apiTimeP(v *time.Time) *metav1.Time {
   510  	if v == nil {
   511  		return nil
   512  	}
   513  	t := metav1.NewTime(*v)
   514  	return &t
   515  }