2023-01-27 21:37:20 +00:00
|
|
|
// Copyright (c) Tailscale Inc & AUTHORS
|
|
|
|
// SPDX-License-Identifier: BSD-3-Clause
|
2020-10-01 20:56:46 +00:00
|
|
|
|
|
|
|
package uniq_test
|
|
|
|
|
|
|
|
import (
|
|
|
|
"reflect"
|
|
|
|
"strconv"
|
|
|
|
"testing"
|
|
|
|
|
|
|
|
"tailscale.com/util/uniq"
|
|
|
|
)
|
|
|
|
|
2022-08-30 22:51:18 +00:00
|
|
|
func runTests(t *testing.T, cb func(*[]uint32)) {
|
2020-10-01 20:56:46 +00:00
|
|
|
tests := []struct {
|
2022-08-30 22:51:18 +00:00
|
|
|
// Use uint32 to be different from an int-typed slice index
|
|
|
|
in []uint32
|
|
|
|
want []uint32
|
2020-10-01 20:56:46 +00:00
|
|
|
}{
|
2022-08-30 22:51:18 +00:00
|
|
|
{in: []uint32{0, 1, 2}, want: []uint32{0, 1, 2}},
|
|
|
|
{in: []uint32{0, 1, 2, 2}, want: []uint32{0, 1, 2}},
|
|
|
|
{in: []uint32{0, 0, 1, 2}, want: []uint32{0, 1, 2}},
|
|
|
|
{in: []uint32{0, 1, 0, 2}, want: []uint32{0, 1, 0, 2}},
|
|
|
|
{in: []uint32{0}, want: []uint32{0}},
|
|
|
|
{in: []uint32{0, 0}, want: []uint32{0}},
|
|
|
|
{in: []uint32{}, want: []uint32{}},
|
2020-10-01 20:56:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for _, test := range tests {
|
2022-08-30 22:51:18 +00:00
|
|
|
in := make([]uint32, len(test.in))
|
2020-10-01 20:56:46 +00:00
|
|
|
copy(in, test.in)
|
2022-08-30 21:56:51 +00:00
|
|
|
cb(&test.in)
|
2020-10-01 20:56:46 +00:00
|
|
|
if !reflect.DeepEqual(test.in, test.want) {
|
|
|
|
t.Errorf("uniq.Slice(%v) = %v, want %v", in, test.in, test.want)
|
|
|
|
}
|
|
|
|
start := len(test.in)
|
|
|
|
test.in = test.in[:cap(test.in)]
|
|
|
|
for i := start; i < len(in); i++ {
|
|
|
|
if test.in[i] != 0 {
|
|
|
|
t.Errorf("uniq.Slice(%v): non-0 in tail of %v at index %v", in, test.in, i)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-08-30 21:56:51 +00:00
|
|
|
func TestModifySlice(t *testing.T) {
|
2022-08-30 22:51:18 +00:00
|
|
|
runTests(t, func(slice *[]uint32) {
|
2022-08-30 21:56:51 +00:00
|
|
|
uniq.ModifySlice(slice)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2022-08-30 22:51:18 +00:00
|
|
|
func TestModifySliceFunc(t *testing.T) {
|
|
|
|
runTests(t, func(slice *[]uint32) {
|
|
|
|
uniq.ModifySliceFunc(slice, func(i, j uint32) bool {
|
|
|
|
return i == j
|
|
|
|
})
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2020-10-01 20:56:46 +00:00
|
|
|
func Benchmark(b *testing.B) {
|
|
|
|
benches := []struct {
|
|
|
|
name string
|
|
|
|
reset func(s []byte)
|
|
|
|
}{
|
|
|
|
{name: "AllDups",
|
|
|
|
reset: func(s []byte) {
|
|
|
|
for i := range s {
|
|
|
|
s[i] = '*'
|
|
|
|
}
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{name: "NoDups",
|
|
|
|
reset: func(s []byte) {
|
|
|
|
for i := range s {
|
|
|
|
s[i] = byte(i)
|
|
|
|
}
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, bb := range benches {
|
|
|
|
b.Run(bb.name, func(b *testing.B) {
|
|
|
|
for size := 1; size <= 4096; size *= 16 {
|
|
|
|
b.Run(strconv.Itoa(size), func(b *testing.B) {
|
|
|
|
benchmark(b, 64, bb.reset)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func benchmark(b *testing.B, size int64, reset func(s []byte)) {
|
|
|
|
b.ReportAllocs()
|
|
|
|
b.SetBytes(size)
|
|
|
|
s := make([]byte, size)
|
|
|
|
b.ResetTimer()
|
2024-04-16 20:15:13 +00:00
|
|
|
for range b.N {
|
2020-10-01 20:56:46 +00:00
|
|
|
s = s[:size]
|
|
|
|
reset(s)
|
2022-08-30 21:56:51 +00:00
|
|
|
uniq.ModifySlice(&s)
|
2020-10-01 20:56:46 +00:00
|
|
|
}
|
|
|
|
}
|