mirror of
https://github.com/docker/cli.git
synced 2026-09-27 01:40:31 -04:00
Merge pull request #7267 from thaJeztah/fix_aliases
cmd/docker: fix stringSliceReplaceAt with overlapping matches
This commit is contained in:
+19
-25
@@ -1,32 +1,26 @@
|
||||
package main
|
||||
|
||||
func stringSliceIndex(s, subs []string) int {
|
||||
j := 0
|
||||
if len(subs) > 0 {
|
||||
for i, x := range s {
|
||||
if j < len(subs) && subs[j] == x {
|
||||
j++
|
||||
} else {
|
||||
j = 0
|
||||
}
|
||||
if len(subs) == j {
|
||||
return i + 1 - j
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
import "slices"
|
||||
|
||||
// stringSliceReplaceAt replaces the sub-slice find, with the sub-slice replace, in the string
|
||||
// slice s, returning a new slice and a boolean indicating if the replacement happened.
|
||||
// requireIdx is the index at which old needs to be found at (or -1 to disregard that).
|
||||
// stringSliceReplaceAt replaces the sub-slice find with the sub-slice replace in s,
|
||||
// returning a new slice and a boolean indicating whether the replacement happened.
|
||||
// requireIndex is the index at which find must be found, or -1 to disregard it.
|
||||
func stringSliceReplaceAt(s, find, replace []string, requireIndex int) ([]string, bool) {
|
||||
idx := stringSliceIndex(s, find)
|
||||
if (requireIndex != -1 && requireIndex != idx) || idx == -1 {
|
||||
if len(find) == 0 {
|
||||
return s, false
|
||||
}
|
||||
out := append([]string{}, s[:idx]...)
|
||||
out = append(out, replace...)
|
||||
out = append(out, s[idx+len(find):]...)
|
||||
return out, true
|
||||
|
||||
if requireIndex >= 0 {
|
||||
if requireIndex+len(find) > len(s) || !slices.Equal(s[requireIndex:requireIndex+len(find)], find) {
|
||||
return s, false
|
||||
}
|
||||
return slices.Concat(s[:requireIndex], replace, s[requireIndex+len(find):]), true
|
||||
}
|
||||
|
||||
for i := range len(s) - len(find) + 1 {
|
||||
if slices.Equal(s[i:i+len(find)], find) {
|
||||
return slices.Concat(s[:i], replace, s[i+len(find):]), true
|
||||
}
|
||||
}
|
||||
return s, false
|
||||
}
|
||||
|
||||
@@ -7,27 +7,80 @@ import (
|
||||
)
|
||||
|
||||
func TestStringSliceReplaceAt(t *testing.T) {
|
||||
out, ok := stringSliceReplaceAt([]string{"abc", "foo", "bar", "bax"}, []string{"foo", "bar"}, []string{"baz"}, -1)
|
||||
assert.Assert(t, ok)
|
||||
assert.DeepEqual(t, []string{"abc", "baz", "bax"}, out)
|
||||
tests := []struct {
|
||||
name string
|
||||
s []string
|
||||
find []string
|
||||
replace []string
|
||||
requireIndex int
|
||||
expected []string
|
||||
ok bool
|
||||
}{
|
||||
{
|
||||
name: "replace",
|
||||
s: []string{"abc", "foo", "bar", "bax"},
|
||||
find: []string{"foo", "bar"},
|
||||
replace: []string{"baz"},
|
||||
requireIndex: -1,
|
||||
expected: []string{"abc", "baz", "bax"},
|
||||
ok: true,
|
||||
},
|
||||
{
|
||||
name: "find longer than input",
|
||||
s: []string{"foo"},
|
||||
find: []string{"foo", "bar"},
|
||||
replace: []string{"baz"},
|
||||
requireIndex: -1,
|
||||
expected: []string{"foo"},
|
||||
},
|
||||
{
|
||||
name: "wrong required index",
|
||||
s: []string{"abc", "foo", "bar", "bax"},
|
||||
find: []string{"foo", "bar"},
|
||||
replace: []string{"baz"},
|
||||
requireIndex: 0,
|
||||
expected: []string{"abc", "foo", "bar", "bax"},
|
||||
},
|
||||
{
|
||||
name: "required index",
|
||||
s: []string{"foo", "bar", "bax"},
|
||||
find: []string{"foo", "bar"},
|
||||
replace: []string{"baz"},
|
||||
requireIndex: 0,
|
||||
expected: []string{"baz", "bax"},
|
||||
ok: true,
|
||||
},
|
||||
{
|
||||
name: "remove",
|
||||
s: []string{"abc", "foo", "bar", "baz"},
|
||||
find: []string{"foo", "bar"},
|
||||
requireIndex: -1,
|
||||
expected: []string{"abc", "baz"},
|
||||
ok: true,
|
||||
},
|
||||
{
|
||||
name: "empty find",
|
||||
s: []string{"foo"},
|
||||
replace: []string{"baz"},
|
||||
requireIndex: -1,
|
||||
expected: []string{"foo"},
|
||||
},
|
||||
{
|
||||
name: "overlapping match",
|
||||
s: []string{"a", "a", "b"},
|
||||
find: []string{"a", "b"},
|
||||
replace: []string{"c"},
|
||||
requireIndex: -1,
|
||||
expected: []string{"a", "c"},
|
||||
ok: true,
|
||||
},
|
||||
}
|
||||
|
||||
out, ok = stringSliceReplaceAt([]string{"foo"}, []string{"foo", "bar"}, []string{"baz"}, -1)
|
||||
assert.Assert(t, !ok)
|
||||
assert.DeepEqual(t, []string{"foo"}, out)
|
||||
|
||||
out, ok = stringSliceReplaceAt([]string{"abc", "foo", "bar", "bax"}, []string{"foo", "bar"}, []string{"baz"}, 0)
|
||||
assert.Assert(t, !ok)
|
||||
assert.DeepEqual(t, []string{"abc", "foo", "bar", "bax"}, out)
|
||||
|
||||
out, ok = stringSliceReplaceAt([]string{"foo", "bar", "bax"}, []string{"foo", "bar"}, []string{"baz"}, 0)
|
||||
assert.Assert(t, ok)
|
||||
assert.DeepEqual(t, []string{"baz", "bax"}, out)
|
||||
|
||||
out, ok = stringSliceReplaceAt([]string{"abc", "foo", "bar", "baz"}, []string{"foo", "bar"}, nil, -1)
|
||||
assert.Assert(t, ok)
|
||||
assert.DeepEqual(t, []string{"abc", "baz"}, out)
|
||||
|
||||
out, ok = stringSliceReplaceAt([]string{"foo"}, nil, []string{"baz"}, -1)
|
||||
assert.Assert(t, !ok)
|
||||
assert.DeepEqual(t, []string{"foo"}, out)
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
out, ok := stringSliceReplaceAt(tc.s, tc.find, tc.replace, tc.requireIndex)
|
||||
assert.Equal(t, tc.ok, ok)
|
||||
assert.DeepEqual(t, tc.expected, out)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user