1
0
mirror of https://github.com/golang/go synced 2024-11-18 17:54:57 -07:00

encoding/xml: fix incorrect indirect code in chardata, comment, innerxml fields

The new tests in this CL have been checked against Go 1.7 as well
and all pass in Go 1.7, with the one exception noted in a comment
(an intentional change to omitempty already present before this CL).

CL 15684 made the intentional change to omitempty.
This CL fixes bugs introduced along the way.

Most of these are corner cases that are arguably not that important,
but they've always worked all the way back to Go 1, and someone
cared enough to file #19063. The most significant problem found
while adding tests is that in the case of a nil *string field with
`xml:",chardata"`, the existing code silently stops processing not just
that field but the entire remainder of the struct.
Even if #19063 were not worth fixing, this chardata bug would be.

Fixes #19063.

Change-Id: I318cf8f9945e1a4615982d9904e109fde577ebf9
Reviewed-on: https://go-review.googlesource.com/36954
Run-TryBot: Russ Cox <rsc@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Daniel Martí <mvdan@mvdan.cc>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
This commit is contained in:
Russ Cox 2017-02-14 00:17:50 -05:00 committed by Ian Lance Taylor
parent eebd8f51e8
commit 72aa757ddd
2 changed files with 554 additions and 16 deletions

View File

