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