// Copyright (c) Tailscale Inc & AUTHORS // SPDX-License-Identifier: BSD-3-Clause package uniq_test import ( "reflect" "strconv" "testing" "tailscale.com/util/uniq" ) func runTests(t *testing.T, cb func(*[]uint32)) { tests := []struct { // Use uint32 to be different from an int-typed slice index in []uint32 want []uint32 }{ {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{}}, } for _, test := range tests { in := make([]uint32, len(test.in)) copy(in, test.in) cb(&test.in) 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) } } } } func TestModifySlice(t *testing.T) { runTests(t, func(slice *[]uint32) { uniq.ModifySlice(slice) }) } func TestModifySliceFunc(t *testing.T) { runTests(t, func(slice *[]uint32) { uniq.ModifySliceFunc(slice, func(i, j uint32) bool { return i == j }) }) } 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() for range b.N { s = s[:size] reset(s) uniq.ModifySlice(&s) } }