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 }