package tsdb import ( "fmt" "testing" "github.com/google/go-cmp/cmp" ) func makeIntegerArray(count int, min, max int64) *IntegerArray { vals := NewIntegerArrayLen(count) ts := min inc := (max - min) / int64(count) for i := 0; i < count; i++ { vals.Timestamps[i] = ts ts += inc } return vals } func makeIntegerArrayFromSlice(t []int64) *IntegerArray { iv := NewIntegerArrayLen(len(t)) copy(iv.Timestamps, t) return iv } func TestIntegerArray_FindRangeNoValues(t *testing.T) { var vals IntegerArray l, r := vals.FindRange(0, 100) if exp := -1; l != exp { t.Errorf("invalid l; exp=%d, got=%d", exp, l) } if exp := -1; r != exp { t.Errorf("invalid r; exp=%d, got=%d", exp, r) } } func TestIntegerArray_FindRange(t *testing.T) { vals := makeIntegerArrayFromSlice([]int64{10, 11, 13, 15, 17, 20, 21}) cases := []struct { min, max int64 l, r int }{ {12, 20, 2, 5}, {22, 40, -1, -1}, {1, 9, -1, -1}, {1, 10, 0, 0}, {1, 11, 0, 1}, {15, 15, 3, 3}, } for _, tc := range cases { t.Run(fmt.Sprintf("%d→%d", tc.min, tc.max), func(t *testing.T) { l, r := vals.FindRange(tc.min, tc.max) if l != tc.l { t.Errorf("left: got %d, exp %d", l, tc.l) } if r != tc.r { t.Errorf("right: got %d, exp %d", r, tc.r) } }) } } func TestIntegerArray_Exclude(t *testing.T) { cases := []struct { n string min, max int64 exp []int64 }{ {"excl bad range", 18, 11, []int64{10, 12, 14, 16, 18}}, {"excl none-lo", 0, 9, []int64{10, 12, 14, 16, 18}}, {"excl none-hi", 19, 30, []int64{10, 12, 14, 16, 18}}, {"excl first", 0, 10, []int64{12, 14, 16, 18}}, {"excl last", 18, 20, []int64{10, 12, 14, 16}}, {"excl all but first and last", 12, 16, []int64{10, 18}}, {"excl none in middle", 13, 13, []int64{10, 12, 14, 16, 18}}, {"excl middle", 14, 14, []int64{10, 12, 16, 18}}, {"excl suffix", 14, 18, []int64{10, 12}}, } for _, tc := range cases { t.Run(fmt.Sprintf("%s[%d,%d]", tc.n, tc.min, tc.max), func(t *testing.T) { vals := makeIntegerArray(5, 10, 20) vals.Exclude(tc.min, tc.max) got := vals.Timestamps if !cmp.Equal(got, tc.exp) { t.Errorf("unexpected values -got/+exp\n%s", cmp.Diff(got, tc.exp)) } }) } } func TestIntegerArray_Include(t *testing.T) { cases := []struct { n string min, max int64 exp []int64 }{ {"incl none-lo", 0, 9, []int64{}}, {"incl none-hi", 19, 30, []int64{}}, {"incl first", 0, 10, []int64{10}}, {"incl last", 18, 20, []int64{18}}, {"incl all but first and last", 12, 16, []int64{12, 14, 16}}, {"incl none in middle", 13, 13, []int64{}}, {"incl middle", 14, 14, []int64{14}}, } for _, tc := range cases { t.Run(fmt.Sprintf("%s[%d,%d]", tc.n, tc.min, tc.max), func(t *testing.T) { vals := makeIntegerArray(5, 10, 20) vals.Include(tc.min, tc.max) got := vals.Timestamps if !cmp.Equal(got, tc.exp) { t.Errorf("unexpected values -got/+exp\n%s", cmp.Diff(got, tc.exp)) } }) } } func benchExclude(b *testing.B, vals *IntegerArray, min, max int64) { b.ResetTimer() for i := 0; i < b.N; i++ { vals.Exclude(min, max) } } func BenchmarkIntegerArray_ExcludeNone_1000(b *testing.B) { benchExclude(b, makeIntegerArray(1000, 1000, 2000), 0, 500) } func BenchmarkIntegerArray_ExcludeMiddleHalf_1000(b *testing.B) { benchExclude(b, makeIntegerArray(1000, 1000, 2000), 1250, 1750) } func BenchmarkIntegerArray_ExcludeFirst_1000(b *testing.B) { benchExclude(b, makeIntegerArray(1000, 1000, 2000), 0, 1000) } func BenchmarkIntegerArray_ExcludeLast_1000(b *testing.B) { benchExclude(b, makeIntegerArray(1000, 1000, 2000), 1999, 2000) } func BenchmarkIntegerArray_ExcludeNone_10000(b *testing.B) { benchExclude(b, makeIntegerArray(10000, 10000, 20000), 00, 5000) } func BenchmarkIntegerArray_ExcludeMiddleHalf_10000(b *testing.B) { benchExclude(b, makeIntegerArray(10000, 10000, 20000), 12500, 17500) } func BenchmarkIntegerArray_ExcludeFirst_10000(b *testing.B) { benchExclude(b, makeIntegerArray(10000, 10000, 20000), 0, 10000) } func BenchmarkIntegerArray_ExcludeLast_10000(b *testing.B) { benchExclude(b, makeIntegerArray(10000, 10000, 20000), 19999, 20000) } func benchInclude(b *testing.B, vals *IntegerArray, min, max int64) { src := *vals tmp := NewIntegerArrayLen(vals.Len()) copy(tmp.Timestamps, vals.Timestamps) copy(tmp.Values, vals.Values) b.ResetTimer() for i := 0; i < b.N; i++ { vals.Include(min, max) *vals = src copy(vals.Timestamps, tmp.Timestamps) copy(vals.Values, tmp.Values) } } func BenchmarkIntegerArray_IncludeNone_1000(b *testing.B) { benchInclude(b, makeIntegerArray(1000, 1000, 2000), 0, 500) } func BenchmarkIntegerArray_IncludeMiddleHalf_1000(b *testing.B) { benchInclude(b, makeIntegerArray(1000, 1000, 2000), 1250, 1750) } func BenchmarkIntegerArray_IncludeFirst_1000(b *testing.B) { benchInclude(b, makeIntegerArray(1000, 1000, 2000), 0, 1000) } func BenchmarkIntegerArray_IncludeLast_1000(b *testing.B) { benchInclude(b, makeIntegerArray(1000, 1000, 2000), 1999, 2000) } func BenchmarkIntegerArray_IncludeNone_10000(b *testing.B) { benchInclude(b, makeIntegerArray(10000, 10000, 20000), 00, 5000) } func BenchmarkIntegerArray_IncludeMiddleHalf_10000(b *testing.B) { benchInclude(b, makeIntegerArray(10000, 10000, 20000), 12500, 17500) } func BenchmarkIntegerArray_IncludeFirst_10000(b *testing.B) { benchInclude(b, makeIntegerArray(10000, 10000, 20000), 0, 10000) } func BenchmarkIntegerArray_IncludeLast_10000(b *testing.B) { benchInclude(b, makeIntegerArray(10000, 10000, 20000), 19999, 20000) }