Skip to content
Merged
5 changes: 2 additions & 3 deletions client/v2/autocli/flag/map.go
Original file line number Diff line number Diff line change
Expand Up @@ -202,11 +202,10 @@ func (m compositeMapType[T]) NewValue(ctx *context.Context, opts *Builder) Value
func (m *compositeMapValue[T]) Set(s string) error {
comaArgs := strings.Split(s, ",")
for _, arg := range comaArgs {
parts := strings.SplitN(arg, "=", 2)
if len(parts) != 2 {
key, val, found := strings.Cut(arg, "=")
if !found {
return errors.New("invalid format, expected key=value")
}
key, val := parts[0], parts[1]

keyValue, err := m.keyValueResolver(key)
if err != nil {
Expand Down
142 changes: 142 additions & 0 deletions client/v2/autocli/flag/map_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
package flag

import (
"context"
"errors"
"testing"

"github.com/stretchr/testify/assert"
"google.golang.org/protobuf/reflect/protoreflect"
)

type mockValue struct {
val string
err error
}

func (m *mockValue) Set(s string) error {
if m.err != nil {
return m.err
}
m.val = s
return nil
}

func (m *mockValue) String() string {
return m.val
}

func (m *mockValue) Type() string {
return "mock"
}

func (m *mockValue) Get(_ protoreflect.Value) (protoreflect.Value, error) {
if m.err != nil {
return protoreflect.Value{}, m.err
}
return protoreflect.ValueOfString(m.val), nil
}

type mockType struct {
err error
}

func (m *mockType) NewValue(ctx *context.Context, opts *Builder) Value {
return &mockValue{err: m.err}
}

func (m *mockType) DefaultValue() string {
return ""
}

func TestCompositeMapValue_Set(t *testing.T) {
tests := []struct {
name string
input string
resolver keyValueResolver[int]
valueType Type
expectErr bool
expectVals map[int]string
}{
{
name: "valid input",
input: "1=foo,2=bar",
resolver: func(s string) (int, error) {
switch s {
case "1":
return 1, nil
case "2":
return 2, nil
default:
return 0, errors.New("invalid key")
}
},
valueType: &mockType{},
expectErr: false,
expectVals: map[int]string{
1: "foo",
2: "bar",
},
},
{
name: "invalid format",
input: "1foo,2=bar",
resolver: func(s string) (int, error) {
return 0, nil
},
valueType: &mockType{},
expectErr: true,
},
{
name: "key resolver fails",
input: "1=foo,invalid=bar",
resolver: func(s string) (int, error) {
if s == "1" {
return 1, nil
}
return 0, errors.New("invalid key")
},
valueType: &mockType{},
expectErr: true,
},
{
name: "value parsing fails",
input: "1=foo,2=bar",
resolver: func(s string) (int, error) {
return 1, nil
},
valueType: &mockType{err: errors.New("value error")},
expectErr: true,
},
}

for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
ctx := context.Background()
m := &compositeMapValue[int]{
keyValueResolver: tc.resolver,
keyType: "int",
valueType: tc.valueType,
ctx: &ctx,
opts: &Builder{},
values: make(map[int]protoreflect.Value),
}

err := m.Set(tc.input)

if tc.expectErr {
assert.Error(t, err)
} else {
assert.NoError(t, err)

// Convert the protoreflect.Value map to a string map for comparison
actualVals := make(map[int]string)
for k, v := range m.values {
actualVals[k] = v.String()
}

assert.Equal(t, tc.expectVals, actualVals)
}
})
}
}
8 changes: 4 additions & 4 deletions client/v2/autocli/flag/maps/generic.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,15 @@ func (gm *genericMapValue[K, V]) Set(val string) error {
ss := strings.Split(val, ",")
out := make(map[K]V, len(ss))
for _, pair := range ss {
kv := strings.SplitN(pair, "=", 2)
if len(kv) != 2 {
key, val, found := strings.Cut(pair, "=")
if !found {
return fmt.Errorf("%s must be formatted as key=value", pair)
}
key, err := gm.Options.keyParser(kv[0])
parsedKey, err := gm.Options.keyParser(key)
if err != nil {
return err
}
out[key], err = gm.Options.valueParser(kv[1])
out[parsedKey], err = gm.Options.valueParser(val)
if err != nil {
return err
}
Expand Down
10 changes: 4 additions & 6 deletions store/rootmulti/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -796,14 +796,12 @@ func parsePath(path string) (storeName, subpath string, err error) {
return storeName, subpath, errorsmod.Wrapf(types.ErrUnknownRequest, "invalid path: %s", path)
}

paths := strings.SplitN(path[1:], "/", 2)
storeName = paths[0]

if len(paths) == 2 {
subpath = "/" + paths[1]
storeName, subpath, found := strings.Cut(path[1:], "/")
if !found {
return storeName, subpath, nil
}

return storeName, subpath, nil
return storeName, "/" + subpath, nil
}

//---------------------- Snapshotting ------------------
Expand Down
Loading