marshal: do not encode embedded structs as sub-table (#368)
Currently, the marshalling code encodes the embedded structs as sub-tables. This is a bit unexpected, as it differs from what encoding/json does in that case: https://play.golang.org/p/KDPaGtrijV1 Unmarshalling code handles this scenario gracefully. This PR adapts the encoder to behave like encoding/json. Fields in an embedded struct are promoted to the top level table. In case the embedded struct is named in the tag, it will still encode as a sub-table. The added PromoteAnonymous option on the Encoder allows configuring the old behavior, where anonymous structs are encoded as sub-tables. On duplicate keys, the behavior of encoding/json is mimicked: Fields from anonymous structs are shadowed by regular fields. An example is added to show the affects of setting PromoteAnonymous.
This commit is contained in:
@@ -1974,6 +1974,99 @@ func TestUnmarshalDefaultFailureUnsupported(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestMarshalNestedAnonymousStructs(t *testing.T) {
|
||||
type Embedded struct {
|
||||
Value string `toml:"value"`
|
||||
Top struct {
|
||||
Value string `toml:"value"`
|
||||
} `toml:"top"`
|
||||
}
|
||||
|
||||
type Named struct {
|
||||
Value string `toml:"value"`
|
||||
}
|
||||
|
||||
var doc struct {
|
||||
Embedded
|
||||
Named `toml:"named"`
|
||||
Anonymous struct {
|
||||
Value string `toml:"value"`
|
||||
} `toml:"anonymous"`
|
||||
}
|
||||
|
||||
expected := `value = ""
|
||||
|
||||
[anonymous]
|
||||
value = ""
|
||||
|
||||
[named]
|
||||
value = ""
|
||||
|
||||
[top]
|
||||
value = ""
|
||||
`
|
||||
|
||||
result, err := Marshal(doc)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %s", err.Error())
|
||||
}
|
||||
if !bytes.Equal(result, []byte(expected)) {
|
||||
t.Errorf("Bad marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, string(result))
|
||||
}
|
||||
}
|
||||
|
||||
func TestEncoderPromoteNestedAnonymousStructs(t *testing.T) {
|
||||
type Embedded struct {
|
||||
Value string `toml:"value"`
|
||||
}
|
||||
|
||||
var doc struct {
|
||||
Embedded
|
||||
}
|
||||
|
||||
expected := `
|
||||
[Embedded]
|
||||
value = ""
|
||||
`
|
||||
var buf bytes.Buffer
|
||||
if err := NewEncoder(&buf).PromoteAnonymous(true).Encode(doc); err != nil {
|
||||
t.Fatalf("unexpected error: %s", err.Error())
|
||||
}
|
||||
if !bytes.Equal(buf.Bytes(), []byte(expected)) {
|
||||
t.Errorf("Bad marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, buf.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestMarshalNestedAnonymousStructs_DuplicateField(t *testing.T) {
|
||||
type Embedded struct {
|
||||
Value string `toml:"value"`
|
||||
Top struct {
|
||||
Value string `toml:"value"`
|
||||
} `toml:"top"`
|
||||
}
|
||||
|
||||
var doc struct {
|
||||
Value string `toml:"value"`
|
||||
Embedded
|
||||
}
|
||||
doc.Embedded.Value = "shadowed"
|
||||
doc.Value = "shadows"
|
||||
|
||||
expected := `value = "shadows"
|
||||
|
||||
[top]
|
||||
value = ""
|
||||
`
|
||||
|
||||
result, err := Marshal(doc)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %s", err.Error())
|
||||
}
|
||||
if !bytes.Equal(result, []byte(expected)) {
|
||||
t.Errorf("Bad marshal: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expected, string(result))
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnmarshalNestedAnonymousStructs(t *testing.T) {
|
||||
type Nested struct {
|
||||
Value string `toml:"nested_field"`
|
||||
|
||||
Reference in New Issue
Block a user