github.com/m3db/m3@v1.5.1-0.20231129193456-75a402aa583b/src/x/time/range_test.go (about) 1 // Copyright (c) 2016 Uber Technologies, Inc. 2 // 3 // Permission is hereby granted, free of charge, to any person obtaining a copy 4 // of this software and associated documentation files (the "Software"), to deal 5 // in the Software without restriction, including without limitation the rights 6 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 // copies of the Software, and to permit persons to whom the Software is 8 // furnished to do so, subject to the following conditions: 9 // 10 // The above copyright notice and this permission notice shall be included in 11 // all copies or substantial portions of the Software. 12 // 13 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 // THE SOFTWARE. 20 21 package time 22 23 import ( 24 "fmt" 25 "testing" 26 "time" 27 28 "github.com/stretchr/testify/require" 29 ) 30 31 var ( 32 testStart = Now() 33 ) 34 35 type testRanges struct { 36 r1 Range 37 r2 Range 38 } 39 40 func testInput() []testRanges { 41 return []testRanges{ 42 { 43 // r1 before r2, r1.end == r2.start 44 Range{testStart, testStart.Add(10 * time.Second)}, 45 Range{testStart.Add(10 * time.Second), testStart.Add(20 * time.Second)}, 46 }, 47 { 48 // r1 before r2, r1.end < r2.start 49 Range{testStart, testStart.Add(10 * time.Second)}, 50 Range{testStart.Add(20 * time.Second), testStart.Add(30 * time.Second)}, 51 }, 52 { 53 // r1 contains r2, r1.end == r2.end 54 Range{testStart, testStart.Add(10 * time.Second)}, 55 Range{testStart.Add(5 * time.Second), testStart.Add(10 * time.Second)}, 56 }, 57 { 58 // r1 contains r2, r1.end > r2.end 59 Range{testStart, testStart.Add(10 * time.Second)}, 60 Range{testStart.Add(5 * time.Second), testStart.Add(8 * time.Second)}, 61 }, 62 { 63 // r1 overlaps r2, r1.end < r2.end 64 Range{testStart, testStart.Add(10 * time.Second)}, 65 Range{testStart.Add(5 * time.Second), testStart.Add(15 * time.Second)}, 66 }, 67 { 68 // r2 before r1, r1.start == r2.end 69 Range{testStart, testStart.Add(10 * time.Second)}, 70 Range{testStart.Add(-5 * time.Second), testStart}, 71 }, 72 { 73 // r2 before r1, r1.start > r2.end 74 Range{testStart, testStart.Add(10 * time.Second)}, 75 Range{testStart.Add(-10 * time.Second), testStart.Add(-5 * time.Second)}, 76 }, 77 { 78 // r2 contains r1, r1.end == r2.end 79 Range{testStart, testStart.Add(10 * time.Second)}, 80 Range{testStart.Add(-5 * time.Second), testStart.Add(10 * time.Second)}, 81 }, 82 { 83 // r2 contains r1, r1.end < r2.end 84 Range{testStart, testStart.Add(10 * time.Second)}, 85 Range{testStart.Add(-5 * time.Second), testStart.Add(20 * time.Second)}, 86 }, 87 { 88 // r1 overlaps r2, r1.end > r2.end 89 Range{testStart, testStart.Add(10 * time.Second)}, 90 Range{testStart.Add(-5 * time.Second), testStart.Add(5 * time.Second)}, 91 }, 92 { 93 // r1 == r2 94 Range{testStart, testStart.Add(10 * time.Second)}, 95 Range{testStart, testStart.Add(10 * time.Second)}, 96 }, 97 } 98 } 99 100 func timeFromSec(s int64) UnixNano { 101 return ToUnixNano(time.Unix(s, 0)) 102 } 103 104 func TestRangeIsEmpty(t *testing.T) { 105 r := Range{testStart, testStart} 106 require.True(t, r.IsEmpty()) 107 108 r.End = testStart.Add(time.Second) 109 require.False(t, r.IsEmpty()) 110 } 111 112 func TestEqual(t *testing.T) { 113 inputs := []struct { 114 a, b Range 115 expected bool 116 }{ 117 { 118 a: Range{Start: timeFromSec(12), End: timeFromSec(34)}, 119 b: Range{Start: timeFromSec(12), End: timeFromSec(34)}, 120 expected: true, 121 }, 122 { 123 a: Range{Start: timeFromSec(12), End: timeFromSec(34)}, 124 b: Range{ 125 Start: ToUnixNano(time.Unix(12, 0).UTC()), 126 End: ToUnixNano(time.Unix(34, 0).UTC()), 127 }, 128 expected: true, 129 }, 130 { 131 a: Range{Start: timeFromSec(12), End: timeFromSec(34)}, 132 b: Range{Start: timeFromSec(13), End: timeFromSec(34)}, 133 expected: false, 134 }, 135 { 136 a: Range{Start: timeFromSec(12), End: timeFromSec(34)}, 137 b: Range{Start: timeFromSec(12), End: timeFromSec(36)}, 138 expected: false, 139 }, 140 } 141 for _, input := range inputs { 142 require.Equal(t, input.expected, input.a.Equal(input.b)) 143 require.Equal(t, input.expected, input.b.Equal(input.a)) 144 } 145 } 146 147 func TestRangeBefore(t *testing.T) { 148 input := testInput() 149 expected := []bool{ 150 true, true, false, false, false, false, false, false, false, false, false, 151 } 152 for i := 0; i < len(input); i++ { 153 require.Equal(t, expected[i], input[i].r1.Before(input[i].r2)) 154 } 155 } 156 157 func TestRangeAfter(t *testing.T) { 158 input := testInput() 159 expected := []bool{ 160 false, false, false, false, false, true, true, false, false, false, false, 161 } 162 for i := 0; i < len(input); i++ { 163 require.Equal(t, expected[i], input[i].r1.After(input[i].r2)) 164 } 165 } 166 167 func TestRangeContains(t *testing.T) { 168 input := testInput() 169 expected := []bool{ 170 false, false, true, true, false, false, false, false, false, false, true, 171 } 172 for i := 0; i < len(input); i++ { 173 require.Equal(t, expected[i], input[i].r1.Contains(input[i].r2)) 174 } 175 176 expected = []bool{ 177 false, false, false, false, false, false, false, true, true, false, true, 178 } 179 for i := 0; i < len(input); i++ { 180 require.Equal(t, input[i].r2.Contains(input[i].r1), expected[i]) 181 } 182 } 183 184 func TestRangeOverlaps(t *testing.T) { 185 input := testInput() 186 expected := []bool{ 187 false, false, true, true, true, false, false, true, true, true, true, 188 } 189 for i := 0; i < len(input); i++ { 190 require.Equal(t, expected[i], input[i].r1.Overlaps(input[i].r2)) 191 } 192 } 193 194 func TestRangeDuration(t *testing.T) { 195 inputs := []struct { 196 r Range 197 expected time.Duration 198 }{ 199 { 200 r: Range{Start: timeFromSec(12), End: timeFromSec(34)}, 201 expected: 22 * time.Second, 202 }, 203 { 204 r: Range{Start: timeFromSec(8), End: timeFromSec(8)}, 205 expected: 0, 206 }, 207 } 208 for _, input := range inputs { 209 require.Equal(t, input.expected, input.r.Duration()) 210 } 211 } 212 213 func TestRangeIntersect(t *testing.T) { 214 input := testInput() 215 for i := 0; i < len(input); i++ { 216 var ( 217 r1 = input[i].r1 218 r2 = input[i].r2 219 r1Intersected, ok1 = r1.Intersect(r2) 220 r2Intersected, ok2 = r2.Intersect(r1) 221 ) 222 switch i { 223 case 0: // r1 before r2, r1.end == r2.start 224 require.False(t, ok1) 225 require.False(t, ok2) 226 case 1: // r1 before r2, r1.end < r2.start 227 require.False(t, ok1) 228 require.False(t, ok2) 229 case 2: // r1 contains r2, r1.end == r2.end 230 require.True(t, ok1) 231 require.True(t, ok2) 232 require.Equal(t, r1Intersected.Start, r2.Start) 233 require.Equal(t, r2Intersected.Start, r2.Start) 234 case 3: // r1 contains r2, r1.end > r2.end 235 require.True(t, ok1) 236 require.True(t, ok2) 237 case 4: // r1 overlaps r2, r1.end < r2.end 238 require.True(t, ok1) 239 require.True(t, ok2) 240 require.Equal(t, r1Intersected.Start, r2.Start) 241 require.Equal(t, r1Intersected.End, r1.End) 242 require.Equal(t, r2Intersected.Start, r2.Start) 243 require.Equal(t, r2Intersected.End, r1.End) 244 case 5: // r2 before r1, r1.start == r2.end 245 require.False(t, ok1) 246 require.False(t, ok2) 247 case 6: // r2 before r1, r1.start > r2.end 248 require.False(t, ok1) 249 require.False(t, ok2) 250 case 7: // r2 contains r1, r1.end == r2.end 251 require.True(t, ok1) 252 require.True(t, ok2) 253 require.Equal(t, r1Intersected.Start, r1.Start) 254 require.Equal(t, r1Intersected.End, r1.End) 255 require.Equal(t, r2Intersected.Start, r1.Start) 256 require.Equal(t, r2Intersected.End, r2.End) 257 case 8: // r2 contains r1, r1.end < r2.end 258 require.True(t, ok1) 259 require.True(t, ok2) 260 require.Equal(t, r1Intersected.Start, r1.Start) 261 require.Equal(t, r1Intersected.End, r1.End) 262 require.Equal(t, r2Intersected.Start, r1.Start) 263 require.Equal(t, r2Intersected.End, r1.End) 264 case 9: // r1 overlaps r2, r1.end > r2.end 265 require.True(t, ok1) 266 require.True(t, ok2) 267 require.Equal(t, r1Intersected.Start, r1.Start) 268 require.Equal(t, r1Intersected.End, r2.End) 269 require.Equal(t, r2Intersected.Start, r1.Start) 270 require.Equal(t, r2Intersected.End, r2.End) 271 case 10: // r1 == r2 272 require.True(t, ok1) 273 require.True(t, ok2) 274 require.Equal(t, r1Intersected.Start, r1.Start) 275 require.Equal(t, r1Intersected.End, r1.End) 276 require.Equal(t, r2Intersected.Start, r2.Start) 277 require.Equal(t, r2Intersected.End, r2.End) 278 } 279 } 280 281 } 282 283 func TestRangeSince(t *testing.T) { 284 r := Range{testStart, testStart.Add(10 * time.Second)} 285 require.Equal(t, r, r.Since(testStart.Add(-time.Second))) 286 require.Equal(t, r, r.Since(testStart)) 287 require.Equal(t, Range{ 288 Start: testStart.Add(5 * time.Second), 289 End: testStart.Add(10 * time.Second), 290 }, r.Since(testStart.Add(5*time.Second))) 291 require.Equal(t, Range{ 292 Start: testStart.Add(10 * time.Second), 293 End: testStart.Add(10 * time.Second), 294 }, r.Since(testStart.Add(10*time.Second))) 295 require.Equal(t, Range{}, r.Since(testStart.Add(20*time.Second))) 296 } 297 298 func TestRangeMerge(t *testing.T) { 299 input := testInput() 300 expected := []Range{ 301 {testStart, testStart.Add(20 * time.Second)}, 302 {testStart, testStart.Add(30 * time.Second)}, 303 {testStart, testStart.Add(10 * time.Second)}, 304 {testStart, testStart.Add(10 * time.Second)}, 305 {testStart, testStart.Add(15 * time.Second)}, 306 {testStart.Add(-5 * time.Second), testStart.Add(10 * time.Second)}, 307 {testStart.Add(-10 * time.Second), testStart.Add(10 * time.Second)}, 308 {testStart.Add(-5 * time.Second), testStart.Add(10 * time.Second)}, 309 {testStart.Add(-5 * time.Second), testStart.Add(20 * time.Second)}, 310 {testStart.Add(-5 * time.Second), testStart.Add(10 * time.Second)}, 311 {testStart, testStart.Add(10 * time.Second)}, 312 } 313 for i := 0; i < len(input); i++ { 314 require.Equal(t, expected[i], input[i].r1.Merge(input[i].r2)) 315 } 316 } 317 318 func TestRangeSubtract(t *testing.T) { 319 input := testInput() 320 expected := [][]Range{ 321 { 322 {testStart, testStart.Add(10 * time.Second)}, 323 }, 324 { 325 {testStart, testStart.Add(10 * time.Second)}, 326 }, 327 { 328 {testStart, testStart.Add(5 * time.Second)}, 329 }, 330 { 331 {testStart, testStart.Add(5 * time.Second)}, 332 {testStart.Add(8 * time.Second), testStart.Add(10 * time.Second)}, 333 }, 334 { 335 {testStart, testStart.Add(5 * time.Second)}, 336 }, 337 { 338 {testStart, testStart.Add(10 * time.Second)}, 339 }, 340 { 341 {testStart, testStart.Add(10 * time.Second)}, 342 }, 343 nil, 344 nil, 345 { 346 {testStart.Add(5 * time.Second), testStart.Add(10 * time.Second)}, 347 }, 348 nil, 349 } 350 for i := 0; i < len(input); i++ { 351 require.Equal(t, expected[i], input[i].r1.Subtract(input[i].r2)) 352 } 353 } 354 355 func TestRangeIterateForward(t *testing.T) { 356 testCases := []struct { 357 r Range 358 stepSize time.Duration 359 expected []UnixNano 360 }{ 361 { 362 r: Range{Start: 0, End: 0}, 363 stepSize: time.Second, 364 }, 365 { 366 r: Range{Start: 0, End: UnixNano(time.Millisecond)}, 367 stepSize: time.Second, 368 expected: []UnixNano{0}, 369 }, 370 { 371 r: Range{Start: 0, End: UnixNano(time.Second)}, 372 stepSize: time.Second, 373 expected: []UnixNano{0}, 374 }, 375 { 376 r: Range{Start: 0, End: UnixNano(3 * time.Second)}, 377 stepSize: time.Second, 378 expected: []UnixNano{0, UnixNano(time.Second), UnixNano(2 * time.Second)}, 379 }, 380 } 381 382 for _, tc := range testCases { 383 tc := tc 384 t.Run(fmt.Sprintf("%s", tc.r.String()), func(t *testing.T) { 385 var actual []UnixNano 386 tc.r.IterateForward(tc.stepSize, func(currStep UnixNano) bool { 387 actual = append(actual, currStep) 388 return true 389 }) 390 require.Equal(t, tc.expected, actual) 391 }) 392 } 393 } 394 395 func TestRangeIterateBackward(t *testing.T) { 396 testCases := []struct { 397 r Range 398 stepSize time.Duration 399 expected []UnixNano 400 }{ 401 { 402 r: Range{Start: 0, End: 0}, 403 stepSize: time.Second, 404 }, 405 { 406 r: Range{Start: 0, End: UnixNano(time.Millisecond)}, 407 stepSize: time.Second, 408 expected: []UnixNano{UnixNano(time.Millisecond)}, 409 }, 410 { 411 r: Range{Start: 0, End: UnixNano(time.Second)}, 412 stepSize: time.Second, 413 expected: []UnixNano{UnixNano(time.Second)}, 414 }, 415 { 416 r: Range{Start: 0, End: UnixNano(3 * time.Second)}, 417 stepSize: time.Second, 418 expected: []UnixNano{ 419 UnixNano(3 * time.Second), UnixNano(2 * time.Second), UnixNano(time.Second), 420 }, 421 }, 422 } 423 424 for _, tc := range testCases { 425 tc := tc 426 t.Run(fmt.Sprintf("%s", tc.r.String()), func(t *testing.T) { 427 var actual []UnixNano 428 tc.r.IterateBackward(tc.stepSize, func(currStep UnixNano) bool { 429 actual = append(actual, currStep) 430 return true 431 }) 432 require.Equal(t, tc.expected, actual) 433 }) 434 } 435 } 436 437 func TestRangeString(t *testing.T) { 438 start := ToUnixNano(time.Unix(1465430400, 0).UTC()) 439 r := Range{Start: start, End: start.Add(2 * time.Hour)} 440 require.Equal(t, "(2016-06-09 00:00:00 +0000 UTC,2016-06-09 02:00:00 +0000 UTC)", r.String()) 441 }