Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion libs/structs/structaccess/get.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,9 @@ func getValue(v any, path *structpath.PathNode) (reflect.Value, error) {
cur, ok = deref(cur)
if !ok {
// cannot proceed further due to nil encountered at current location
return reflect.Value{}, fmt.Errorf("%s: cannot access nil value", node.Parent().String())
// There could be 2 cases: the type is correct but value is not found due to nil, in this case NotFoundError is 100% correct.
// It could also be that path up to nil is correct, but not after. We don't know because we stop there. In this case NotFoundError refers to path up to nil.
return reflect.Value{}, &NotFoundError{node.Parent().String() + ": cannot access nil value"}
}

if idx, isIndex := node.Index(); isIndex {
Expand Down
54 changes: 23 additions & 31 deletions libs/structs/structaccess/get_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,12 @@ import (

// unexported global test case type
type testCase struct {
name string
path string
want any
wantSelf bool
errFmt string
notFound string // if set, expect NotFoundError with this message
typeHasPath bool
name string
path string
want any
wantSelf bool
errFmt string
notFound string // if set, expect NotFoundError with this message
}

func testGet(t *testing.T, obj any, path string, want any) {
Expand Down Expand Up @@ -197,10 +196,9 @@ func runCommonTests(t *testing.T, obj any) {
errFmt: "connection[0]: cannot index struct",
},
{
name: "out of range index",
path: "items[5]",
notFound: "items[5]: index out of range, length is 2",
typeHasPath: true,
name: "out of range index",
path: "items[5]",
notFound: "items[5]: index out of range, length is 2",
},
{
name: "no json tag field should not be accessible",
Expand All @@ -213,21 +211,19 @@ func runCommonTests(t *testing.T, obj any) {
errFmt: "items.id: cannot access key \"id\" on slice",
},
{
name: "nil pointer access",
path: "connection_not_set.id",
errFmt: "connection_not_set: cannot access nil value",
typeHasPath: true,
name: "nil pointer access",
path: "connection_not_set.id",
notFound: "connection_not_set: cannot access nil value",
},
{
name: "map non-string key type",
path: "map_int.any",
errFmt: "map_int.any: map key must be string, got int",
},
{
name: "map missing key",
path: "labels.missing",
notFound: "labels.missing: key \"missing\" not found in map",
typeHasPath: true,
name: "map missing key",
path: "labels.missing",
notFound: "labels.missing: key \"missing\" not found in map",
},
{
name: "json dash ignored",
Expand All @@ -247,33 +243,29 @@ func runCommonTests(t *testing.T, obj any) {
want: "first",
},
{
name: "key-value no match",
path: "items[id='missing']",
notFound: "items[id='missing']: no element found with id=\"missing\"",
typeHasPath: true,
name: "key-value no match",
path: "items[id='missing']",
notFound: "items[id='missing']: no element found with id=\"missing\"",
},
{
name: "key-value on non-slice",
path: "connection[id='abc']",
errFmt: "connection[id='abc']: cannot use key-value syntax on struct",
},
{
name: "key-value field not found",
path: "items[missing='value']",
notFound: "items[missing='value']: no element found with missing=\"value\"",
typeHasPath: true,
name: "key-value field not found",
path: "items[missing='value']",
notFound: "items[missing='value']: no element found with missing=\"value\"",
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
hasPathError := ValidateByString(reflect.TypeOf(obj), tt.path)
if tt.errFmt == "" && tt.notFound == "" || tt.typeHasPath {
if tt.errFmt == "" {
require.NoError(t, hasPathError)
} else if tt.errFmt != "" {
} else {
require.EqualError(t, hasPathError, tt.errFmt)
} else if tt.notFound != "" {
require.EqualError(t, hasPathError, tt.notFound)
}

got, err := GetByString(obj, tt.path)
Expand Down