Skip to content

Commit

Permalink
fix(fill_struct): Work with non-pointer structs and pointers to non-s…
Browse files Browse the repository at this point in the history
…tructs
  • Loading branch information
dustmop committed Mar 18, 2019
1 parent a9aec5a commit 0d14bac
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 13 deletions.
2 changes: 1 addition & 1 deletion api/remote.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ func NewRemoteHandlers(node *p2p.QriNode) *RemoteHandlers {
// ReceiveHandler is the endpoint for remotes to receive daginfo
func (h *RemoteHandlers) ReceiveHandler(w http.ResponseWriter, r *http.Request) {
switch r.Method {
// no "OPTIONS" method here, because browsers should never hit this endpoint
// no "OPTIONS" method here, because browsers should never hit this endpoint
case "POST":
h.receiveDataset(w, r)
default:
Expand Down
22 changes: 10 additions & 12 deletions base/fill_struct.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ type ArbitrarySetter interface {
var (
// timeObj and strObj are used for reflect.TypeOf
timeObj time.Time
strObj string
strObj string
)

// putFieldsToTargetStruct iterates over the fields in the target struct, and assigns each
Expand Down Expand Up @@ -154,9 +154,13 @@ func putValueToPlace(val interface{}, place reflect.Value) error {
}
return fmt.Errorf("need type time, value %s", val)
}
// Other struct types are not handled currently. Should probably do the same thing
// as what's done for `pointer` below.
return fmt.Errorf("unknown struct %s", place.Type())
// Struct must be assigned from a map.
component, err := toStringMap(val)
if err != nil {
return err
}
// Recursion to handle sub-component.
return putFieldsToTargetStruct(component, place)
case reflect.Map:
if val == nil {
// If map is nil, nothing more to do.
Expand Down Expand Up @@ -211,17 +215,11 @@ func putValueToPlace(val interface{}, place reflect.Value) error {
alloc := reflect.New(place.Type().Elem())
place.Set(alloc)
inner := alloc.Elem()
// For now, can only point to a struct.
if inner.Kind() != reflect.Struct {
return fmt.Errorf("can only assign to *struct")
}
// Struct must be assigned from a map.
component, err := toStringMap(val)
err := putValueToPlace(val, inner)
if err != nil {
return err
}
// Recursion to handle sub-component.
return putFieldsToTargetStruct(component, inner)
return nil
default:
return fmt.Errorf("unknown kind %s", place.Kind())
}
Expand Down
61 changes: 61 additions & 0 deletions base/fill_struct_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,12 @@ type Collection struct {
Ptr *int
Dict map[string]string
List []string
Sub SubElement
}

type SubElement struct {
Num int
Things *map[string]string
}

func (c *Collection) SetArbitrary(key string, val interface{}) error {
Expand Down Expand Up @@ -435,3 +441,58 @@ func TestNilPointer(t *testing.T) {
t.Error("expected null Ptr")
}
}

func TestFillSubSection(t *testing.T) {
jsonData := `{
"Sub": {
"Num": 7
}
}`

data := make(map[string]interface{})
err := json.Unmarshal([]byte(jsonData), &data)
if err != nil {
panic(err)
}

var c Collection
err = FillStruct(data, &c)
if err != nil {
panic(err)
}

if c.Sub.Num != 7 {
t.Errorf("expected: c.Sub.Num should be 7, got: %d", c.Sub.Num)
}
}

func TestFillPointerToMap(t *testing.T) {
jsonData := `{
"Things": {
"a": "apple",
"b": "banana"
}
}`

data := make(map[string]interface{})
err := json.Unmarshal([]byte(jsonData), &data)
if err != nil {
panic(err)
}

var s SubElement
err = FillStruct(data, &s)
if err != nil {
panic(err)
}

if s.Things == nil {
t.Errorf("expected: s.Things should be non-nil")
}
if (*s.Things)["a"] != "apple" {
t.Errorf("expected: s.Things[\"a\"] should be \"apple\"")
}
if (*s.Things)["b"] != "banana" {
t.Errorf("expected: s.Things[\"b\"] should be \"banana\"")
}
}

0 comments on commit 0d14bac

Please sign in to comment.