util/slicesx: add HasPrefix, HasSuffix, CutPrefix, and CutSuffix functions

The standard library includes these for strings and byte slices,
but it lacks similar functions for generic slices of comparable types.
Although they are not as commonly used, these functions are useful
in scenarios such as working with field index sequences (i.e., []int)
via reflection.

Updates #12687

Signed-off-by: Nick Khyl <nickk@tailscale.com>
This commit is contained in:
Nick Khyl
2024-07-22 10:36:10 -05:00
committed by Nick Khyl
parent 1f94047475
commit d500a92926
2 changed files with 82 additions and 1 deletions

View File

@@ -151,3 +151,49 @@ func TestAppendMatching(t *testing.T) {
t.Errorf("got %v; want %v", v, wantOrigMem)
}
}
func TestCutPrefix(t *testing.T) {
tests := []struct {
name string
s, prefix []int
after []int
found bool
}{
{"has-prefix", []int{1, 2, 3}, []int{1}, []int{2, 3}, true},
{"exact-prefix", []int{1, 2, 3}, []int{1, 2, 3}, []int{}, true},
{"blank-prefix", []int{1, 2, 3}, []int{}, []int{1, 2, 3}, true},
{"no-prefix", []int{1, 2, 3}, []int{42}, []int{1, 2, 3}, false},
{"blank-slice", []int{}, []int{42}, []int{}, false},
{"blank-all", []int{}, []int{}, []int{}, true},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if after, found := CutPrefix(tt.s, tt.prefix); !slices.Equal(after, tt.after) || found != tt.found {
t.Errorf("CutPrefix(%v, %v) = %v, %v; want %v, %v", tt.s, tt.prefix, after, found, tt.after, tt.found)
}
})
}
}
func TestCutSuffix(t *testing.T) {
tests := []struct {
name string
s, suffix []int
before []int
found bool
}{
{"has-suffix", []int{1, 2, 3}, []int{3}, []int{1, 2}, true},
{"exact-suffix", []int{1, 2, 3}, []int{1, 2, 3}, []int{}, true},
{"blank-suffix", []int{1, 2, 3}, []int{}, []int{1, 2, 3}, true},
{"no-suffix", []int{1, 2, 3}, []int{42}, []int{1, 2, 3}, false},
{"blank-slice", []int{}, []int{42}, []int{}, false},
{"blank-all", []int{}, []int{}, []int{}, true},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if before, found := CutSuffix(tt.s, tt.suffix); !slices.Equal(before, tt.before) || found != tt.found {
t.Errorf("CutSuffix(%v, %v) = %v, %v; want %v, %v", tt.s, tt.suffix, before, found, tt.before, tt.found)
}
})
}
}