Skip to content

Commit

Permalink
fix(GetForToken): added support for pointer to interface{}
Browse files Browse the repository at this point in the history
reflect-based switch doesn't work when the value passed is *any:
the resulting indirection is typed as reflect.Interface and not
the actual underlying type.

* added more stringent checking on nil values (i.e. covers
  interface{}(nil)
* contributes: go-swagger/go-swagger#1898 (pointers to content of a
  x-... swagger extension)

Signed-off-by: Frederic BIDON <fredbi@yahoo.com>
  • Loading branch information
fredbi committed Dec 21, 2023
1 parent 6cf0fb8 commit 344388f
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 13 deletions.
24 changes: 22 additions & 2 deletions pointer.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,16 +110,36 @@ func SetForToken(document any, decodedToken string, value any) (any, error) {
return document, setSingleImpl(document, value, decodedToken, swag.DefaultJSONNameProvider)
}

func isNil(input any) bool {
if input == nil {
return true
}

kind := reflect.TypeOf(input).Kind()
switch kind { //nolint:exhaustive
case reflect.Ptr, reflect.Map, reflect.Slice, reflect.Chan:
return reflect.ValueOf(input).IsNil()
default:
return false
}
}

func getSingleImpl(node any, decodedToken string, nameProvider *swag.NameProvider) (any, reflect.Kind, error) {
rValue := reflect.Indirect(reflect.ValueOf(node))
kind := rValue.Kind()
if isNil(node) {
return nil, kind, fmt.Errorf("nil value has not field %q", decodedToken)
}

if rValue.Type().Implements(jsonPointableType) {
r, err := node.(JSONPointable).JSONLookup(decodedToken)
switch typed := node.(type) {
case JSONPointable:
r, err := typed.JSONLookup(decodedToken)
if err != nil {
return nil, kind, err
}
return r, kind, nil
case *any: // case of a pointer to interface, that is not resolved by reflect.Indirect
return getSingleImpl(*typed, decodedToken, nameProvider)
}

switch kind { //nolint:exhaustive
Expand Down
59 changes: 48 additions & 11 deletions pointer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -140,19 +140,56 @@ func TestIsEmpty(t *testing.T) {
func TestGetSingle(t *testing.T) {
const in = `/obj`

_, err := New(in)
require.NoError(t, err)
result, _, err := GetForToken(testDocumentJSON, "obj")
require.NoError(t, err)
assert.Len(t, result, TestNodeObjNBItems)
t.Run("should create a new JSON pointer", func(t *testing.T) {
_, err := New(in)
require.NoError(t, err)
})

result, _, err = GetForToken(testStructJSONDoc, "Obj")
require.Error(t, err)
assert.Nil(t, result)
t.Run(`should find token "obj" in JSON`, func(t *testing.T) {
result, _, err := GetForToken(testDocumentJSON, "obj")
require.NoError(t, err)
assert.Len(t, result, TestNodeObjNBItems)
})

result, _, err = GetForToken(testStructJSONDoc, "Obj2")
require.Error(t, err)
assert.Nil(t, result)
t.Run(`should find token "obj" in type alias interface`, func(t *testing.T) {
type alias interface{}
var in alias = testDocumentJSON
result, _, err := GetForToken(in, "obj")
require.NoError(t, err)
assert.Len(t, result, TestNodeObjNBItems)
})

t.Run(`should find token "obj" in pointer to interface`, func(t *testing.T) {
in := &testDocumentJSON
result, _, err := GetForToken(in, "obj")
require.NoError(t, err)
assert.Len(t, result, TestNodeObjNBItems)
})

t.Run(`should not find token "Obj" in struct`, func(t *testing.T) {
result, _, err := GetForToken(testStructJSONDoc, "Obj")
require.Error(t, err)
assert.Nil(t, result)
})

t.Run(`should not find token "Obj2" in struct`, func(t *testing.T) {
result, _, err := GetForToken(testStructJSONDoc, "Obj2")
require.Error(t, err)
assert.Nil(t, result)
})

t.Run(`should not find token in nil`, func(t *testing.T) {
result, _, err := GetForToken(nil, "obj")
require.Error(t, err)
assert.Nil(t, result)
})

t.Run(`should not find token in nil interface`, func(t *testing.T) {
var in interface{}
result, _, err := GetForToken(in, "obj")
require.Error(t, err)
assert.Nil(t, result)
})
}

type pointableImpl struct {
Expand Down

0 comments on commit 344388f

Please sign in to comment.