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  }