@ -775,6 +775,20 @@ func (p *printer) marshalSimple(typ reflect.Type, val reflect.Value) (string, []
var ddBytes = []byte("--") var ddBytes = []byte("--")
// indirect drills into interfaces and pointers, returning the pointed-at value.
// If it encounters a nil interface or pointer, indirect returns that nil value.
// This can turn into an infinite loop given a cyclic chain,
// but it matches the Go 1 behavior.
func indirect(vf reflect.Value) reflect.Value {
for vf.Kind() == reflect.Interface || vf.Kind() == reflect.Ptr {
if vf.IsNil() {
return vf
}
vf = vf.Elem()
}
return vf
}
func (p *printer) marshalStruct(tinfo *typeInfo, val reflect.Value) error { func (p *printer) marshalStruct(tinfo *typeInfo, val reflect.Value) error {
s := parentStack{p: p} s := parentStack{p: p}
for i := range tinfo.fields { for i := range tinfo.fields {
@ -816,17 +830,9 @@ func (p *printer) marshalStruct(tinfo *typeInfo, val reflect.Value) error {
continue continue
} }
} }
// Drill into interfaces and pointers.
// This can turn into an infinite loop given a cyclic chain,
// but it matches the Go 1 behavior.
for vf.Kind() == reflect.Interface || vf.Kind() == reflect.Ptr {
if vf.IsNil() {
return nil
}
vf = vf.Elem()
}
var scratch [64]byte var scratch [64]byte
vf = indirect(vf)
switch vf.Kind() { switch vf.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
if err := emit(p, strconv.AppendInt(scratch[:0], vf.Int(), 10)); err != nil { if err := emit(p, strconv.AppendInt(scratch[:0], vf.Int(), 10)); err != nil {
@ -861,6 +867,7 @@ func (p *printer) marshalStruct(tinfo *typeInfo, val reflect.Value) error {
if err := s.trim(finfo.parents); err != nil { if err := s.trim(finfo.parents); err != nil {
return err return err
} }
vf = indirect(vf)
k := vf.Kind() k := vf.Kind()
if !(k == reflect.String || k == reflect.Slice && vf.Type().Elem().Kind() == reflect.Uint8) { if !(k == reflect.String || k == reflect.Slice && vf.Type().Elem().Kind() == reflect.Uint8) {
return fmt.Errorf("xml: bad type for comment field of %s", val.Type()) return fmt.Errorf("xml: bad type for comment field of %s", val.Type())
@ -901,6 +908,7 @@ func (p *printer) marshalStruct(tinfo *typeInfo, val reflect.Value) error {
continue continue
case fInnerXml: case fInnerXml:
vf = indirect(vf)
iface := vf.Interface() iface := vf.Interface()
switch raw := iface.(type) { switch raw := iface.(type) {
case []byte: case []byte:

View File

@ -386,6 +386,140 @@ func ifaceptr(x interface{}) interface{} {
return &x return &x
} }
func stringptr(x string) *string {
return &x
}
type T1 struct{}
type T2 struct{}
type T3 struct{}
type IndirComment struct {
T1 T1
Comment *string `xml:",comment"`
T2 T2
}
type DirectComment struct {
T1 T1
Comment string `xml:",comment"`
T2 T2
}
type IfaceComment struct {
T1 T1
Comment interface{} `xml:",comment"`
T2 T2
}
type IndirChardata struct {
T1 T1
Chardata *string `xml:",chardata"`
T2 T2
}
type DirectChardata struct {
T1 T1
Chardata string `xml:",chardata"`
T2 T2
}
type IfaceChardata struct {
T1 T1
Chardata interface{} `xml:",chardata"`
T2 T2
}
type IndirCDATA struct {
T1 T1
CDATA *string `xml:",cdata"`
T2 T2
}
type DirectCDATA struct {
T1 T1
CDATA string `xml:",cdata"`
T2 T2
}
type IfaceCDATA struct {
T1 T1
CDATA interface{} `xml:",cdata"`
T2 T2
}
type IndirInnerXML struct {
T1 T1
InnerXML *string `xml:",innerxml"`
T2 T2
}
type DirectInnerXML struct {
T1 T1
InnerXML string `xml:",innerxml"`
T2 T2
}
type IfaceInnerXML struct {
T1 T1
InnerXML interface{} `xml:",innerxml"`
T2 T2
}
type IndirElement struct {
T1 T1
Element *string
T2 T2
}
type DirectElement struct {
T1 T1
Element string
T2 T2
}
type IfaceElement struct {
T1 T1
Element interface{}
T2 T2
}
type IndirOmitEmpty struct {
T1 T1
OmitEmpty *string `xml:",omitempty"`
T2 T2
}
type DirectOmitEmpty struct {
T1 T1
OmitEmpty string `xml:",omitempty"`
T2 T2
}
type IfaceOmitEmpty struct {
T1 T1
OmitEmpty interface{} `xml:",omitempty"`
T2 T2
}
type IndirAny struct {
T1 T1
Any *string `xml:",any"`
T2 T2
}
type DirectAny struct {
T1 T1
Any string `xml:",any"`
T2 T2
}
type IfaceAny struct {
T1 T1
Any interface{} `xml:",any"`
T2 T2
}
var ( var (
nameAttr = "Sarah" nameAttr = "Sarah"
ageAttr = uint(12) ageAttr = uint(12)
@ -398,10 +532,12 @@ var (
// please try to make them two-way as well to ensure that // please try to make them two-way as well to ensure that
// marshaling and unmarshaling are as symmetrical as feasible. // marshaling and unmarshaling are as symmetrical as feasible.
var marshalTests = []struct { var marshalTests = []struct {
Value interface{} Value interface{}
ExpectXML string ExpectXML string
MarshalOnly bool MarshalOnly bool
UnmarshalOnly bool MarshalError string
UnmarshalOnly bool
UnmarshalError string
}{ }{
// Test nil marshals to nothing // Test nil marshals to nothing
{Value: nil, ExpectXML: ``, MarshalOnly: true}, {Value: nil, ExpectXML: ``, MarshalOnly: true},
@ -1133,6 +1269,382 @@ var marshalTests = []struct {
ExpectXML: `<NestedAndCData><A><B></B><B></B></A><![CDATA[test]]></NestedAndCData>`, ExpectXML: `<NestedAndCData><A><B></B><B></B></A><![CDATA[test]]></NestedAndCData>`,
Value: &NestedAndCData{AB: make([]string, 2), CDATA: "test"}, Value: &NestedAndCData{AB: make([]string, 2), CDATA: "test"},
}, },
// Test pointer indirection in various kinds of fields.
// https://golang.org/issue/19063
{
ExpectXML: `<IndirComment><T1></T1><!--hi--><T2></T2></IndirComment>`,
Value: &IndirComment{Comment: stringptr("hi")},
MarshalOnly: true,
},
{
ExpectXML: `<IndirComment><T1></T1><T2></T2></IndirComment>`,
Value: &IndirComment{Comment: stringptr("")},
MarshalOnly: true,
},
{
ExpectXML: `<IndirComment><T1></T1><T2></T2></IndirComment>`,
Value: &IndirComment{Comment: nil},
MarshalError: "xml: bad type for comment field of xml.IndirComment",
},
{
ExpectXML: `<IndirComment><T1></T1><!--hi--><T2></T2></IndirComment>`,
Value: &IndirComment{Comment: nil},
UnmarshalOnly: true,
},
{
ExpectXML: `<IfaceComment><T1></T1><!--hi--><T2></T2></IfaceComment>`,
Value: &IfaceComment{Comment: "hi"},
MarshalOnly: true,
},
{
ExpectXML: `<IfaceComment><T1></T1><!--hi--><T2></T2></IfaceComment>`,
Value: &IfaceComment{Comment: nil},
UnmarshalOnly: true,
},
{
ExpectXML: `<IfaceComment><T1></T1><T2></T2></IfaceComment>`,
Value: &IfaceComment{Comment: nil},
MarshalError: "xml: bad type for comment field of xml.IfaceComment",
},
{
ExpectXML: `<IfaceComment><T1></T1><T2></T2></IfaceComment>`,
Value: &IfaceComment{Comment: nil},
UnmarshalOnly: true,
},
{
ExpectXML: `<DirectComment><T1></T1><!--hi--><T2></T2></DirectComment>`,
Value: &DirectComment{Comment: string("hi")},
},
{
ExpectXML: `<DirectComment><T1></T1><T2></T2></DirectComment>`,
Value: &DirectComment{Comment: string("")},
},
{
ExpectXML: `<IndirChardata><T1></T1>hi<T2></T2></IndirChardata>`,
Value: &IndirChardata{Chardata: stringptr("hi")},
},
{
ExpectXML: `<IndirChardata><T1></T1><![CDATA[hi]]><T2></T2></IndirChardata>`,
Value: &IndirChardata{Chardata: stringptr("hi")},
UnmarshalOnly: true, // marshals without CDATA
},
{
ExpectXML: `<IndirChardata><T1></T1><T2></T2></IndirChardata>`,
Value: &IndirChardata{Chardata: stringptr("")},
},
{
ExpectXML: `<IndirChardata><T1></T1><T2></T2></IndirChardata>`,
Value: &IndirChardata{Chardata: nil},
MarshalOnly: true, // unmarshal leaves Chardata=stringptr("")
},
{
ExpectXML: `<IfaceChardata><T1></T1>hi<T2></T2></IfaceChardata>`,
Value: &IfaceChardata{Chardata: string("hi")},
UnmarshalError: "cannot unmarshal into interface {}",
},
{
ExpectXML: `<IfaceChardata><T1></T1><![CDATA[hi]]><T2></T2></IfaceChardata>`,
Value: &IfaceChardata{Chardata: string("hi")},
UnmarshalOnly: true, // marshals without CDATA
UnmarshalError: "cannot unmarshal into interface {}",
},
{
ExpectXML: `<IfaceChardata><T1></T1><T2></T2></IfaceChardata>`,
Value: &IfaceChardata{Chardata: string("")},
UnmarshalError: "cannot unmarshal into interface {}",
},
{
ExpectXML: `<IfaceChardata><T1></T1><T2></T2></IfaceChardata>`,
Value: &IfaceChardata{Chardata: nil},
UnmarshalError: "cannot unmarshal into interface {}",
},
{
ExpectXML: `<DirectChardata><T1></T1>hi<T2></T2></DirectChardata>`,
Value: &DirectChardata{Chardata: string("hi")},
},
{
ExpectXML: `<DirectChardata><T1></T1><![CDATA[hi]]><T2></T2></DirectChardata>`,
Value: &DirectChardata{Chardata: string("hi")},
UnmarshalOnly: true, // marshals without CDATA
},
{
ExpectXML: `<DirectChardata><T1></T1><T2></T2></DirectChardata>`,
Value: &DirectChardata{Chardata: string("")},
},
{
ExpectXML: `<IndirCDATA><T1></T1><![CDATA[hi]]><T2></T2></IndirCDATA>`,
Value: &IndirCDATA{CDATA: stringptr("hi")},
},
{
ExpectXML: `<IndirCDATA><T1></T1>hi<T2></T2></IndirCDATA>`,
Value: &IndirCDATA{CDATA: stringptr("hi")},
UnmarshalOnly: true, // marshals with CDATA
},
{
ExpectXML: `<IndirCDATA><T1></T1><T2></T2></IndirCDATA>`,
Value: &IndirCDATA{CDATA: stringptr("")},
},
{
ExpectXML: `<IndirCDATA><T1></T1><T2></T2></IndirCDATA>`,
Value: &IndirCDATA{CDATA: nil},
MarshalOnly: true, // unmarshal leaves CDATA=stringptr("")
},
{
ExpectXML: `<IfaceCDATA><T1></T1><![CDATA[hi]]><T2></T2></IfaceCDATA>`,
Value: &IfaceCDATA{CDATA: string("hi")},
UnmarshalError: "cannot unmarshal into interface {}",
},
{
ExpectXML: `<IfaceCDATA><T1></T1>hi<T2></T2></IfaceCDATA>`,
Value: &IfaceCDATA{CDATA: string("hi")},
UnmarshalOnly: true, // marshals with CDATA
UnmarshalError: "cannot unmarshal into interface {}",
},
{
ExpectXML: `<IfaceCDATA><T1></T1><T2></T2></IfaceCDATA>`,
Value: &IfaceCDATA{CDATA: string("")},
UnmarshalError: "cannot unmarshal into interface {}",
},
{
ExpectXML: `<IfaceCDATA><T1></T1><T2></T2></IfaceCDATA>`,
Value: &IfaceCDATA{CDATA: nil},
UnmarshalError: "cannot unmarshal into interface {}",
},
{
ExpectXML: `<DirectCDATA><T1></T1><![CDATA[hi]]><T2></T2></DirectCDATA>`,
Value: &DirectCDATA{CDATA: string("hi")},
},
{
ExpectXML: `<DirectCDATA><T1></T1>hi<T2></T2></DirectCDATA>`,
Value: &DirectCDATA{CDATA: string("hi")},
UnmarshalOnly: true, // marshals with CDATA
},
{
ExpectXML: `<DirectCDATA><T1></T1><T2></T2></DirectCDATA>`,
Value: &DirectCDATA{CDATA: string("")},
},
{
ExpectXML: `<IndirInnerXML><T1></T1><hi/><T2></T2></IndirInnerXML>`,
Value: &IndirInnerXML{InnerXML: stringptr("<hi/>")},
MarshalOnly: true,
},
{
ExpectXML: `<IndirInnerXML><T1></T1><T2></T2></IndirInnerXML>`,
Value: &IndirInnerXML{InnerXML: stringptr("")},
MarshalOnly: true,
},
{
ExpectXML: `<IndirInnerXML><T1></T1><T2></T2></IndirInnerXML>`,
Value: &IndirInnerXML{InnerXML: nil},
},
{
ExpectXML: `<IndirInnerXML><T1></T1><hi/><T2></T2></IndirInnerXML>`,
Value: &IndirInnerXML{InnerXML: nil},
UnmarshalOnly: true,
},
{
ExpectXML: `<IfaceInnerXML><T1></T1><hi/><T2></T2></IfaceInnerXML>`,
Value: &IfaceInnerXML{InnerXML: "<hi/>"},
MarshalOnly: true,
},
{
ExpectXML: `<IfaceInnerXML><T1></T1><hi/><T2></T2></IfaceInnerXML>`,
Value: &IfaceInnerXML{InnerXML: nil},
UnmarshalOnly: true,
},
{
ExpectXML: `<IfaceInnerXML><T1></T1><T2></T2></IfaceInnerXML>`,
Value: &IfaceInnerXML{InnerXML: nil},
},
{
ExpectXML: `<IfaceInnerXML><T1></T1><T2></T2></IfaceInnerXML>`,
Value: &IfaceInnerXML{InnerXML: nil},
UnmarshalOnly: true,
},
{
ExpectXML: `<DirectInnerXML><T1></T1><hi/><T2></T2></DirectInnerXML>`,
Value: &DirectInnerXML{InnerXML: string("<hi/>")},
MarshalOnly: true,
},
{
ExpectXML: `<DirectInnerXML><T1></T1><hi/><T2></T2></DirectInnerXML>`,
Value: &DirectInnerXML{InnerXML: string("<T1></T1><hi/><T2></T2>")},
UnmarshalOnly: true,
},
{
ExpectXML: `<DirectInnerXML><T1></T1><T2></T2></DirectInnerXML>`,
Value: &DirectInnerXML{InnerXML: string("")},
MarshalOnly: true,
},
{
ExpectXML: `<DirectInnerXML><T1></T1><T2></T2></DirectInnerXML>`,
Value: &DirectInnerXML{InnerXML: string("<T1></T1><T2></T2>")},
UnmarshalOnly: true,
},
{
ExpectXML: `<IndirElement><T1></T1><Element>hi</Element><T2></T2></IndirElement>`,
Value: &IndirElement{Element: stringptr("hi")},
},
{
ExpectXML: `<IndirElement><T1></T1><Element></Element><T2></T2></IndirElement>`,
Value: &IndirElement{Element: stringptr("")},
},
{
ExpectXML: `<IndirElement><T1></T1><T2></T2></IndirElement>`,
Value: &IndirElement{Element: nil},
},
{
ExpectXML: `<IfaceElement><T1></T1><Element>hi</Element><T2></T2></IfaceElement>`,
Value: &IfaceElement{Element: "hi"},
MarshalOnly: true,
},
{
ExpectXML: `<IfaceElement><T1></T1><Element>hi</Element><T2></T2></IfaceElement>`,
Value: &IfaceElement{Element: nil},
UnmarshalOnly: true,
},
{
ExpectXML: `<IfaceElement><T1></T1><T2></T2></IfaceElement>`,
Value: &IfaceElement{Element: nil},
},
{
ExpectXML: `<IfaceElement><T1></T1><T2></T2></IfaceElement>`,
Value: &IfaceElement{Element: nil},
UnmarshalOnly: true,
},
{
ExpectXML: `<DirectElement><T1></T1><Element>hi</Element><T2></T2></DirectElement>`,
Value: &DirectElement{Element: string("hi")},
},
{
ExpectXML: `<DirectElement><T1></T1><Element></Element><T2></T2></DirectElement>`,
Value: &DirectElement{Element: string("")},
},
{
ExpectXML: `<IndirOmitEmpty><T1></T1><OmitEmpty>hi</OmitEmpty><T2></T2></IndirOmitEmpty>`,
Value: &IndirOmitEmpty{OmitEmpty: stringptr("hi")},
},
{
// Note: Changed in Go 1.8 to include <OmitEmpty> element (because x.OmitEmpty != nil).
ExpectXML: `<IndirOmitEmpty><T1></T1><OmitEmpty></OmitEmpty><T2></T2></IndirOmitEmpty>`,
Value: &IndirOmitEmpty{OmitEmpty: stringptr("")},
MarshalOnly: true,
},
{
ExpectXML: `<IndirOmitEmpty><T1></T1><OmitEmpty></OmitEmpty><T2></T2></IndirOmitEmpty>`,
Value: &IndirOmitEmpty{OmitEmpty: stringptr("")},
UnmarshalOnly: true,
},
{
ExpectXML: `<IndirOmitEmpty><T1></T1><T2></T2></IndirOmitEmpty>`,
Value: &IndirOmitEmpty{OmitEmpty: nil},
},
{
ExpectXML: `<IfaceOmitEmpty><T1></T1><OmitEmpty>hi</OmitEmpty><T2></T2></IfaceOmitEmpty>`,
Value: &IfaceOmitEmpty{OmitEmpty: "hi"},
MarshalOnly: true,
},
{
ExpectXML: `<IfaceOmitEmpty><T1></T1><OmitEmpty>hi</OmitEmpty><T2></T2></IfaceOmitEmpty>`,
Value: &IfaceOmitEmpty{OmitEmpty: nil},
UnmarshalOnly: true,
},
{
ExpectXML: `<IfaceOmitEmpty><T1></T1><T2></T2></IfaceOmitEmpty>`,
Value: &IfaceOmitEmpty{OmitEmpty: nil},
},
{
ExpectXML: `<IfaceOmitEmpty><T1></T1><T2></T2></IfaceOmitEmpty>`,
Value: &IfaceOmitEmpty{OmitEmpty: nil},
UnmarshalOnly: true,
},
{
ExpectXML: `<DirectOmitEmpty><T1></T1><OmitEmpty>hi</OmitEmpty><T2></T2></DirectOmitEmpty>`,
Value: &DirectOmitEmpty{OmitEmpty: string("hi")},
},
{
ExpectXML: `<DirectOmitEmpty><T1></T1><T2></T2></DirectOmitEmpty>`,
Value: &DirectOmitEmpty{OmitEmpty: string("")},
},
{
ExpectXML: `<IndirAny><T1></T1><Any>hi</Any><T2></T2></IndirAny>`,
Value: &IndirAny{Any: stringptr("hi")},
},
{
ExpectXML: `<IndirAny><T1></T1><Any></Any><T2></T2></IndirAny>`,
Value: &IndirAny{Any: stringptr("")},
},
{
ExpectXML: `<IndirAny><T1></T1><T2></T2></IndirAny>`,
Value: &IndirAny{Any: nil},
},
{
ExpectXML: `<IfaceAny><T1></T1><Any>hi</Any><T2></T2></IfaceAny>`,
Value: &IfaceAny{Any: "hi"},
MarshalOnly: true,
},
{
ExpectXML: `<IfaceAny><T1></T1><Any>hi</Any><T2></T2></IfaceAny>`,
Value: &IfaceAny{Any: nil},
UnmarshalOnly: true,
},
{
ExpectXML: `<IfaceAny><T1></T1><T2></T2></IfaceAny>`,
Value: &IfaceAny{Any: nil},
},
{
ExpectXML: `<IfaceAny><T1></T1><T2></T2></IfaceAny>`,
Value: &IfaceAny{Any: nil},
UnmarshalOnly: true,
},
{
ExpectXML: `<DirectAny><T1></T1><Any>hi</Any><T2></T2></DirectAny>`,
Value: &DirectAny{Any: string("hi")},
},
{
ExpectXML: `<DirectAny><T1></T1><Any></Any><T2></T2></DirectAny>`,
Value: &DirectAny{Any: string("")},
},
{
ExpectXML: `<IndirFoo><T1></T1><Foo>hi</Foo><T2></T2></IndirFoo>`,
Value: &IndirAny{Any: stringptr("hi")},
UnmarshalOnly: true,
},
{
ExpectXML: `<IndirFoo><T1></T1><Foo></Foo><T2></T2></IndirFoo>`,
Value: &IndirAny{Any: stringptr("")},
UnmarshalOnly: true,
},
{
ExpectXML: `<IndirFoo><T1></T1><T2></T2></IndirFoo>`,
Value: &IndirAny{Any: nil},
UnmarshalOnly: true,
},
{
ExpectXML: `<IfaceFoo><T1></T1><Foo>hi</Foo><T2></T2></IfaceFoo>`,
Value: &IfaceAny{Any: nil},
UnmarshalOnly: true,
},
{
ExpectXML: `<IfaceFoo><T1></T1><T2></T2></IfaceFoo>`,
Value: &IfaceAny{Any: nil},
UnmarshalOnly: true,
},
{
ExpectXML: `<IfaceFoo><T1></T1><T2></T2></IfaceFoo>`,
Value: &IfaceAny{Any: nil},
UnmarshalOnly: true,
},
{
ExpectXML: `<DirectFoo><T1></T1><Foo>hi</Foo><T2></T2></DirectFoo>`,
Value: &DirectAny{Any: string("hi")},
UnmarshalOnly: true,
},
{
ExpectXML: `<DirectFoo><T1></T1><Foo></Foo><T2></T2></DirectFoo>`,
Value: &DirectAny{Any: string("")},
UnmarshalOnly: true,
},
} }
func TestMarshal(t *testing.T) { func TestMarshal(t *testing.T) {
@ -1142,7 +1654,17 @@ func TestMarshal(t *testing.T) {
} }
data, err := Marshal(test.Value) data, err := Marshal(test.Value)
if err != nil { if err != nil {
t.Errorf("#%d: marshal(%#v): %s", idx, test.Value, err) if test.MarshalError == "" {
t.Errorf("#%d: marshal(%#v): %s", idx, test.Value, err)
continue
}
if !strings.Contains(err.Error(), test.MarshalError) {
t.Errorf("#%d: marshal(%#v): %s, want %q", idx, test.Value, err, test.MarshalError)
}
continue
}
if test.MarshalError != "" {
t.Errorf("#%d: Marshal succeeded, want error %q", idx, test.MarshalError)
continue continue
} }
if got, want := string(data), test.ExpectXML; got != want { if got, want := string(data), test.ExpectXML; got != want {
@ -1268,8 +1790,16 @@ func TestUnmarshal(t *testing.T) {
} }
if err != nil { if err != nil {
t.Errorf("#%d: unexpected error: %#v", i, err) if test.UnmarshalError == "" {
} else if got, want := dest, test.Value; !reflect.DeepEqual(got, want) { t.Errorf("#%d: unmarshal(%#v): %s", i, test.ExpectXML, err)
continue
}
if !strings.Contains(err.Error(), test.UnmarshalError) {
t.Errorf("#%d: unmarshal(%#v): %s, want %q", i, test.ExpectXML, err, test.UnmarshalError)
}
continue
}
if got, want := dest, test.Value; !reflect.DeepEqual(got, want) {
t.Errorf("#%d: unmarshal(%q):\nhave %#v\nwant %#v", i, test.ExpectXML, got, want) t.Errorf("#%d: unmarshal(%q):\nhave %#v\nwant %#v", i, test.ExpectXML, got, want)
} }
} }