1// Copyright 2011 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package xml
6
7import (
8	"bytes"
9	"errors"
10	"fmt"
11	"io"
12	"reflect"
13	"strconv"
14	"strings"
15	"sync"
16	"testing"
17	"time"
18)
19
20type DriveType int
21
22const (
23	HyperDrive DriveType = iota
24	ImprobabilityDrive
25)
26
27type Passenger struct {
28	Name   []string `xml:"name"`
29	Weight float32  `xml:"weight"`
30}
31
32type Ship struct {
33	XMLName struct{} `xml:"spaceship"`
34
35	Name      string       `xml:"name,attr"`
36	Pilot     string       `xml:"pilot,attr"`
37	Drive     DriveType    `xml:"drive"`
38	Age       uint         `xml:"age"`
39	Passenger []*Passenger `xml:"passenger"`
40	secret    string
41}
42
43type NamedType string
44
45type Port struct {
46	XMLName struct{} `xml:"port"`
47	Type    string   `xml:"type,attr,omitempty"`
48	Comment string   `xml:",comment"`
49	Number  string   `xml:",chardata"`
50}
51
52type Domain struct {
53	XMLName struct{} `xml:"domain"`
54	Country string   `xml:",attr,omitempty"`
55	Name    []byte   `xml:",chardata"`
56	Comment []byte   `xml:",comment"`
57}
58
59type Book struct {
60	XMLName struct{} `xml:"book"`
61	Title   string   `xml:",chardata"`
62}
63
64type Event struct {
65	XMLName struct{} `xml:"event"`
66	Year    int      `xml:",chardata"`
67}
68
69type Movie struct {
70	XMLName struct{} `xml:"movie"`
71	Length  uint     `xml:",chardata"`
72}
73
74type Pi struct {
75	XMLName       struct{} `xml:"pi"`
76	Approximation float32  `xml:",chardata"`
77}
78
79type Universe struct {
80	XMLName struct{} `xml:"universe"`
81	Visible float64  `xml:",chardata"`
82}
83
84type Particle struct {
85	XMLName struct{} `xml:"particle"`
86	HasMass bool     `xml:",chardata"`
87}
88
89type Departure struct {
90	XMLName struct{}  `xml:"departure"`
91	When    time.Time `xml:",chardata"`
92}
93
94type SecretAgent struct {
95	XMLName   struct{} `xml:"agent"`
96	Handle    string   `xml:"handle,attr"`
97	Identity  string
98	Obfuscate string `xml:",innerxml"`
99}
100
101type NestedItems struct {
102	XMLName struct{} `xml:"result"`
103	Items   []string `xml:">item"`
104	Item1   []string `xml:"Items>item1"`
105}
106
107type NestedOrder struct {
108	XMLName struct{} `xml:"result"`
109	Field1  string   `xml:"parent>c"`
110	Field2  string   `xml:"parent>b"`
111	Field3  string   `xml:"parent>a"`
112}
113
114type MixedNested struct {
115	XMLName struct{} `xml:"result"`
116	A       string   `xml:"parent1>a"`
117	B       string   `xml:"b"`
118	C       string   `xml:"parent1>parent2>c"`
119	D       string   `xml:"parent1>d"`
120}
121
122type NilTest struct {
123	A interface{} `xml:"parent1>parent2>a"`
124	B interface{} `xml:"parent1>b"`
125	C interface{} `xml:"parent1>parent2>c"`
126}
127
128type Service struct {
129	XMLName struct{} `xml:"service"`
130	Domain  *Domain  `xml:"host>domain"`
131	Port    *Port    `xml:"host>port"`
132	Extra1  interface{}
133	Extra2  interface{} `xml:"host>extra2"`
134}
135
136var nilStruct *Ship
137
138type EmbedA struct {
139	EmbedC
140	EmbedB EmbedB
141	FieldA string
142}
143
144type EmbedB struct {
145	FieldB string
146	*EmbedC
147}
148
149type EmbedC struct {
150	FieldA1 string `xml:"FieldA>A1"`
151	FieldA2 string `xml:"FieldA>A2"`
152	FieldB  string
153	FieldC  string
154}
155
156type NameCasing struct {
157	XMLName struct{} `xml:"casing"`
158	Xy      string
159	XY      string
160	XyA     string `xml:"Xy,attr"`
161	XYA     string `xml:"XY,attr"`
162}
163
164type NamePrecedence struct {
165	XMLName     Name              `xml:"Parent"`
166	FromTag     XMLNameWithoutTag `xml:"InTag"`
167	FromNameVal XMLNameWithoutTag
168	FromNameTag XMLNameWithTag
169	InFieldName string
170}
171
172type XMLNameWithTag struct {
173	XMLName Name   `xml:"InXMLNameTag"`
174	Value   string `xml:",chardata"`
175}
176
177type XMLNameWithNSTag struct {
178	XMLName Name   `xml:"ns InXMLNameWithNSTag"`
179	Value   string `xml:",chardata"`
180}
181
182type XMLNameWithoutTag struct {
183	XMLName Name
184	Value   string `xml:",chardata"`
185}
186
187type NameInField struct {
188	Foo Name `xml:"ns foo"`
189}
190
191type AttrTest struct {
192	Int   int     `xml:",attr"`
193	Named int     `xml:"int,attr"`
194	Float float64 `xml:",attr"`
195	Uint8 uint8   `xml:",attr"`
196	Bool  bool    `xml:",attr"`
197	Str   string  `xml:",attr"`
198	Bytes []byte  `xml:",attr"`
199}
200
201type OmitAttrTest struct {
202	Int   int     `xml:",attr,omitempty"`
203	Named int     `xml:"int,attr,omitempty"`
204	Float float64 `xml:",attr,omitempty"`
205	Uint8 uint8   `xml:",attr,omitempty"`
206	Bool  bool    `xml:",attr,omitempty"`
207	Str   string  `xml:",attr,omitempty"`
208	Bytes []byte  `xml:",attr,omitempty"`
209}
210
211type OmitFieldTest struct {
212	Int   int           `xml:",omitempty"`
213	Named int           `xml:"int,omitempty"`
214	Float float64       `xml:",omitempty"`
215	Uint8 uint8         `xml:",omitempty"`
216	Bool  bool          `xml:",omitempty"`
217	Str   string        `xml:",omitempty"`
218	Bytes []byte        `xml:",omitempty"`
219	Ptr   *PresenceTest `xml:",omitempty"`
220}
221
222type AnyTest struct {
223	XMLName  struct{}  `xml:"a"`
224	Nested   string    `xml:"nested>value"`
225	AnyField AnyHolder `xml:",any"`
226}
227
228type AnyOmitTest struct {
229	XMLName  struct{}   `xml:"a"`
230	Nested   string     `xml:"nested>value"`
231	AnyField *AnyHolder `xml:",any,omitempty"`
232}
233
234type AnySliceTest struct {
235	XMLName  struct{}    `xml:"a"`
236	Nested   string      `xml:"nested>value"`
237	AnyField []AnyHolder `xml:",any"`
238}
239
240type AnyHolder struct {
241	XMLName Name
242	XML     string `xml:",innerxml"`
243}
244
245type RecurseA struct {
246	A string
247	B *RecurseB
248}
249
250type RecurseB struct {
251	A *RecurseA
252	B string
253}
254
255type PresenceTest struct {
256	Exists *struct{}
257}
258
259type IgnoreTest struct {
260	PublicSecret string `xml:"-"`
261}
262
263type MyBytes []byte
264
265type Data struct {
266	Bytes  []byte
267	Attr   []byte `xml:",attr"`
268	Custom MyBytes
269}
270
271type Plain struct {
272	V interface{}
273}
274
275type MyInt int
276
277type EmbedInt struct {
278	MyInt
279}
280
281type Strings struct {
282	X []string `xml:"A>B,omitempty"`
283}
284
285type PointerFieldsTest struct {
286	XMLName  Name    `xml:"dummy"`
287	Name     *string `xml:"name,attr"`
288	Age      *uint   `xml:"age,attr"`
289	Empty    *string `xml:"empty,attr"`
290	Contents *string `xml:",chardata"`
291}
292
293type ChardataEmptyTest struct {
294	XMLName  Name    `xml:"test"`
295	Contents *string `xml:",chardata"`
296}
297
298type MyMarshalerTest struct {
299}
300
301var _ Marshaler = (*MyMarshalerTest)(nil)
302
303func (m *MyMarshalerTest) MarshalXML(e *Encoder, start StartElement) error {
304	e.EncodeToken(start)
305	e.EncodeToken(CharData([]byte("hello world")))
306	e.EncodeToken(EndElement{start.Name})
307	return nil
308}
309
310type MyMarshalerAttrTest struct{}
311
312var _ MarshalerAttr = (*MyMarshalerAttrTest)(nil)
313
314func (m *MyMarshalerAttrTest) MarshalXMLAttr(name Name) (Attr, error) {
315	return Attr{name, "hello world"}, nil
316}
317
318type MyMarshalerValueAttrTest struct{}
319
320var _ MarshalerAttr = MyMarshalerValueAttrTest{}
321
322func (m MyMarshalerValueAttrTest) MarshalXMLAttr(name Name) (Attr, error) {
323	return Attr{name, "hello world"}, nil
324}
325
326type MarshalerStruct struct {
327	Foo MyMarshalerAttrTest `xml:",attr"`
328}
329
330type MarshalerValueStruct struct {
331	Foo MyMarshalerValueAttrTest `xml:",attr"`
332}
333
334type InnerStruct struct {
335	XMLName Name `xml:"testns outer"`
336}
337
338type OuterStruct struct {
339	InnerStruct
340	IntAttr int `xml:"int,attr"`
341}
342
343type OuterNamedStruct struct {
344	InnerStruct
345	XMLName Name `xml:"outerns test"`
346	IntAttr int  `xml:"int,attr"`
347}
348
349type OuterNamedOrderedStruct struct {
350	XMLName Name `xml:"outerns test"`
351	InnerStruct
352	IntAttr int `xml:"int,attr"`
353}
354
355type OuterOuterStruct struct {
356	OuterStruct
357}
358
359type NestedAndChardata struct {
360	AB       []string `xml:"A>B"`
361	Chardata string   `xml:",chardata"`
362}
363
364type NestedAndComment struct {
365	AB      []string `xml:"A>B"`
366	Comment string   `xml:",comment"`
367}
368
369type XMLNSFieldStruct struct {
370	Ns   string `xml:"xmlns,attr"`
371	Body string
372}
373
374type NamedXMLNSFieldStruct struct {
375	XMLName struct{} `xml:"testns test"`
376	Ns      string   `xml:"xmlns,attr"`
377	Body    string
378}
379
380type XMLNSFieldStructWithOmitEmpty struct {
381	Ns   string `xml:"xmlns,attr,omitempty"`
382	Body string
383}
384
385type NamedXMLNSFieldStructWithEmptyNamespace struct {
386	XMLName struct{} `xml:"test"`
387	Ns      string   `xml:"xmlns,attr"`
388	Body    string
389}
390
391type RecursiveXMLNSFieldStruct struct {
392	Ns   string                     `xml:"xmlns,attr"`
393	Body *RecursiveXMLNSFieldStruct `xml:",omitempty"`
394	Text string                     `xml:",omitempty"`
395}
396
397func ifaceptr(x interface{}) interface{} {
398	return &x
399}
400
401var (
402	nameAttr     = "Sarah"
403	ageAttr      = uint(12)
404	contentsAttr = "lorem ipsum"
405)
406
407// Unless explicitly stated as such (or *Plain), all of the
408// tests below are two-way tests. When introducing new tests,
409// please try to make them two-way as well to ensure that
410// marshalling and unmarshalling are as symmetrical as feasible.
411var marshalTests = []struct {
412	Value         interface{}
413	ExpectXML     string
414	MarshalOnly   bool
415	UnmarshalOnly bool
416}{
417	// Test nil marshals to nothing
418	{Value: nil, ExpectXML: ``, MarshalOnly: true},
419	{Value: nilStruct, ExpectXML: ``, MarshalOnly: true},
420
421	// Test value types
422	{Value: &Plain{true}, ExpectXML: `<Plain><V>true</V></Plain>`},
423	{Value: &Plain{false}, ExpectXML: `<Plain><V>false</V></Plain>`},
424	{Value: &Plain{int(42)}, ExpectXML: `<Plain><V>42</V></Plain>`},
425	{Value: &Plain{int8(42)}, ExpectXML: `<Plain><V>42</V></Plain>`},
426	{Value: &Plain{int16(42)}, ExpectXML: `<Plain><V>42</V></Plain>`},
427	{Value: &Plain{int32(42)}, ExpectXML: `<Plain><V>42</V></Plain>`},
428	{Value: &Plain{uint(42)}, ExpectXML: `<Plain><V>42</V></Plain>`},
429	{Value: &Plain{uint8(42)}, ExpectXML: `<Plain><V>42</V></Plain>`},
430	{Value: &Plain{uint16(42)}, ExpectXML: `<Plain><V>42</V></Plain>`},
431	{Value: &Plain{uint32(42)}, ExpectXML: `<Plain><V>42</V></Plain>`},
432	{Value: &Plain{float32(1.25)}, ExpectXML: `<Plain><V>1.25</V></Plain>`},
433	{Value: &Plain{float64(1.25)}, ExpectXML: `<Plain><V>1.25</V></Plain>`},
434	{Value: &Plain{uintptr(0xFFDD)}, ExpectXML: `<Plain><V>65501</V></Plain>`},
435	{Value: &Plain{"gopher"}, ExpectXML: `<Plain><V>gopher</V></Plain>`},
436	{Value: &Plain{[]byte("gopher")}, ExpectXML: `<Plain><V>gopher</V></Plain>`},
437	{Value: &Plain{"</>"}, ExpectXML: `<Plain><V>&lt;/&gt;</V></Plain>`},
438	{Value: &Plain{[]byte("</>")}, ExpectXML: `<Plain><V>&lt;/&gt;</V></Plain>`},
439	{Value: &Plain{[3]byte{'<', '/', '>'}}, ExpectXML: `<Plain><V>&lt;/&gt;</V></Plain>`},
440	{Value: &Plain{NamedType("potato")}, ExpectXML: `<Plain><V>potato</V></Plain>`},
441	{Value: &Plain{[]int{1, 2, 3}}, ExpectXML: `<Plain><V>1</V><V>2</V><V>3</V></Plain>`},
442	{Value: &Plain{[3]int{1, 2, 3}}, ExpectXML: `<Plain><V>1</V><V>2</V><V>3</V></Plain>`},
443	{Value: ifaceptr(true), MarshalOnly: true, ExpectXML: `<bool>true</bool>`},
444
445	// Test time.
446	{
447		Value:     &Plain{time.Unix(1e9, 123456789).UTC()},
448		ExpectXML: `<Plain><V>2001-09-09T01:46:40.123456789Z</V></Plain>`,
449	},
450
451	// A pointer to struct{} may be used to test for an element's presence.
452	{
453		Value:     &PresenceTest{new(struct{})},
454		ExpectXML: `<PresenceTest><Exists></Exists></PresenceTest>`,
455	},
456	{
457		Value:     &PresenceTest{},
458		ExpectXML: `<PresenceTest></PresenceTest>`,
459	},
460
461	// A pointer to struct{} may be used to test for an element's presence.
462	{
463		Value:     &PresenceTest{new(struct{})},
464		ExpectXML: `<PresenceTest><Exists></Exists></PresenceTest>`,
465	},
466	{
467		Value:     &PresenceTest{},
468		ExpectXML: `<PresenceTest></PresenceTest>`,
469	},
470
471	// A []byte field is only nil if the element was not found.
472	{
473		Value:         &Data{},
474		ExpectXML:     `<Data></Data>`,
475		UnmarshalOnly: true,
476	},
477	{
478		Value:         &Data{Bytes: []byte{}, Custom: MyBytes{}, Attr: []byte{}},
479		ExpectXML:     `<Data Attr=""><Bytes></Bytes><Custom></Custom></Data>`,
480		UnmarshalOnly: true,
481	},
482
483	// Check that []byte works, including named []byte types.
484	{
485		Value:     &Data{Bytes: []byte("ab"), Custom: MyBytes("cd"), Attr: []byte{'v'}},
486		ExpectXML: `<Data Attr="v"><Bytes>ab</Bytes><Custom>cd</Custom></Data>`,
487	},
488
489	// Test innerxml
490	{
491		Value: &SecretAgent{
492			Handle:    "007",
493			Identity:  "James Bond",
494			Obfuscate: "<redacted/>",
495		},
496		ExpectXML:   `<agent handle="007"><Identity>James Bond</Identity><redacted/></agent>`,
497		MarshalOnly: true,
498	},
499	{
500		Value: &SecretAgent{
501			Handle:    "007",
502			Identity:  "James Bond",
503			Obfuscate: "<Identity>James Bond</Identity><redacted/>",
504		},
505		ExpectXML:     `<agent handle="007"><Identity>James Bond</Identity><redacted/></agent>`,
506		UnmarshalOnly: true,
507	},
508
509	// Test structs
510	{Value: &Port{Type: "ssl", Number: "443"}, ExpectXML: `<port type="ssl">443</port>`},
511	{Value: &Port{Number: "443"}, ExpectXML: `<port>443</port>`},
512	{Value: &Port{Type: "<unix>"}, ExpectXML: `<port type="&lt;unix&gt;"></port>`},
513	{Value: &Port{Number: "443", Comment: "https"}, ExpectXML: `<port><!--https-->443</port>`},
514	{Value: &Port{Number: "443", Comment: "add space-"}, ExpectXML: `<port><!--add space- -->443</port>`, MarshalOnly: true},
515	{Value: &Domain{Name: []byte("google.com&friends")}, ExpectXML: `<domain>google.com&amp;friends</domain>`},
516	{Value: &Domain{Name: []byte("google.com"), Comment: []byte(" &friends ")}, ExpectXML: `<domain>google.com<!-- &friends --></domain>`},
517	{Value: &Book{Title: "Pride & Prejudice"}, ExpectXML: `<book>Pride &amp; Prejudice</book>`},
518	{Value: &Event{Year: -3114}, ExpectXML: `<event>-3114</event>`},
519	{Value: &Movie{Length: 13440}, ExpectXML: `<movie>13440</movie>`},
520	{Value: &Pi{Approximation: 3.14159265}, ExpectXML: `<pi>3.1415927</pi>`},
521	{Value: &Universe{Visible: 9.3e13}, ExpectXML: `<universe>9.3e+13</universe>`},
522	{Value: &Particle{HasMass: true}, ExpectXML: `<particle>true</particle>`},
523	{Value: &Departure{When: ParseTime("2013-01-09T00:15:00-09:00")}, ExpectXML: `<departure>2013-01-09T00:15:00-09:00</departure>`},
524	{Value: atomValue, ExpectXML: atomXml},
525	{
526		Value: &Ship{
527			Name:  "Heart of Gold",
528			Pilot: "Computer",
529			Age:   1,
530			Drive: ImprobabilityDrive,
531			Passenger: []*Passenger{
532				{
533					Name:   []string{"Zaphod", "Beeblebrox"},
534					Weight: 7.25,
535				},
536				{
537					Name:   []string{"Trisha", "McMillen"},
538					Weight: 5.5,
539				},
540				{
541					Name:   []string{"Ford", "Prefect"},
542					Weight: 7,
543				},
544				{
545					Name:   []string{"Arthur", "Dent"},
546					Weight: 6.75,
547				},
548			},
549		},
550		ExpectXML: `<spaceship name="Heart of Gold" pilot="Computer">` +
551			`<drive>` + strconv.Itoa(int(ImprobabilityDrive)) + `</drive>` +
552			`<age>1</age>` +
553			`<passenger>` +
554			`<name>Zaphod</name>` +
555			`<name>Beeblebrox</name>` +
556			`<weight>7.25</weight>` +
557			`</passenger>` +
558			`<passenger>` +
559			`<name>Trisha</name>` +
560			`<name>McMillen</name>` +
561			`<weight>5.5</weight>` +
562			`</passenger>` +
563			`<passenger>` +
564			`<name>Ford</name>` +
565			`<name>Prefect</name>` +
566			`<weight>7</weight>` +
567			`</passenger>` +
568			`<passenger>` +
569			`<name>Arthur</name>` +
570			`<name>Dent</name>` +
571			`<weight>6.75</weight>` +
572			`</passenger>` +
573			`</spaceship>`,
574	},
575
576	// Test a>b
577	{
578		Value: &NestedItems{Items: nil, Item1: nil},
579		ExpectXML: `<result>` +
580			`<Items>` +
581			`</Items>` +
582			`</result>`,
583	},
584	{
585		Value: &NestedItems{Items: []string{}, Item1: []string{}},
586		ExpectXML: `<result>` +
587			`<Items>` +
588			`</Items>` +
589			`</result>`,
590		MarshalOnly: true,
591	},
592	{
593		Value: &NestedItems{Items: nil, Item1: []string{"A"}},
594		ExpectXML: `<result>` +
595			`<Items>` +
596			`<item1>A</item1>` +
597			`</Items>` +
598			`</result>`,
599	},
600	{
601		Value: &NestedItems{Items: []string{"A", "B"}, Item1: nil},
602		ExpectXML: `<result>` +
603			`<Items>` +
604			`<item>A</item>` +
605			`<item>B</item>` +
606			`</Items>` +
607			`</result>`,
608	},
609	{
610		Value: &NestedItems{Items: []string{"A", "B"}, Item1: []string{"C"}},
611		ExpectXML: `<result>` +
612			`<Items>` +
613			`<item>A</item>` +
614			`<item>B</item>` +
615			`<item1>C</item1>` +
616			`</Items>` +
617			`</result>`,
618	},
619	{
620		Value: &NestedOrder{Field1: "C", Field2: "B", Field3: "A"},
621		ExpectXML: `<result>` +
622			`<parent>` +
623			`<c>C</c>` +
624			`<b>B</b>` +
625			`<a>A</a>` +
626			`</parent>` +
627			`</result>`,
628	},
629	{
630		Value: &NilTest{A: "A", B: nil, C: "C"},
631		ExpectXML: `<NilTest>` +
632			`<parent1>` +
633			`<parent2><a>A</a></parent2>` +
634			`<parent2><c>C</c></parent2>` +
635			`</parent1>` +
636			`</NilTest>`,
637		MarshalOnly: true, // Uses interface{}
638	},
639	{
640		Value: &MixedNested{A: "A", B: "B", C: "C", D: "D"},
641		ExpectXML: `<result>` +
642			`<parent1><a>A</a></parent1>` +
643			`<b>B</b>` +
644			`<parent1>` +
645			`<parent2><c>C</c></parent2>` +
646			`<d>D</d>` +
647			`</parent1>` +
648			`</result>`,
649	},
650	{
651		Value:     &Service{Port: &Port{Number: "80"}},
652		ExpectXML: `<service><host><port>80</port></host></service>`,
653	},
654	{
655		Value:     &Service{},
656		ExpectXML: `<service></service>`,
657	},
658	{
659		Value: &Service{Port: &Port{Number: "80"}, Extra1: "A", Extra2: "B"},
660		ExpectXML: `<service>` +
661			`<host><port>80</port></host>` +
662			`<Extra1>A</Extra1>` +
663			`<host><extra2>B</extra2></host>` +
664			`</service>`,
665		MarshalOnly: true,
666	},
667	{
668		Value: &Service{Port: &Port{Number: "80"}, Extra2: "example"},
669		ExpectXML: `<service>` +
670			`<host><port>80</port></host>` +
671			`<host><extra2>example</extra2></host>` +
672			`</service>`,
673		MarshalOnly: true,
674	},
675	{
676		Value: &struct {
677			XMLName struct{} `xml:"space top"`
678			A       string   `xml:"x>a"`
679			B       string   `xml:"x>b"`
680			C       string   `xml:"space x>c"`
681			C1      string   `xml:"space1 x>c"`
682			D1      string   `xml:"space1 x>d"`
683			E1      string   `xml:"x>e"`
684		}{
685			A:  "a",
686			B:  "b",
687			C:  "c",
688			C1: "c1",
689			D1: "d1",
690			E1: "e1",
691		},
692		ExpectXML: `<top xmlns="space">` +
693			`<x><a>a</a><b>b</b><c>c</c></x>` +
694			`<x xmlns="space1">` +
695			`<c>c1</c>` +
696			`<d>d1</d>` +
697			`</x>` +
698			`<x>` +
699			`<e>e1</e>` +
700			`</x>` +
701			`</top>`,
702	},
703	{
704		Value: &struct {
705			XMLName Name
706			A       string `xml:"x>a"`
707			B       string `xml:"x>b"`
708			C       string `xml:"space x>c"`
709			C1      string `xml:"space1 x>c"`
710			D1      string `xml:"space1 x>d"`
711		}{
712			XMLName: Name{
713				Space: "space0",
714				Local: "top",
715			},
716			A:  "a",
717			B:  "b",
718			C:  "c",
719			C1: "c1",
720			D1: "d1",
721		},
722		ExpectXML: `<top xmlns="space0">` +
723			`<x><a>a</a><b>b</b></x>` +
724			`<x xmlns="space"><c>c</c></x>` +
725			`<x xmlns="space1">` +
726			`<c>c1</c>` +
727			`<d>d1</d>` +
728			`</x>` +
729			`</top>`,
730	},
731	{
732		Value: &struct {
733			XMLName struct{} `xml:"top"`
734			B       string   `xml:"space x>b"`
735			B1      string   `xml:"space1 x>b"`
736		}{
737			B:  "b",
738			B1: "b1",
739		},
740		ExpectXML: `<top>` +
741			`<x xmlns="space"><b>b</b></x>` +
742			`<x xmlns="space1"><b>b1</b></x>` +
743			`</top>`,
744	},
745
746	// Test struct embedding
747	{
748		Value: &EmbedA{
749			EmbedC: EmbedC{
750				FieldA1: "", // Shadowed by A.A
751				FieldA2: "", // Shadowed by A.A
752				FieldB:  "A.C.B",
753				FieldC:  "A.C.C",
754			},
755			EmbedB: EmbedB{
756				FieldB: "A.B.B",
757				EmbedC: &EmbedC{
758					FieldA1: "A.B.C.A1",
759					FieldA2: "A.B.C.A2",
760					FieldB:  "", // Shadowed by A.B.B
761					FieldC:  "A.B.C.C",
762				},
763			},
764			FieldA: "A.A",
765		},
766		ExpectXML: `<EmbedA>` +
767			`<FieldB>A.C.B</FieldB>` +
768			`<FieldC>A.C.C</FieldC>` +
769			`<EmbedB>` +
770			`<FieldB>A.B.B</FieldB>` +
771			`<FieldA>` +
772			`<A1>A.B.C.A1</A1>` +
773			`<A2>A.B.C.A2</A2>` +
774			`</FieldA>` +
775			`<FieldC>A.B.C.C</FieldC>` +
776			`</EmbedB>` +
777			`<FieldA>A.A</FieldA>` +
778			`</EmbedA>`,
779	},
780
781	// Test that name casing matters
782	{
783		Value:     &NameCasing{Xy: "mixed", XY: "upper", XyA: "mixedA", XYA: "upperA"},
784		ExpectXML: `<casing Xy="mixedA" XY="upperA"><Xy>mixed</Xy><XY>upper</XY></casing>`,
785	},
786
787	// Test the order in which the XML element name is chosen
788	{
789		Value: &NamePrecedence{
790			FromTag:     XMLNameWithoutTag{Value: "A"},
791			FromNameVal: XMLNameWithoutTag{XMLName: Name{Local: "InXMLName"}, Value: "B"},
792			FromNameTag: XMLNameWithTag{Value: "C"},
793			InFieldName: "D",
794		},
795		ExpectXML: `<Parent>` +
796			`<InTag>A</InTag>` +
797			`<InXMLName>B</InXMLName>` +
798			`<InXMLNameTag>C</InXMLNameTag>` +
799			`<InFieldName>D</InFieldName>` +
800			`</Parent>`,
801		MarshalOnly: true,
802	},
803	{
804		Value: &NamePrecedence{
805			XMLName:     Name{Local: "Parent"},
806			FromTag:     XMLNameWithoutTag{XMLName: Name{Local: "InTag"}, Value: "A"},
807			FromNameVal: XMLNameWithoutTag{XMLName: Name{Local: "FromNameVal"}, Value: "B"},
808			FromNameTag: XMLNameWithTag{XMLName: Name{Local: "InXMLNameTag"}, Value: "C"},
809			InFieldName: "D",
810		},
811		ExpectXML: `<Parent>` +
812			`<InTag>A</InTag>` +
813			`<FromNameVal>B</FromNameVal>` +
814			`<InXMLNameTag>C</InXMLNameTag>` +
815			`<InFieldName>D</InFieldName>` +
816			`</Parent>`,
817		UnmarshalOnly: true,
818	},
819
820	// xml.Name works in a plain field as well.
821	{
822		Value:     &NameInField{Name{Space: "ns", Local: "foo"}},
823		ExpectXML: `<NameInField><foo xmlns="ns"></foo></NameInField>`,
824	},
825	{
826		Value:         &NameInField{Name{Space: "ns", Local: "foo"}},
827		ExpectXML:     `<NameInField><foo xmlns="ns"><ignore></ignore></foo></NameInField>`,
828		UnmarshalOnly: true,
829	},
830
831	// Marshaling zero xml.Name uses the tag or field name.
832	{
833		Value:       &NameInField{},
834		ExpectXML:   `<NameInField><foo xmlns="ns"></foo></NameInField>`,
835		MarshalOnly: true,
836	},
837
838	// Test attributes
839	{
840		Value: &AttrTest{
841			Int:   8,
842			Named: 9,
843			Float: 23.5,
844			Uint8: 255,
845			Bool:  true,
846			Str:   "str",
847			Bytes: []byte("byt"),
848		},
849		ExpectXML: `<AttrTest Int="8" int="9" Float="23.5" Uint8="255"` +
850			` Bool="true" Str="str" Bytes="byt"></AttrTest>`,
851	},
852	{
853		Value: &AttrTest{Bytes: []byte{}},
854		ExpectXML: `<AttrTest Int="0" int="0" Float="0" Uint8="0"` +
855			` Bool="false" Str="" Bytes=""></AttrTest>`,
856	},
857	{
858		Value: &OmitAttrTest{
859			Int:   8,
860			Named: 9,
861			Float: 23.5,
862			Uint8: 255,
863			Bool:  true,
864			Str:   "str",
865			Bytes: []byte("byt"),
866		},
867		ExpectXML: `<OmitAttrTest Int="8" int="9" Float="23.5" Uint8="255"` +
868			` Bool="true" Str="str" Bytes="byt"></OmitAttrTest>`,
869	},
870	{
871		Value:     &OmitAttrTest{},
872		ExpectXML: `<OmitAttrTest></OmitAttrTest>`,
873	},
874
875	// pointer fields
876	{
877		Value:       &PointerFieldsTest{Name: &nameAttr, Age: &ageAttr, Contents: &contentsAttr},
878		ExpectXML:   `<dummy name="Sarah" age="12">lorem ipsum</dummy>`,
879		MarshalOnly: true,
880	},
881
882	// empty chardata pointer field
883	{
884		Value:       &ChardataEmptyTest{},
885		ExpectXML:   `<test></test>`,
886		MarshalOnly: true,
887	},
888
889	// omitempty on fields
890	{
891		Value: &OmitFieldTest{
892			Int:   8,
893			Named: 9,
894			Float: 23.5,
895			Uint8: 255,
896			Bool:  true,
897			Str:   "str",
898			Bytes: []byte("byt"),
899			Ptr:   &PresenceTest{},
900		},
901		ExpectXML: `<OmitFieldTest>` +
902			`<Int>8</Int>` +
903			`<int>9</int>` +
904			`<Float>23.5</Float>` +
905			`<Uint8>255</Uint8>` +
906			`<Bool>true</Bool>` +
907			`<Str>str</Str>` +
908			`<Bytes>byt</Bytes>` +
909			`<Ptr></Ptr>` +
910			`</OmitFieldTest>`,
911	},
912	{
913		Value:     &OmitFieldTest{},
914		ExpectXML: `<OmitFieldTest></OmitFieldTest>`,
915	},
916
917	// Test ",any"
918	{
919		ExpectXML: `<a><nested><value>known</value></nested><other><sub>unknown</sub></other></a>`,
920		Value: &AnyTest{
921			Nested: "known",
922			AnyField: AnyHolder{
923				XMLName: Name{Local: "other"},
924				XML:     "<sub>unknown</sub>",
925			},
926		},
927	},
928	{
929		Value: &AnyTest{Nested: "known",
930			AnyField: AnyHolder{
931				XML:     "<unknown/>",
932				XMLName: Name{Local: "AnyField"},
933			},
934		},
935		ExpectXML: `<a><nested><value>known</value></nested><AnyField><unknown/></AnyField></a>`,
936	},
937	{
938		ExpectXML: `<a><nested><value>b</value></nested></a>`,
939		Value: &AnyOmitTest{
940			Nested: "b",
941		},
942	},
943	{
944		ExpectXML: `<a><nested><value>b</value></nested><c><d>e</d></c><g xmlns="f"><h>i</h></g></a>`,
945		Value: &AnySliceTest{
946			Nested: "b",
947			AnyField: []AnyHolder{
948				{
949					XMLName: Name{Local: "c"},
950					XML:     "<d>e</d>",
951				},
952				{
953					XMLName: Name{Space: "f", Local: "g"},
954					XML:     "<h>i</h>",
955				},
956			},
957		},
958	},
959	{
960		ExpectXML: `<a><nested><value>b</value></nested></a>`,
961		Value: &AnySliceTest{
962			Nested: "b",
963		},
964	},
965
966	// Test recursive types.
967	{
968		Value: &RecurseA{
969			A: "a1",
970			B: &RecurseB{
971				A: &RecurseA{"a2", nil},
972				B: "b1",
973			},
974		},
975		ExpectXML: `<RecurseA><A>a1</A><B><A><A>a2</A></A><B>b1</B></B></RecurseA>`,
976	},
977
978	// Test ignoring fields via "-" tag
979	{
980		ExpectXML: `<IgnoreTest></IgnoreTest>`,
981		Value:     &IgnoreTest{},
982	},
983	{
984		ExpectXML:   `<IgnoreTest></IgnoreTest>`,
985		Value:       &IgnoreTest{PublicSecret: "can't tell"},
986		MarshalOnly: true,
987	},
988	{
989		ExpectXML:     `<IgnoreTest><PublicSecret>ignore me</PublicSecret></IgnoreTest>`,
990		Value:         &IgnoreTest{},
991		UnmarshalOnly: true,
992	},
993
994	// Test escaping.
995	{
996		ExpectXML: `<a><nested><value>dquote: &#34;; squote: &#39;; ampersand: &amp;; less: &lt;; greater: &gt;;</value></nested><empty></empty></a>`,
997		Value: &AnyTest{
998			Nested:   `dquote: "; squote: '; ampersand: &; less: <; greater: >;`,
999			AnyField: AnyHolder{XMLName: Name{Local: "empty"}},
1000		},
1001	},
1002	{
1003		ExpectXML: `<a><nested><value>newline: &#xA;; cr: &#xD;; tab: &#x9;;</value></nested><AnyField></AnyField></a>`,
1004		Value: &AnyTest{
1005			Nested:   "newline: \n; cr: \r; tab: \t;",
1006			AnyField: AnyHolder{XMLName: Name{Local: "AnyField"}},
1007		},
1008	},
1009	{
1010		ExpectXML: "<a><nested><value>1\r2\r\n3\n\r4\n5</value></nested></a>",
1011		Value: &AnyTest{
1012			Nested: "1\n2\n3\n\n4\n5",
1013		},
1014		UnmarshalOnly: true,
1015	},
1016	{
1017		ExpectXML: `<EmbedInt><MyInt>42</MyInt></EmbedInt>`,
1018		Value: &EmbedInt{
1019			MyInt: 42,
1020		},
1021	},
1022	// Test omitempty with parent chain; see golang.org/issue/4168.
1023	{
1024		ExpectXML: `<Strings><A></A></Strings>`,
1025		Value:     &Strings{},
1026	},
1027	// Custom marshalers.
1028	{
1029		ExpectXML: `<MyMarshalerTest>hello world</MyMarshalerTest>`,
1030		Value:     &MyMarshalerTest{},
1031	},
1032	{
1033		ExpectXML: `<MarshalerStruct Foo="hello world"></MarshalerStruct>`,
1034		Value:     &MarshalerStruct{},
1035	},
1036	{
1037		ExpectXML: `<MarshalerValueStruct Foo="hello world"></MarshalerValueStruct>`,
1038		Value:     &MarshalerValueStruct{},
1039	},
1040	{
1041		ExpectXML: `<outer xmlns="testns" int="10"></outer>`,
1042		Value:     &OuterStruct{IntAttr: 10},
1043	},
1044	{
1045		ExpectXML: `<test xmlns="outerns" int="10"></test>`,
1046		Value:     &OuterNamedStruct{XMLName: Name{Space: "outerns", Local: "test"}, IntAttr: 10},
1047	},
1048	{
1049		ExpectXML: `<test xmlns="outerns" int="10"></test>`,
1050		Value:     &OuterNamedOrderedStruct{XMLName: Name{Space: "outerns", Local: "test"}, IntAttr: 10},
1051	},
1052	{
1053		ExpectXML: `<outer xmlns="testns" int="10"></outer>`,
1054		Value:     &OuterOuterStruct{OuterStruct{IntAttr: 10}},
1055	},
1056	{
1057		ExpectXML: `<NestedAndChardata><A><B></B><B></B></A>test</NestedAndChardata>`,
1058		Value:     &NestedAndChardata{AB: make([]string, 2), Chardata: "test"},
1059	},
1060	{
1061		ExpectXML: `<NestedAndComment><A><B></B><B></B></A><!--test--></NestedAndComment>`,
1062		Value:     &NestedAndComment{AB: make([]string, 2), Comment: "test"},
1063	},
1064	{
1065		ExpectXML: `<XMLNSFieldStruct xmlns="http://example.com/ns"><Body>hello world</Body></XMLNSFieldStruct>`,
1066		Value:     &XMLNSFieldStruct{Ns: "http://example.com/ns", Body: "hello world"},
1067	},
1068	{
1069		ExpectXML: `<testns:test xmlns:testns="testns" xmlns="http://example.com/ns"><Body>hello world</Body></testns:test>`,
1070		Value:     &NamedXMLNSFieldStruct{Ns: "http://example.com/ns", Body: "hello world"},
1071	},
1072	{
1073		ExpectXML: `<testns:test xmlns:testns="testns"><Body>hello world</Body></testns:test>`,
1074		Value:     &NamedXMLNSFieldStruct{Ns: "", Body: "hello world"},
1075	},
1076	{
1077		ExpectXML: `<XMLNSFieldStructWithOmitEmpty><Body>hello world</Body></XMLNSFieldStructWithOmitEmpty>`,
1078		Value:     &XMLNSFieldStructWithOmitEmpty{Body: "hello world"},
1079	},
1080	{
1081		// The xmlns attribute must be ignored because the <test>
1082		// element is in the empty namespace, so it's not possible
1083		// to set the default namespace to something non-empty.
1084		ExpectXML:   `<test><Body>hello world</Body></test>`,
1085		Value:       &NamedXMLNSFieldStructWithEmptyNamespace{Ns: "foo", Body: "hello world"},
1086		MarshalOnly: true,
1087	},
1088	{
1089		ExpectXML: `<RecursiveXMLNSFieldStruct xmlns="foo"><Body xmlns=""><Text>hello world</Text></Body></RecursiveXMLNSFieldStruct>`,
1090		Value: &RecursiveXMLNSFieldStruct{
1091			Ns: "foo",
1092			Body: &RecursiveXMLNSFieldStruct{
1093				Text: "hello world",
1094			},
1095		},
1096	},
1097}
1098
1099func TestMarshal(t *testing.T) {
1100	for idx, test := range marshalTests {
1101		if test.UnmarshalOnly {
1102			continue
1103		}
1104		data, err := Marshal(test.Value)
1105		if err != nil {
1106			t.Errorf("#%d: marshal(%#v): %s", idx, test.Value, err)
1107			continue
1108		}
1109		if got, want := string(data), test.ExpectXML; got != want {
1110			if strings.Contains(want, "\n") {
1111				t.Errorf("#%d: marshal(%#v):\nHAVE:\n%s\nWANT:\n%s", idx, test.Value, got, want)
1112			} else {
1113				t.Errorf("#%d: marshal(%#v):\nhave %#q\nwant %#q", idx, test.Value, got, want)
1114			}
1115		}
1116	}
1117}
1118
1119type AttrParent struct {
1120	X string `xml:"X>Y,attr"`
1121}
1122
1123type BadAttr struct {
1124	Name []string `xml:"name,attr"`
1125}
1126
1127var marshalErrorTests = []struct {
1128	Value interface{}
1129	Err   string
1130	Kind  reflect.Kind
1131}{
1132	{
1133		Value: make(chan bool),
1134		Err:   "xml: unsupported type: chan bool",
1135		Kind:  reflect.Chan,
1136	},
1137	{
1138		Value: map[string]string{
1139			"question": "What do you get when you multiply six by nine?",
1140			"answer":   "42",
1141		},
1142		Err:  "xml: unsupported type: map[string]string",
1143		Kind: reflect.Map,
1144	},
1145	{
1146		Value: map[*Ship]bool{nil: false},
1147		Err:   "xml: unsupported type: map[*xml.Ship]bool",
1148		Kind:  reflect.Map,
1149	},
1150	{
1151		Value: &Domain{Comment: []byte("f--bar")},
1152		Err:   `xml: comments must not contain "--"`,
1153	},
1154	// Reject parent chain with attr, never worked; see golang.org/issue/5033.
1155	{
1156		Value: &AttrParent{},
1157		Err:   `xml: X>Y chain not valid with attr flag`,
1158	},
1159	{
1160		Value: BadAttr{[]string{"X", "Y"}},
1161		Err:   `xml: unsupported type: []string`,
1162	},
1163}
1164
1165var marshalIndentTests = []struct {
1166	Value     interface{}
1167	Prefix    string
1168	Indent    string
1169	ExpectXML string
1170}{
1171	{
1172		Value: &SecretAgent{
1173			Handle:    "007",
1174			Identity:  "James Bond",
1175			Obfuscate: "<redacted/>",
1176		},
1177		Prefix:    "",
1178		Indent:    "\t",
1179		ExpectXML: fmt.Sprintf("<agent handle=\"007\">\n\t<Identity>James Bond</Identity><redacted/>\n</agent>"),
1180	},
1181}
1182
1183func TestMarshalErrors(t *testing.T) {
1184	for idx, test := range marshalErrorTests {
1185		data, err := Marshal(test.Value)
1186		if err == nil {
1187			t.Errorf("#%d: marshal(%#v) = [success] %q, want error %v", idx, test.Value, data, test.Err)
1188			continue
1189		}
1190		if err.Error() != test.Err {
1191			t.Errorf("#%d: marshal(%#v) = [error] %v, want %v", idx, test.Value, err, test.Err)
1192		}
1193		if test.Kind != reflect.Invalid {
1194			if kind := err.(*UnsupportedTypeError).Type.Kind(); kind != test.Kind {
1195				t.Errorf("#%d: marshal(%#v) = [error kind] %s, want %s", idx, test.Value, kind, test.Kind)
1196			}
1197		}
1198	}
1199}
1200
1201// Do invertibility testing on the various structures that we test
1202func TestUnmarshal(t *testing.T) {
1203	for i, test := range marshalTests {
1204		if test.MarshalOnly {
1205			continue
1206		}
1207		if _, ok := test.Value.(*Plain); ok {
1208			continue
1209		}
1210		vt := reflect.TypeOf(test.Value)
1211		dest := reflect.New(vt.Elem()).Interface()
1212		err := Unmarshal([]byte(test.ExpectXML), dest)
1213
1214		switch fix := dest.(type) {
1215		case *Feed:
1216			fix.Author.InnerXML = ""
1217			for i := range fix.Entry {
1218				fix.Entry[i].Author.InnerXML = ""
1219			}
1220		}
1221
1222		if err != nil {
1223			t.Errorf("#%d: unexpected error: %#v", i, err)
1224		} else if got, want := dest, test.Value; !reflect.DeepEqual(got, want) {
1225			t.Errorf("#%d: unmarshal(%q):\nhave %#v\nwant %#v", i, test.ExpectXML, got, want)
1226		}
1227	}
1228}
1229
1230func TestMarshalIndent(t *testing.T) {
1231	for i, test := range marshalIndentTests {
1232		data, err := MarshalIndent(test.Value, test.Prefix, test.Indent)
1233		if err != nil {
1234			t.Errorf("#%d: Error: %s", i, err)
1235			continue
1236		}
1237		if got, want := string(data), test.ExpectXML; got != want {
1238			t.Errorf("#%d: MarshalIndent:\nGot:%s\nWant:\n%s", i, got, want)
1239		}
1240	}
1241}
1242
1243type limitedBytesWriter struct {
1244	w      io.Writer
1245	remain int // until writes fail
1246}
1247
1248func (lw *limitedBytesWriter) Write(p []byte) (n int, err error) {
1249	if lw.remain <= 0 {
1250		println("error")
1251		return 0, errors.New("write limit hit")
1252	}
1253	if len(p) > lw.remain {
1254		p = p[:lw.remain]
1255		n, _ = lw.w.Write(p)
1256		lw.remain = 0
1257		return n, errors.New("write limit hit")
1258	}
1259	n, err = lw.w.Write(p)
1260	lw.remain -= n
1261	return n, err
1262}
1263
1264func TestMarshalWriteErrors(t *testing.T) {
1265	var buf bytes.Buffer
1266	const writeCap = 1024
1267	w := &limitedBytesWriter{&buf, writeCap}
1268	enc := NewEncoder(w)
1269	var err error
1270	var i int
1271	const n = 4000
1272	for i = 1; i <= n; i++ {
1273		err = enc.Encode(&Passenger{
1274			Name:   []string{"Alice", "Bob"},
1275			Weight: 5,
1276		})
1277		if err != nil {
1278			break
1279		}
1280	}
1281	if err == nil {
1282		t.Error("expected an error")
1283	}
1284	if i == n {
1285		t.Errorf("expected to fail before the end")
1286	}
1287	if buf.Len() != writeCap {
1288		t.Errorf("buf.Len() = %d; want %d", buf.Len(), writeCap)
1289	}
1290}
1291
1292func TestMarshalWriteIOErrors(t *testing.T) {
1293	enc := NewEncoder(errWriter{})
1294
1295	expectErr := "unwritable"
1296	err := enc.Encode(&Passenger{})
1297	if err == nil || err.Error() != expectErr {
1298		t.Errorf("EscapeTest = [error] %v, want %v", err, expectErr)
1299	}
1300}
1301
1302func TestMarshalFlush(t *testing.T) {
1303	var buf bytes.Buffer
1304	enc := NewEncoder(&buf)
1305	if err := enc.EncodeToken(CharData("hello world")); err != nil {
1306		t.Fatalf("enc.EncodeToken: %v", err)
1307	}
1308	if buf.Len() > 0 {
1309		t.Fatalf("enc.EncodeToken caused actual write: %q", buf.Bytes())
1310	}
1311	if err := enc.Flush(); err != nil {
1312		t.Fatalf("enc.Flush: %v", err)
1313	}
1314	if buf.String() != "hello world" {
1315		t.Fatalf("after enc.Flush, buf.String() = %q, want %q", buf.String(), "hello world")
1316	}
1317}
1318
1319var encodeElementTests = []struct {
1320	desc      string
1321	value     interface{}
1322	start     StartElement
1323	expectXML string
1324}{{
1325	desc:  "simple string",
1326	value: "hello",
1327	start: StartElement{
1328		Name: Name{Local: "a"},
1329	},
1330	expectXML: `<a>hello</a>`,
1331}, {
1332	desc:  "string with added attributes",
1333	value: "hello",
1334	start: StartElement{
1335		Name: Name{Local: "a"},
1336		Attr: []Attr{{
1337			Name:  Name{Local: "x"},
1338			Value: "y",
1339		}, {
1340			Name:  Name{Local: "foo"},
1341			Value: "bar",
1342		}},
1343	},
1344	expectXML: `<a x="y" foo="bar">hello</a>`,
1345}, {
1346	desc: "start element with default name space",
1347	value: struct {
1348		Foo XMLNameWithNSTag
1349	}{
1350		Foo: XMLNameWithNSTag{
1351			Value: "hello",
1352		},
1353	},
1354	start: StartElement{
1355		Name: Name{Space: "ns", Local: "a"},
1356		Attr: []Attr{{
1357			Name: Name{Local: "xmlns"},
1358			// "ns" is the name space defined in XMLNameWithNSTag
1359			Value: "ns",
1360		}},
1361	},
1362	expectXML: `<a xmlns="ns"><InXMLNameWithNSTag>hello</InXMLNameWithNSTag></a>`,
1363}, {
1364	desc: "start element in name space with different default name space",
1365	value: struct {
1366		Foo XMLNameWithNSTag
1367	}{
1368		Foo: XMLNameWithNSTag{
1369			Value: "hello",
1370		},
1371	},
1372	start: StartElement{
1373		Name: Name{Space: "ns2", Local: "a"},
1374		Attr: []Attr{{
1375			Name: Name{Local: "xmlns"},
1376			// "ns" is the name space defined in XMLNameWithNSTag
1377			Value: "ns",
1378		}},
1379	},
1380	expectXML: `<ns2:a xmlns:ns2="ns2" xmlns="ns"><InXMLNameWithNSTag>hello</InXMLNameWithNSTag></ns2:a>`,
1381}, {
1382	desc:  "XMLMarshaler with start element with default name space",
1383	value: &MyMarshalerTest{},
1384	start: StartElement{
1385		Name: Name{Space: "ns2", Local: "a"},
1386		Attr: []Attr{{
1387			Name: Name{Local: "xmlns"},
1388			// "ns" is the name space defined in XMLNameWithNSTag
1389			Value: "ns",
1390		}},
1391	},
1392	expectXML: `<ns2:a xmlns:ns2="ns2" xmlns="ns">hello world</ns2:a>`,
1393}}
1394
1395func TestEncodeElement(t *testing.T) {
1396	for idx, test := range encodeElementTests {
1397		var buf bytes.Buffer
1398		enc := NewEncoder(&buf)
1399		err := enc.EncodeElement(test.value, test.start)
1400		if err != nil {
1401			t.Fatalf("enc.EncodeElement: %v", err)
1402		}
1403		err = enc.Flush()
1404		if err != nil {
1405			t.Fatalf("enc.Flush: %v", err)
1406		}
1407		if got, want := buf.String(), test.expectXML; got != want {
1408			t.Errorf("#%d(%s): EncodeElement(%#v, %#v):\nhave %#q\nwant %#q", idx, test.desc, test.value, test.start, got, want)
1409		}
1410	}
1411}
1412
1413func BenchmarkMarshal(b *testing.B) {
1414	b.ReportAllocs()
1415	for i := 0; i < b.N; i++ {
1416		Marshal(atomValue)
1417	}
1418}
1419
1420func BenchmarkUnmarshal(b *testing.B) {
1421	b.ReportAllocs()
1422	xml := []byte(atomXml)
1423	for i := 0; i < b.N; i++ {
1424		Unmarshal(xml, &Feed{})
1425	}
1426}
1427
1428// golang.org/issue/6556
1429func TestStructPointerMarshal(t *testing.T) {
1430	type A struct {
1431		XMLName string `xml:"a"`
1432		B       []interface{}
1433	}
1434	type C struct {
1435		XMLName Name
1436		Value   string `xml:"value"`
1437	}
1438
1439	a := new(A)
1440	a.B = append(a.B, &C{
1441		XMLName: Name{Local: "c"},
1442		Value:   "x",
1443	})
1444
1445	b, err := Marshal(a)
1446	if err != nil {
1447		t.Fatal(err)
1448	}
1449	if x := string(b); x != "<a><c><value>x</value></c></a>" {
1450		t.Fatal(x)
1451	}
1452	var v A
1453	err = Unmarshal(b, &v)
1454	if err != nil {
1455		t.Fatal(err)
1456	}
1457}
1458
1459var encodeTokenTests = []struct {
1460	desc string
1461	toks []Token
1462	want string
1463	err  string
1464}{{
1465	desc: "start element with name space",
1466	toks: []Token{
1467		StartElement{Name{"space", "local"}, nil},
1468	},
1469	want: `<space:local xmlns:space="space">`,
1470}, {
1471	desc: "start element with no name",
1472	toks: []Token{
1473		StartElement{Name{"space", ""}, nil},
1474	},
1475	err: "xml: start tag with no name",
1476}, {
1477	desc: "end element with no name",
1478	toks: []Token{
1479		EndElement{Name{"space", ""}},
1480	},
1481	err: "xml: end tag with no name",
1482}, {
1483	desc: "char data",
1484	toks: []Token{
1485		CharData("foo"),
1486	},
1487	want: `foo`,
1488}, {
1489	desc: "char data with escaped chars",
1490	toks: []Token{
1491		CharData(" \t\n"),
1492	},
1493	want: " &#x9;\n",
1494}, {
1495	desc: "comment",
1496	toks: []Token{
1497		Comment("foo"),
1498	},
1499	want: `<!--foo-->`,
1500}, {
1501	desc: "comment with invalid content",
1502	toks: []Token{
1503		Comment("foo-->"),
1504	},
1505	err: "xml: EncodeToken of Comment containing --> marker",
1506}, {
1507	desc: "proc instruction",
1508	toks: []Token{
1509		ProcInst{"Target", []byte("Instruction")},
1510	},
1511	want: `<?Target Instruction?>`,
1512}, {
1513	desc: "proc instruction with empty target",
1514	toks: []Token{
1515		ProcInst{"", []byte("Instruction")},
1516	},
1517	err: "xml: EncodeToken of ProcInst with invalid Target",
1518}, {
1519	desc: "proc instruction with bad content",
1520	toks: []Token{
1521		ProcInst{"", []byte("Instruction?>")},
1522	},
1523	err: "xml: EncodeToken of ProcInst with invalid Target",
1524}, {
1525	desc: "directive",
1526	toks: []Token{
1527		Directive("foo"),
1528	},
1529	want: `<!foo>`,
1530}, {
1531	desc: "more complex directive",
1532	toks: []Token{
1533		Directive("DOCTYPE doc [ <!ELEMENT doc '>'> <!-- com>ment --> ]"),
1534	},
1535	want: `<!DOCTYPE doc [ <!ELEMENT doc '>'> <!-- com>ment --> ]>`,
1536}, {
1537	desc: "directive instruction with bad name",
1538	toks: []Token{
1539		Directive("foo>"),
1540	},
1541	err: "xml: EncodeToken of Directive containing wrong < or > markers",
1542}, {
1543	desc: "end tag without start tag",
1544	toks: []Token{
1545		EndElement{Name{"foo", "bar"}},
1546	},
1547	err: "xml: end tag </bar> without start tag",
1548}, {
1549	desc: "mismatching end tag local name",
1550	toks: []Token{
1551		StartElement{Name{"", "foo"}, nil},
1552		EndElement{Name{"", "bar"}},
1553	},
1554	err:  "xml: end tag </bar> does not match start tag <foo>",
1555	want: `<foo>`,
1556}, {
1557	desc: "mismatching end tag namespace",
1558	toks: []Token{
1559		StartElement{Name{"space", "foo"}, nil},
1560		EndElement{Name{"another", "foo"}},
1561	},
1562	err:  "xml: end tag </foo> in namespace another does not match start tag <foo> in namespace space",
1563	want: `<space:foo xmlns:space="space">`,
1564}, {
1565	desc: "start element with explicit namespace",
1566	toks: []Token{
1567		StartElement{Name{"space", "local"}, []Attr{
1568			{Name{"xmlns", "x"}, "space"},
1569			{Name{"space", "foo"}, "value"},
1570		}},
1571	},
1572	want: `<x:local xmlns:x="space" x:foo="value">`,
1573}, {
1574	desc: "start element with explicit namespace and colliding prefix",
1575	toks: []Token{
1576		StartElement{Name{"space", "local"}, []Attr{
1577			{Name{"xmlns", "x"}, "space"},
1578			{Name{"space", "foo"}, "value"},
1579			{Name{"x", "bar"}, "other"},
1580		}},
1581	},
1582	want: `<x:local xmlns:x_1="x" xmlns:x="space" x:foo="value" x_1:bar="other">`,
1583}, {
1584	desc: "start element using previously defined namespace",
1585	toks: []Token{
1586		StartElement{Name{"", "local"}, []Attr{
1587			{Name{"xmlns", "x"}, "space"},
1588		}},
1589		StartElement{Name{"space", "foo"}, []Attr{
1590			{Name{"space", "x"}, "y"},
1591		}},
1592	},
1593	want: `<local xmlns:x="space"><x:foo x:x="y">`,
1594}, {
1595	desc: "nested name space with same prefix",
1596	toks: []Token{
1597		StartElement{Name{"", "foo"}, []Attr{
1598			{Name{"xmlns", "x"}, "space1"},
1599		}},
1600		StartElement{Name{"", "foo"}, []Attr{
1601			{Name{"xmlns", "x"}, "space2"},
1602		}},
1603		StartElement{Name{"", "foo"}, []Attr{
1604			{Name{"space1", "a"}, "space1 value"},
1605			{Name{"space2", "b"}, "space2 value"},
1606		}},
1607		EndElement{Name{"", "foo"}},
1608		EndElement{Name{"", "foo"}},
1609		StartElement{Name{"", "foo"}, []Attr{
1610			{Name{"space1", "a"}, "space1 value"},
1611			{Name{"space2", "b"}, "space2 value"},
1612		}},
1613	},
1614	want: `<foo xmlns:x="space1"><foo xmlns:x="space2"><foo xmlns:space1="space1" space1:a="space1 value" x:b="space2 value"></foo></foo><foo xmlns:space2="space2" x:a="space1 value" space2:b="space2 value">`,
1615}, {
1616	desc: "start element defining several prefixes for the same name space",
1617	toks: []Token{
1618		StartElement{Name{"space", "foo"}, []Attr{
1619			{Name{"xmlns", "a"}, "space"},
1620			{Name{"xmlns", "b"}, "space"},
1621			{Name{"space", "x"}, "value"},
1622		}},
1623	},
1624	want: `<a:foo xmlns:a="space" a:x="value">`,
1625}, {
1626	desc: "nested element redefines name space",
1627	toks: []Token{
1628		StartElement{Name{"", "foo"}, []Attr{
1629			{Name{"xmlns", "x"}, "space"},
1630		}},
1631		StartElement{Name{"space", "foo"}, []Attr{
1632			{Name{"xmlns", "y"}, "space"},
1633			{Name{"space", "a"}, "value"},
1634		}},
1635	},
1636	want: `<foo xmlns:x="space"><x:foo x:a="value">`,
1637}, {
1638	desc: "nested element creates alias for default name space",
1639	toks: []Token{
1640		StartElement{Name{"space", "foo"}, []Attr{
1641			{Name{"", "xmlns"}, "space"},
1642		}},
1643		StartElement{Name{"space", "foo"}, []Attr{
1644			{Name{"xmlns", "y"}, "space"},
1645			{Name{"space", "a"}, "value"},
1646		}},
1647	},
1648	want: `<foo xmlns="space"><foo xmlns:y="space" y:a="value">`,
1649}, {
1650	desc: "nested element defines default name space with existing prefix",
1651	toks: []Token{
1652		StartElement{Name{"", "foo"}, []Attr{
1653			{Name{"xmlns", "x"}, "space"},
1654		}},
1655		StartElement{Name{"space", "foo"}, []Attr{
1656			{Name{"", "xmlns"}, "space"},
1657			{Name{"space", "a"}, "value"},
1658		}},
1659	},
1660	want: `<foo xmlns:x="space"><foo xmlns="space" x:a="value">`,
1661}, {
1662	desc: "nested element uses empty attribute name space when default ns defined",
1663	toks: []Token{
1664		StartElement{Name{"space", "foo"}, []Attr{
1665			{Name{"", "xmlns"}, "space"},
1666		}},
1667		StartElement{Name{"space", "foo"}, []Attr{
1668			{Name{"", "attr"}, "value"},
1669		}},
1670	},
1671	want: `<foo xmlns="space"><foo attr="value">`,
1672}, {
1673	desc: "redefine xmlns",
1674	toks: []Token{
1675		StartElement{Name{"", "foo"}, []Attr{
1676			{Name{"foo", "xmlns"}, "space"},
1677		}},
1678	},
1679	err: `xml: cannot redefine xmlns attribute prefix`,
1680}, {
1681	desc: "xmlns with explicit name space #1",
1682	toks: []Token{
1683		StartElement{Name{"space", "foo"}, []Attr{
1684			{Name{"xml", "xmlns"}, "space"},
1685		}},
1686	},
1687	want: `<foo xmlns="space">`,
1688}, {
1689	desc: "xmlns with explicit name space #2",
1690	toks: []Token{
1691		StartElement{Name{"space", "foo"}, []Attr{
1692			{Name{xmlURL, "xmlns"}, "space"},
1693		}},
1694	},
1695	want: `<foo xmlns="space">`,
1696}, {
1697	desc: "empty name space declaration is ignored",
1698	toks: []Token{
1699		StartElement{Name{"", "foo"}, []Attr{
1700			{Name{"xmlns", "foo"}, ""},
1701		}},
1702	},
1703	want: `<foo>`,
1704}, {
1705	desc: "attribute with no name is ignored",
1706	toks: []Token{
1707		StartElement{Name{"", "foo"}, []Attr{
1708			{Name{"", ""}, "value"},
1709		}},
1710	},
1711	want: `<foo>`,
1712}, {
1713	desc: "namespace URL with non-valid name",
1714	toks: []Token{
1715		StartElement{Name{"/34", "foo"}, []Attr{
1716			{Name{"/34", "x"}, "value"},
1717		}},
1718	},
1719	want: `<_:foo xmlns:_="/34" _:x="value">`,
1720}, {
1721	desc: "nested element resets default namespace to empty",
1722	toks: []Token{
1723		StartElement{Name{"space", "foo"}, []Attr{
1724			{Name{"", "xmlns"}, "space"},
1725		}},
1726		StartElement{Name{"", "foo"}, []Attr{
1727			{Name{"", "xmlns"}, ""},
1728			{Name{"", "x"}, "value"},
1729			{Name{"space", "x"}, "value"},
1730		}},
1731	},
1732	want: `<foo xmlns="space"><foo xmlns:space="space" xmlns="" x="value" space:x="value">`,
1733}, {
1734	desc: "nested element requires empty default name space",
1735	toks: []Token{
1736		StartElement{Name{"space", "foo"}, []Attr{
1737			{Name{"", "xmlns"}, "space"},
1738		}},
1739		StartElement{Name{"", "foo"}, nil},
1740	},
1741	want: `<foo xmlns="space"><foo xmlns="">`,
1742}, {
1743	desc: "attribute uses name space from xmlns",
1744	toks: []Token{
1745		StartElement{Name{"some/space", "foo"}, []Attr{
1746			{Name{"", "attr"}, "value"},
1747			{Name{"some/space", "other"}, "other value"},
1748		}},
1749	},
1750	want: `<space:foo xmlns:space="some/space" attr="value" space:other="other value">`,
1751}, {
1752	desc: "default name space should not be used by attributes",
1753	toks: []Token{
1754		StartElement{Name{"space", "foo"}, []Attr{
1755			{Name{"", "xmlns"}, "space"},
1756			{Name{"xmlns", "bar"}, "space"},
1757			{Name{"space", "baz"}, "foo"},
1758		}},
1759		StartElement{Name{"space", "baz"}, nil},
1760		EndElement{Name{"space", "baz"}},
1761		EndElement{Name{"space", "foo"}},
1762	},
1763	want: `<foo xmlns:bar="space" xmlns="space" bar:baz="foo"><baz></baz></foo>`,
1764}, {
1765	desc: "default name space not used by attributes, not explicitly defined",
1766	toks: []Token{
1767		StartElement{Name{"space", "foo"}, []Attr{
1768			{Name{"", "xmlns"}, "space"},
1769			{Name{"space", "baz"}, "foo"},
1770		}},
1771		StartElement{Name{"space", "baz"}, nil},
1772		EndElement{Name{"space", "baz"}},
1773		EndElement{Name{"space", "foo"}},
1774	},
1775	want: `<foo xmlns:space="space" xmlns="space" space:baz="foo"><baz></baz></foo>`,
1776}, {
1777	desc: "impossible xmlns declaration",
1778	toks: []Token{
1779		StartElement{Name{"", "foo"}, []Attr{
1780			{Name{"", "xmlns"}, "space"},
1781		}},
1782		StartElement{Name{"space", "bar"}, []Attr{
1783			{Name{"space", "attr"}, "value"},
1784		}},
1785	},
1786	want: `<foo><space:bar xmlns:space="space" space:attr="value">`,
1787}}
1788
1789func TestEncodeToken(t *testing.T) {
1790loop:
1791	for i, tt := range encodeTokenTests {
1792		var buf bytes.Buffer
1793		enc := NewEncoder(&buf)
1794		var err error
1795		for j, tok := range tt.toks {
1796			err = enc.EncodeToken(tok)
1797			if err != nil && j < len(tt.toks)-1 {
1798				t.Errorf("#%d %s token #%d: %v", i, tt.desc, j, err)
1799				continue loop
1800			}
1801		}
1802		errorf := func(f string, a ...interface{}) {
1803			t.Errorf("#%d %s token #%d:%s", i, tt.desc, len(tt.toks)-1, fmt.Sprintf(f, a...))
1804		}
1805		switch {
1806		case tt.err != "" && err == nil:
1807			errorf(" expected error; got none")
1808			continue
1809		case tt.err == "" && err != nil:
1810			errorf(" got error: %v", err)
1811			continue
1812		case tt.err != "" && err != nil && tt.err != err.Error():
1813			errorf(" error mismatch; got %v, want %v", err, tt.err)
1814			continue
1815		}
1816		if err := enc.Flush(); err != nil {
1817			errorf(" %v", err)
1818			continue
1819		}
1820		if got := buf.String(); got != tt.want {
1821			errorf("\ngot  %v\nwant %v", got, tt.want)
1822			continue
1823		}
1824	}
1825}
1826
1827func TestProcInstEncodeToken(t *testing.T) {
1828	var buf bytes.Buffer
1829	enc := NewEncoder(&buf)
1830
1831	if err := enc.EncodeToken(ProcInst{"xml", []byte("Instruction")}); err != nil {
1832		t.Fatalf("enc.EncodeToken: expected to be able to encode xml target ProcInst as first token, %s", err)
1833	}
1834
1835	if err := enc.EncodeToken(ProcInst{"Target", []byte("Instruction")}); err != nil {
1836		t.Fatalf("enc.EncodeToken: expected to be able to add non-xml target ProcInst")
1837	}
1838
1839	if err := enc.EncodeToken(ProcInst{"xml", []byte("Instruction")}); err == nil {
1840		t.Fatalf("enc.EncodeToken: expected to not be allowed to encode xml target ProcInst when not first token")
1841	}
1842}
1843
1844func TestDecodeEncode(t *testing.T) {
1845	var in, out bytes.Buffer
1846	in.WriteString(`<?xml version="1.0" encoding="UTF-8"?>
1847<?Target Instruction?>
1848<root>
1849</root>
1850`)
1851	dec := NewDecoder(&in)
1852	enc := NewEncoder(&out)
1853	for tok, err := dec.Token(); err == nil; tok, err = dec.Token() {
1854		err = enc.EncodeToken(tok)
1855		if err != nil {
1856			t.Fatalf("enc.EncodeToken: Unable to encode token (%#v), %v", tok, err)
1857		}
1858	}
1859}
1860
1861// Issue 9796. Used to fail with GORACE="halt_on_error=1" -race.
1862func TestRace9796(t *testing.T) {
1863	type A struct{}
1864	type B struct {
1865		C []A `xml:"X>Y"`
1866	}
1867	var wg sync.WaitGroup
1868	for i := 0; i < 2; i++ {
1869		wg.Add(1)
1870		go func() {
1871			Marshal(B{[]A{{}}})
1872			wg.Done()
1873		}()
1874	}
1875	wg.Wait()
1876}
1877
1878func TestIsValidDirective(t *testing.T) {
1879	testOK := []string{
1880		"<>",
1881		"< < > >",
1882		"<!DOCTYPE '<' '>' '>' <!--nothing-->>",
1883		"<!DOCTYPE doc [ <!ELEMENT doc ANY> <!ELEMENT doc ANY> ]>",
1884		"<!DOCTYPE doc [ <!ELEMENT doc \"ANY> '<' <!E\" LEMENT '>' doc ANY> ]>",
1885		"<!DOCTYPE doc <!-- just>>>> a < comment --> [ <!ITEM anything> ] >",
1886	}
1887	testKO := []string{
1888		"<",
1889		">",
1890		"<!--",
1891		"-->",
1892		"< > > < < >",
1893		"<!dummy <!-- > -->",
1894		"<!DOCTYPE doc '>",
1895		"<!DOCTYPE doc '>'",
1896		"<!DOCTYPE doc <!--comment>",
1897	}
1898	for _, s := range testOK {
1899		if !isValidDirective(Directive(s)) {
1900			t.Errorf("Directive %q is expected to be valid", s)
1901		}
1902	}
1903	for _, s := range testKO {
1904		if isValidDirective(Directive(s)) {
1905			t.Errorf("Directive %q is expected to be invalid", s)
1906		}
1907	}
1908}
1909
1910// Issue 11719. EncodeToken used to silently eat tokens with an invalid type.
1911func TestSimpleUseOfEncodeToken(t *testing.T) {
1912	var buf bytes.Buffer
1913	enc := NewEncoder(&buf)
1914	if err := enc.EncodeToken(&StartElement{Name: Name{"", "object1"}}); err == nil {
1915		t.Errorf("enc.EncodeToken: pointer type should be rejected")
1916	}
1917	if err := enc.EncodeToken(&EndElement{Name: Name{"", "object1"}}); err == nil {
1918		t.Errorf("enc.EncodeToken: pointer type should be rejected")
1919	}
1920	if err := enc.EncodeToken(StartElement{Name: Name{"", "object2"}}); err != nil {
1921		t.Errorf("enc.EncodeToken: StartElement %s", err)
1922	}
1923	if err := enc.EncodeToken(EndElement{Name: Name{"", "object2"}}); err != nil {
1924		t.Errorf("enc.EncodeToken: EndElement %s", err)
1925	}
1926	if err := enc.EncodeToken(Universe{}); err == nil {
1927		t.Errorf("enc.EncodeToken: invalid type not caught")
1928	}
1929	if err := enc.Flush(); err != nil {
1930		t.Errorf("enc.Flush: %s", err)
1931	}
1932	if buf.Len() == 0 {
1933		t.Errorf("enc.EncodeToken: empty buffer")
1934	}
1935	want := "<object2></object2>"
1936	if buf.String() != want {
1937		t.Errorf("enc.EncodeToken: expected %q; got %q", want, buf.String())
1938	}
1939}
1940