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 any `xml:"parent1>parent2>a"`
124	B any `xml:"parent1>b"`
125	C any `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  any
133	Extra2  any `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 AttrsTest struct {
203	Attrs []Attr  `xml:",any,attr"`
204	Int   int     `xml:",attr"`
205	Named int     `xml:"int,attr"`
206	Float float64 `xml:",attr"`
207	Uint8 uint8   `xml:",attr"`
208	Bool  bool    `xml:",attr"`
209	Str   string  `xml:",attr"`
210	Bytes []byte  `xml:",attr"`
211}
212
213type OmitAttrTest struct {
214	Int   int     `xml:",attr,omitempty"`
215	Named int     `xml:"int,attr,omitempty"`
216	Float float64 `xml:",attr,omitempty"`
217	Uint8 uint8   `xml:",attr,omitempty"`
218	Bool  bool    `xml:",attr,omitempty"`
219	Str   string  `xml:",attr,omitempty"`
220	Bytes []byte  `xml:",attr,omitempty"`
221	PStr  *string `xml:",attr,omitempty"`
222}
223
224type OmitFieldTest struct {
225	Int   int           `xml:",omitempty"`
226	Named int           `xml:"int,omitempty"`
227	Float float64       `xml:",omitempty"`
228	Uint8 uint8         `xml:",omitempty"`
229	Bool  bool          `xml:",omitempty"`
230	Str   string        `xml:",omitempty"`
231	Bytes []byte        `xml:",omitempty"`
232	PStr  *string       `xml:",omitempty"`
233	Ptr   *PresenceTest `xml:",omitempty"`
234}
235
236type AnyTest struct {
237	XMLName  struct{}  `xml:"a"`
238	Nested   string    `xml:"nested>value"`
239	AnyField AnyHolder `xml:",any"`
240}
241
242type AnyOmitTest struct {
243	XMLName  struct{}   `xml:"a"`
244	Nested   string     `xml:"nested>value"`
245	AnyField *AnyHolder `xml:",any,omitempty"`
246}
247
248type AnySliceTest struct {
249	XMLName  struct{}    `xml:"a"`
250	Nested   string      `xml:"nested>value"`
251	AnyField []AnyHolder `xml:",any"`
252}
253
254type AnyHolder struct {
255	XMLName Name
256	XML     string `xml:",innerxml"`
257}
258
259type RecurseA struct {
260	A string
261	B *RecurseB
262}
263
264type RecurseB struct {
265	A *RecurseA
266	B string
267}
268
269type PresenceTest struct {
270	Exists *struct{}
271}
272
273type IgnoreTest struct {
274	PublicSecret string `xml:"-"`
275}
276
277type MyBytes []byte
278
279type Data struct {
280	Bytes  []byte
281	Attr   []byte `xml:",attr"`
282	Custom MyBytes
283}
284
285type Plain struct {
286	V any
287}
288
289type MyInt int
290
291type EmbedInt struct {
292	MyInt
293}
294
295type Strings struct {
296	X []string `xml:"A>B,omitempty"`
297}
298
299type PointerFieldsTest struct {
300	XMLName  Name    `xml:"dummy"`
301	Name     *string `xml:"name,attr"`
302	Age      *uint   `xml:"age,attr"`
303	Empty    *string `xml:"empty,attr"`
304	Contents *string `xml:",chardata"`
305}
306
307type ChardataEmptyTest struct {
308	XMLName  Name    `xml:"test"`
309	Contents *string `xml:",chardata"`
310}
311
312type PointerAnonFields struct {
313	*MyInt
314	*NamedType
315}
316
317type MyMarshalerTest struct {
318}
319
320var _ Marshaler = (*MyMarshalerTest)(nil)
321
322func (m *MyMarshalerTest) MarshalXML(e *Encoder, start StartElement) error {
323	e.EncodeToken(start)
324	e.EncodeToken(CharData([]byte("hello world")))
325	e.EncodeToken(EndElement{start.Name})
326	return nil
327}
328
329type MyMarshalerAttrTest struct {
330}
331
332var _ MarshalerAttr = (*MyMarshalerAttrTest)(nil)
333
334func (m *MyMarshalerAttrTest) MarshalXMLAttr(name Name) (Attr, error) {
335	return Attr{name, "hello world"}, nil
336}
337
338func (m *MyMarshalerAttrTest) UnmarshalXMLAttr(attr Attr) error {
339	return nil
340}
341
342type MarshalerStruct struct {
343	Foo MyMarshalerAttrTest `xml:",attr"`
344}
345
346type InnerStruct struct {
347	XMLName Name `xml:"testns outer"`
348}
349
350type OuterStruct struct {
351	InnerStruct
352	IntAttr int `xml:"int,attr"`
353}
354
355type OuterNamedStruct struct {
356	InnerStruct
357	XMLName Name `xml:"outerns test"`
358	IntAttr int  `xml:"int,attr"`
359}
360
361type OuterNamedOrderedStruct struct {
362	XMLName Name `xml:"outerns test"`
363	InnerStruct
364	IntAttr int `xml:"int,attr"`
365}
366
367type OuterOuterStruct struct {
368	OuterStruct
369}
370
371type NestedAndChardata struct {
372	AB       []string `xml:"A>B"`
373	Chardata string   `xml:",chardata"`
374}
375
376type NestedAndComment struct {
377	AB      []string `xml:"A>B"`
378	Comment string   `xml:",comment"`
379}
380
381type CDataTest struct {
382	Chardata string `xml:",cdata"`
383}
384
385type NestedAndCData struct {
386	AB    []string `xml:"A>B"`
387	CDATA string   `xml:",cdata"`
388}
389
390func ifaceptr(x any) any {
391	return &x
392}
393
394func stringptr(x string) *string {
395	return &x
396}
397
398type T1 struct{}
399type T2 struct{}
400
401type IndirComment struct {
402	T1      T1
403	Comment *string `xml:",comment"`
404	T2      T2
405}
406
407type DirectComment struct {
408	T1      T1
409	Comment string `xml:",comment"`
410	T2      T2
411}
412
413type IfaceComment struct {
414	T1      T1
415	Comment any `xml:",comment"`
416	T2      T2
417}
418
419type IndirChardata struct {
420	T1       T1
421	Chardata *string `xml:",chardata"`
422	T2       T2
423}
424
425type DirectChardata struct {
426	T1       T1
427	Chardata string `xml:",chardata"`
428	T2       T2
429}
430
431type IfaceChardata struct {
432	T1       T1
433	Chardata any `xml:",chardata"`
434	T2       T2
435}
436
437type IndirCDATA struct {
438	T1    T1
439	CDATA *string `xml:",cdata"`
440	T2    T2
441}
442
443type DirectCDATA struct {
444	T1    T1
445	CDATA string `xml:",cdata"`
446	T2    T2
447}
448
449type IfaceCDATA struct {
450	T1    T1
451	CDATA any `xml:",cdata"`
452	T2    T2
453}
454
455type IndirInnerXML struct {
456	T1       T1
457	InnerXML *string `xml:",innerxml"`
458	T2       T2
459}
460
461type DirectInnerXML struct {
462	T1       T1
463	InnerXML string `xml:",innerxml"`
464	T2       T2
465}
466
467type IfaceInnerXML struct {
468	T1       T1
469	InnerXML any `xml:",innerxml"`
470	T2       T2
471}
472
473type IndirElement struct {
474	T1      T1
475	Element *string
476	T2      T2
477}
478
479type DirectElement struct {
480	T1      T1
481	Element string
482	T2      T2
483}
484
485type IfaceElement struct {
486	T1      T1
487	Element any
488	T2      T2
489}
490
491type IndirOmitEmpty struct {
492	T1        T1
493	OmitEmpty *string `xml:",omitempty"`
494	T2        T2
495}
496
497type DirectOmitEmpty struct {
498	T1        T1
499	OmitEmpty string `xml:",omitempty"`
500	T2        T2
501}
502
503type IfaceOmitEmpty struct {
504	T1        T1
505	OmitEmpty any `xml:",omitempty"`
506	T2        T2
507}
508
509type IndirAny struct {
510	T1  T1
511	Any *string `xml:",any"`
512	T2  T2
513}
514
515type DirectAny struct {
516	T1  T1
517	Any string `xml:",any"`
518	T2  T2
519}
520
521type IfaceAny struct {
522	T1  T1
523	Any any `xml:",any"`
524	T2  T2
525}
526
527type Generic[T any] struct {
528	X T
529}
530
531var (
532	nameAttr     = "Sarah"
533	ageAttr      = uint(12)
534	contentsAttr = "lorem ipsum"
535	empty        = ""
536)
537
538// Unless explicitly stated as such (or *Plain), all of the
539// tests below are two-way tests. When introducing new tests,
540// please try to make them two-way as well to ensure that
541// marshaling and unmarshaling are as symmetrical as feasible.
542var marshalTests = []struct {
543	Value          any
544	ExpectXML      string
545	MarshalOnly    bool
546	MarshalError   string
547	UnmarshalOnly  bool
548	UnmarshalError string
549}{
550	// Test nil marshals to nothing
551	{Value: nil, ExpectXML: ``, MarshalOnly: true},
552	{Value: nilStruct, ExpectXML: ``, MarshalOnly: true},
553
554	// Test value types
555	{Value: &Plain{true}, ExpectXML: `<Plain><V>true</V></Plain>`},
556	{Value: &Plain{false}, ExpectXML: `<Plain><V>false</V></Plain>`},
557	{Value: &Plain{int(42)}, ExpectXML: `<Plain><V>42</V></Plain>`},
558	{Value: &Plain{int8(42)}, ExpectXML: `<Plain><V>42</V></Plain>`},
559	{Value: &Plain{int16(42)}, ExpectXML: `<Plain><V>42</V></Plain>`},
560	{Value: &Plain{int32(42)}, ExpectXML: `<Plain><V>42</V></Plain>`},
561	{Value: &Plain{uint(42)}, ExpectXML: `<Plain><V>42</V></Plain>`},
562	{Value: &Plain{uint8(42)}, ExpectXML: `<Plain><V>42</V></Plain>`},
563	{Value: &Plain{uint16(42)}, ExpectXML: `<Plain><V>42</V></Plain>`},
564	{Value: &Plain{uint32(42)}, ExpectXML: `<Plain><V>42</V></Plain>`},
565	{Value: &Plain{float32(1.25)}, ExpectXML: `<Plain><V>1.25</V></Plain>`},
566	{Value: &Plain{float64(1.25)}, ExpectXML: `<Plain><V>1.25</V></Plain>`},
567	{Value: &Plain{uintptr(0xFFDD)}, ExpectXML: `<Plain><V>65501</V></Plain>`},
568	{Value: &Plain{"gopher"}, ExpectXML: `<Plain><V>gopher</V></Plain>`},
569	{Value: &Plain{[]byte("gopher")}, ExpectXML: `<Plain><V>gopher</V></Plain>`},
570	{Value: &Plain{"</>"}, ExpectXML: `<Plain><V>&lt;/&gt;</V></Plain>`},
571	{Value: &Plain{[]byte("</>")}, ExpectXML: `<Plain><V>&lt;/&gt;</V></Plain>`},
572	{Value: &Plain{[3]byte{'<', '/', '>'}}, ExpectXML: `<Plain><V>&lt;/&gt;</V></Plain>`},
573	{Value: &Plain{NamedType("potato")}, ExpectXML: `<Plain><V>potato</V></Plain>`},
574	{Value: &Plain{[]int{1, 2, 3}}, ExpectXML: `<Plain><V>1</V><V>2</V><V>3</V></Plain>`},
575	{Value: &Plain{[3]int{1, 2, 3}}, ExpectXML: `<Plain><V>1</V><V>2</V><V>3</V></Plain>`},
576	{Value: ifaceptr(true), MarshalOnly: true, ExpectXML: `<bool>true</bool>`},
577
578	// Test time.
579	{
580		Value:     &Plain{time.Unix(1e9, 123456789).UTC()},
581		ExpectXML: `<Plain><V>2001-09-09T01:46:40.123456789Z</V></Plain>`,
582	},
583
584	// A pointer to struct{} may be used to test for an element's presence.
585	{
586		Value:     &PresenceTest{new(struct{})},
587		ExpectXML: `<PresenceTest><Exists></Exists></PresenceTest>`,
588	},
589	{
590		Value:     &PresenceTest{},
591		ExpectXML: `<PresenceTest></PresenceTest>`,
592	},
593
594	// A []byte field is only nil if the element was not found.
595	{
596		Value:         &Data{},
597		ExpectXML:     `<Data></Data>`,
598		UnmarshalOnly: true,
599	},
600	{
601		Value:         &Data{Bytes: []byte{}, Custom: MyBytes{}, Attr: []byte{}},
602		ExpectXML:     `<Data Attr=""><Bytes></Bytes><Custom></Custom></Data>`,
603		UnmarshalOnly: true,
604	},
605
606	// Check that []byte works, including named []byte types.
607	{
608		Value:     &Data{Bytes: []byte("ab"), Custom: MyBytes("cd"), Attr: []byte{'v'}},
609		ExpectXML: `<Data Attr="v"><Bytes>ab</Bytes><Custom>cd</Custom></Data>`,
610	},
611
612	// Test innerxml
613	{
614		Value: &SecretAgent{
615			Handle:    "007",
616			Identity:  "James Bond",
617			Obfuscate: "<redacted/>",
618		},
619		ExpectXML:   `<agent handle="007"><Identity>James Bond</Identity><redacted/></agent>`,
620		MarshalOnly: true,
621	},
622	{
623		Value: &SecretAgent{
624			Handle:    "007",
625			Identity:  "James Bond",
626			Obfuscate: "<Identity>James Bond</Identity><redacted/>",
627		},
628		ExpectXML:     `<agent handle="007"><Identity>James Bond</Identity><redacted/></agent>`,
629		UnmarshalOnly: true,
630	},
631
632	// Test structs
633	{Value: &Port{Type: "ssl", Number: "443"}, ExpectXML: `<port type="ssl">443</port>`},
634	{Value: &Port{Number: "443"}, ExpectXML: `<port>443</port>`},
635	{Value: &Port{Type: "<unix>"}, ExpectXML: `<port type="&lt;unix&gt;"></port>`},
636	{Value: &Port{Number: "443", Comment: "https"}, ExpectXML: `<port><!--https-->443</port>`},
637	{Value: &Port{Number: "443", Comment: "add space-"}, ExpectXML: `<port><!--add space- -->443</port>`, MarshalOnly: true},
638	{Value: &Domain{Name: []byte("google.com&friends")}, ExpectXML: `<domain>google.com&amp;friends</domain>`},
639	{Value: &Domain{Name: []byte("google.com"), Comment: []byte(" &friends ")}, ExpectXML: `<domain>google.com<!-- &friends --></domain>`},
640	{Value: &Book{Title: "Pride & Prejudice"}, ExpectXML: `<book>Pride &amp; Prejudice</book>`},
641	{Value: &Event{Year: -3114}, ExpectXML: `<event>-3114</event>`},
642	{Value: &Movie{Length: 13440}, ExpectXML: `<movie>13440</movie>`},
643	{Value: &Pi{Approximation: 3.14159265}, ExpectXML: `<pi>3.1415927</pi>`},
644	{Value: &Universe{Visible: 9.3e13}, ExpectXML: `<universe>9.3e+13</universe>`},
645	{Value: &Particle{HasMass: true}, ExpectXML: `<particle>true</particle>`},
646	{Value: &Departure{When: ParseTime("2013-01-09T00:15:00-09:00")}, ExpectXML: `<departure>2013-01-09T00:15:00-09:00</departure>`},
647	{Value: atomValue, ExpectXML: atomXML},
648	{Value: &Generic[int]{1}, ExpectXML: `<Generic><X>1</X></Generic>`},
649	{
650		Value: &Ship{
651			Name:  "Heart of Gold",
652			Pilot: "Computer",
653			Age:   1,
654			Drive: ImprobabilityDrive,
655			Passenger: []*Passenger{
656				{
657					Name:   []string{"Zaphod", "Beeblebrox"},
658					Weight: 7.25,
659				},
660				{
661					Name:   []string{"Trisha", "McMillen"},
662					Weight: 5.5,
663				},
664				{
665					Name:   []string{"Ford", "Prefect"},
666					Weight: 7,
667				},
668				{
669					Name:   []string{"Arthur", "Dent"},
670					Weight: 6.75,
671				},
672			},
673		},
674		ExpectXML: `<spaceship name="Heart of Gold" pilot="Computer">` +
675			`<drive>` + strconv.Itoa(int(ImprobabilityDrive)) + `</drive>` +
676			`<age>1</age>` +
677			`<passenger>` +
678			`<name>Zaphod</name>` +
679			`<name>Beeblebrox</name>` +
680			`<weight>7.25</weight>` +
681			`</passenger>` +
682			`<passenger>` +
683			`<name>Trisha</name>` +
684			`<name>McMillen</name>` +
685			`<weight>5.5</weight>` +
686			`</passenger>` +
687			`<passenger>` +
688			`<name>Ford</name>` +
689			`<name>Prefect</name>` +
690			`<weight>7</weight>` +
691			`</passenger>` +
692			`<passenger>` +
693			`<name>Arthur</name>` +
694			`<name>Dent</name>` +
695			`<weight>6.75</weight>` +
696			`</passenger>` +
697			`</spaceship>`,
698	},
699
700	// Test a>b
701	{
702		Value: &NestedItems{Items: nil, Item1: nil},
703		ExpectXML: `<result>` +
704			`<Items>` +
705			`</Items>` +
706			`</result>`,
707	},
708	{
709		Value: &NestedItems{Items: []string{}, Item1: []string{}},
710		ExpectXML: `<result>` +
711			`<Items>` +
712			`</Items>` +
713			`</result>`,
714		MarshalOnly: true,
715	},
716	{
717		Value: &NestedItems{Items: nil, Item1: []string{"A"}},
718		ExpectXML: `<result>` +
719			`<Items>` +
720			`<item1>A</item1>` +
721			`</Items>` +
722			`</result>`,
723	},
724	{
725		Value: &NestedItems{Items: []string{"A", "B"}, Item1: nil},
726		ExpectXML: `<result>` +
727			`<Items>` +
728			`<item>A</item>` +
729			`<item>B</item>` +
730			`</Items>` +
731			`</result>`,
732	},
733	{
734		Value: &NestedItems{Items: []string{"A", "B"}, Item1: []string{"C"}},
735		ExpectXML: `<result>` +
736			`<Items>` +
737			`<item>A</item>` +
738			`<item>B</item>` +
739			`<item1>C</item1>` +
740			`</Items>` +
741			`</result>`,
742	},
743	{
744		Value: &NestedOrder{Field1: "C", Field2: "B", Field3: "A"},
745		ExpectXML: `<result>` +
746			`<parent>` +
747			`<c>C</c>` +
748			`<b>B</b>` +
749			`<a>A</a>` +
750			`</parent>` +
751			`</result>`,
752	},
753	{
754		Value: &NilTest{A: "A", B: nil, C: "C"},
755		ExpectXML: `<NilTest>` +
756			`<parent1>` +
757			`<parent2><a>A</a></parent2>` +
758			`<parent2><c>C</c></parent2>` +
759			`</parent1>` +
760			`</NilTest>`,
761		MarshalOnly: true, // Uses interface{}
762	},
763	{
764		Value: &MixedNested{A: "A", B: "B", C: "C", D: "D"},
765		ExpectXML: `<result>` +
766			`<parent1><a>A</a></parent1>` +
767			`<b>B</b>` +
768			`<parent1>` +
769			`<parent2><c>C</c></parent2>` +
770			`<d>D</d>` +
771			`</parent1>` +
772			`</result>`,
773	},
774	{
775		Value:     &Service{Port: &Port{Number: "80"}},
776		ExpectXML: `<service><host><port>80</port></host></service>`,
777	},
778	{
779		Value:     &Service{},
780		ExpectXML: `<service></service>`,
781	},
782	{
783		Value: &Service{Port: &Port{Number: "80"}, Extra1: "A", Extra2: "B"},
784		ExpectXML: `<service>` +
785			`<host><port>80</port></host>` +
786			`<Extra1>A</Extra1>` +
787			`<host><extra2>B</extra2></host>` +
788			`</service>`,
789		MarshalOnly: true,
790	},
791	{
792		Value: &Service{Port: &Port{Number: "80"}, Extra2: "example"},
793		ExpectXML: `<service>` +
794			`<host><port>80</port></host>` +
795			`<host><extra2>example</extra2></host>` +
796			`</service>`,
797		MarshalOnly: true,
798	},
799	{
800		Value: &struct {
801			XMLName struct{} `xml:"space top"`
802			A       string   `xml:"x>a"`
803			B       string   `xml:"x>b"`
804			C       string   `xml:"space x>c"`
805			C1      string   `xml:"space1 x>c"`
806			D1      string   `xml:"space1 x>d"`
807		}{
808			A:  "a",
809			B:  "b",
810			C:  "c",
811			C1: "c1",
812			D1: "d1",
813		},
814		ExpectXML: `<top xmlns="space">` +
815			`<x><a>a</a><b>b</b><c xmlns="space">c</c>` +
816			`<c xmlns="space1">c1</c>` +
817			`<d xmlns="space1">d1</d>` +
818			`</x>` +
819			`</top>`,
820	},
821	{
822		Value: &struct {
823			XMLName Name
824			A       string `xml:"x>a"`
825			B       string `xml:"x>b"`
826			C       string `xml:"space x>c"`
827			C1      string `xml:"space1 x>c"`
828			D1      string `xml:"space1 x>d"`
829		}{
830			XMLName: Name{
831				Space: "space0",
832				Local: "top",
833			},
834			A:  "a",
835			B:  "b",
836			C:  "c",
837			C1: "c1",
838			D1: "d1",
839		},
840		ExpectXML: `<top xmlns="space0">` +
841			`<x><a>a</a><b>b</b>` +
842			`<c xmlns="space">c</c>` +
843			`<c xmlns="space1">c1</c>` +
844			`<d xmlns="space1">d1</d>` +
845			`</x>` +
846			`</top>`,
847	},
848	{
849		Value: &struct {
850			XMLName struct{} `xml:"top"`
851			B       string   `xml:"space x>b"`
852			B1      string   `xml:"space1 x>b"`
853		}{
854			B:  "b",
855			B1: "b1",
856		},
857		ExpectXML: `<top>` +
858			`<x><b xmlns="space">b</b>` +
859			`<b xmlns="space1">b1</b></x>` +
860			`</top>`,
861	},
862
863	// Test struct embedding
864	{
865		Value: &EmbedA{
866			EmbedC: EmbedC{
867				FieldA1: "", // Shadowed by A.A
868				FieldA2: "", // Shadowed by A.A
869				FieldB:  "A.C.B",
870				FieldC:  "A.C.C",
871			},
872			EmbedB: EmbedB{
873				FieldB: "A.B.B",
874				EmbedC: &EmbedC{
875					FieldA1: "A.B.C.A1",
876					FieldA2: "A.B.C.A2",
877					FieldB:  "", // Shadowed by A.B.B
878					FieldC:  "A.B.C.C",
879				},
880			},
881			FieldA: "A.A",
882			embedD: embedD{
883				FieldE: "A.D.E",
884			},
885		},
886		ExpectXML: `<EmbedA>` +
887			`<FieldB>A.C.B</FieldB>` +
888			`<FieldC>A.C.C</FieldC>` +
889			`<EmbedB>` +
890			`<FieldB>A.B.B</FieldB>` +
891			`<FieldA>` +
892			`<A1>A.B.C.A1</A1>` +
893			`<A2>A.B.C.A2</A2>` +
894			`</FieldA>` +
895			`<FieldC>A.B.C.C</FieldC>` +
896			`</EmbedB>` +
897			`<FieldA>A.A</FieldA>` +
898			`<FieldE>A.D.E</FieldE>` +
899			`</EmbedA>`,
900	},
901
902	// Anonymous struct pointer field which is nil
903	{
904		Value:     &EmbedB{},
905		ExpectXML: `<EmbedB><FieldB></FieldB></EmbedB>`,
906	},
907
908	// Other kinds of nil anonymous fields
909	{
910		Value:     &PointerAnonFields{},
911		ExpectXML: `<PointerAnonFields></PointerAnonFields>`,
912	},
913
914	// Test that name casing matters
915	{
916		Value:     &NameCasing{Xy: "mixed", XY: "upper", XyA: "mixedA", XYA: "upperA"},
917		ExpectXML: `<casing Xy="mixedA" XY="upperA"><Xy>mixed</Xy><XY>upper</XY></casing>`,
918	},
919
920	// Test the order in which the XML element name is chosen
921	{
922		Value: &NamePrecedence{
923			FromTag:     XMLNameWithoutTag{Value: "A"},
924			FromNameVal: XMLNameWithoutTag{XMLName: Name{Local: "InXMLName"}, Value: "B"},
925			FromNameTag: XMLNameWithTag{Value: "C"},
926			InFieldName: "D",
927		},
928		ExpectXML: `<Parent>` +
929			`<InTag>A</InTag>` +
930			`<InXMLName>B</InXMLName>` +
931			`<InXMLNameTag>C</InXMLNameTag>` +
932			`<InFieldName>D</InFieldName>` +
933			`</Parent>`,
934		MarshalOnly: true,
935	},
936	{
937		Value: &NamePrecedence{
938			XMLName:     Name{Local: "Parent"},
939			FromTag:     XMLNameWithoutTag{XMLName: Name{Local: "InTag"}, Value: "A"},
940			FromNameVal: XMLNameWithoutTag{XMLName: Name{Local: "FromNameVal"}, Value: "B"},
941			FromNameTag: XMLNameWithTag{XMLName: Name{Local: "InXMLNameTag"}, Value: "C"},
942			InFieldName: "D",
943		},
944		ExpectXML: `<Parent>` +
945			`<InTag>A</InTag>` +
946			`<FromNameVal>B</FromNameVal>` +
947			`<InXMLNameTag>C</InXMLNameTag>` +
948			`<InFieldName>D</InFieldName>` +
949			`</Parent>`,
950		UnmarshalOnly: true,
951	},
952
953	// xml.Name works in a plain field as well.
954	{
955		Value:     &NameInField{Name{Space: "ns", Local: "foo"}},
956		ExpectXML: `<NameInField><foo xmlns="ns"></foo></NameInField>`,
957	},
958	{
959		Value:         &NameInField{Name{Space: "ns", Local: "foo"}},
960		ExpectXML:     `<NameInField><foo xmlns="ns"><ignore></ignore></foo></NameInField>`,
961		UnmarshalOnly: true,
962	},
963
964	// Marshaling zero xml.Name uses the tag or field name.
965	{
966		Value:       &NameInField{},
967		ExpectXML:   `<NameInField><foo xmlns="ns"></foo></NameInField>`,
968		MarshalOnly: true,
969	},
970
971	// Test attributes
972	{
973		Value: &AttrTest{
974			Int:   8,
975			Named: 9,
976			Float: 23.5,
977			Uint8: 255,
978			Bool:  true,
979			Str:   "str",
980			Bytes: []byte("byt"),
981		},
982		ExpectXML: `<AttrTest Int="8" int="9" Float="23.5" Uint8="255"` +
983			` Bool="true" Str="str" Bytes="byt"></AttrTest>`,
984	},
985	{
986		Value: &AttrTest{Bytes: []byte{}},
987		ExpectXML: `<AttrTest Int="0" int="0" Float="0" Uint8="0"` +
988			` Bool="false" Str="" Bytes=""></AttrTest>`,
989	},
990	{
991		Value: &AttrsTest{
992			Attrs: []Attr{
993				{Name: Name{Local: "Answer"}, Value: "42"},
994				{Name: Name{Local: "Int"}, Value: "8"},
995				{Name: Name{Local: "int"}, Value: "9"},
996				{Name: Name{Local: "Float"}, Value: "23.5"},
997				{Name: Name{Local: "Uint8"}, Value: "255"},
998				{Name: Name{Local: "Bool"}, Value: "true"},
999				{Name: Name{Local: "Str"}, Value: "str"},
1000				{Name: Name{Local: "Bytes"}, Value: "byt"},
1001			},
1002		},
1003		ExpectXML:   `<AttrsTest Answer="42" Int="8" int="9" Float="23.5" Uint8="255" Bool="true" Str="str" Bytes="byt" Int="0" int="0" Float="0" Uint8="0" Bool="false" Str="" Bytes=""></AttrsTest>`,
1004		MarshalOnly: true,
1005	},
1006	{
1007		Value: &AttrsTest{
1008			Attrs: []Attr{
1009				{Name: Name{Local: "Answer"}, Value: "42"},
1010			},
1011			Int:   8,
1012			Named: 9,
1013			Float: 23.5,
1014			Uint8: 255,
1015			Bool:  true,
1016			Str:   "str",
1017			Bytes: []byte("byt"),
1018		},
1019		ExpectXML: `<AttrsTest Answer="42" Int="8" int="9" Float="23.5" Uint8="255" Bool="true" Str="str" Bytes="byt"></AttrsTest>`,
1020	},
1021	{
1022		Value: &AttrsTest{
1023			Attrs: []Attr{
1024				{Name: Name{Local: "Int"}, Value: "0"},
1025				{Name: Name{Local: "int"}, Value: "0"},
1026				{Name: Name{Local: "Float"}, Value: "0"},
1027				{Name: Name{Local: "Uint8"}, Value: "0"},
1028				{Name: Name{Local: "Bool"}, Value: "false"},
1029				{Name: Name{Local: "Str"}},
1030				{Name: Name{Local: "Bytes"}},
1031			},
1032			Bytes: []byte{},
1033		},
1034		ExpectXML:   `<AttrsTest Int="0" int="0" Float="0" Uint8="0" Bool="false" Str="" Bytes="" Int="0" int="0" Float="0" Uint8="0" Bool="false" Str="" Bytes=""></AttrsTest>`,
1035		MarshalOnly: true,
1036	},
1037	{
1038		Value: &OmitAttrTest{
1039			Int:   8,
1040			Named: 9,
1041			Float: 23.5,
1042			Uint8: 255,
1043			Bool:  true,
1044			Str:   "str",
1045			Bytes: []byte("byt"),
1046			PStr:  &empty,
1047		},
1048		ExpectXML: `<OmitAttrTest Int="8" int="9" Float="23.5" Uint8="255"` +
1049			` Bool="true" Str="str" Bytes="byt" PStr=""></OmitAttrTest>`,
1050	},
1051	{
1052		Value:     &OmitAttrTest{},
1053		ExpectXML: `<OmitAttrTest></OmitAttrTest>`,
1054	},
1055
1056	// pointer fields
1057	{
1058		Value:       &PointerFieldsTest{Name: &nameAttr, Age: &ageAttr, Contents: &contentsAttr},
1059		ExpectXML:   `<dummy name="Sarah" age="12">lorem ipsum</dummy>`,
1060		MarshalOnly: true,
1061	},
1062
1063	// empty chardata pointer field
1064	{
1065		Value:       &ChardataEmptyTest{},
1066		ExpectXML:   `<test></test>`,
1067		MarshalOnly: true,
1068	},
1069
1070	// omitempty on fields
1071	{
1072		Value: &OmitFieldTest{
1073			Int:   8,
1074			Named: 9,
1075			Float: 23.5,
1076			Uint8: 255,
1077			Bool:  true,
1078			Str:   "str",
1079			Bytes: []byte("byt"),
1080			PStr:  &empty,
1081			Ptr:   &PresenceTest{},
1082		},
1083		ExpectXML: `<OmitFieldTest>` +
1084			`<Int>8</Int>` +
1085			`<int>9</int>` +
1086			`<Float>23.5</Float>` +
1087			`<Uint8>255</Uint8>` +
1088			`<Bool>true</Bool>` +
1089			`<Str>str</Str>` +
1090			`<Bytes>byt</Bytes>` +
1091			`<PStr></PStr>` +
1092			`<Ptr></Ptr>` +
1093			`</OmitFieldTest>`,
1094	},
1095	{
1096		Value:     &OmitFieldTest{},
1097		ExpectXML: `<OmitFieldTest></OmitFieldTest>`,
1098	},
1099
1100	// Test ",any"
1101	{
1102		ExpectXML: `<a><nested><value>known</value></nested><other><sub>unknown</sub></other></a>`,
1103		Value: &AnyTest{
1104			Nested: "known",
1105			AnyField: AnyHolder{
1106				XMLName: Name{Local: "other"},
1107				XML:     "<sub>unknown</sub>",
1108			},
1109		},
1110	},
1111	{
1112		Value: &AnyTest{Nested: "known",
1113			AnyField: AnyHolder{
1114				XML:     "<unknown/>",
1115				XMLName: Name{Local: "AnyField"},
1116			},
1117		},
1118		ExpectXML: `<a><nested><value>known</value></nested><AnyField><unknown/></AnyField></a>`,
1119	},
1120	{
1121		ExpectXML: `<a><nested><value>b</value></nested></a>`,
1122		Value: &AnyOmitTest{
1123			Nested: "b",
1124		},
1125	},
1126	{
1127		ExpectXML: `<a><nested><value>b</value></nested><c><d>e</d></c><g xmlns="f"><h>i</h></g></a>`,
1128		Value: &AnySliceTest{
1129			Nested: "b",
1130			AnyField: []AnyHolder{
1131				{
1132					XMLName: Name{Local: "c"},
1133					XML:     "<d>e</d>",
1134				},
1135				{
1136					XMLName: Name{Space: "f", Local: "g"},
1137					XML:     "<h>i</h>",
1138				},
1139			},
1140		},
1141	},
1142	{
1143		ExpectXML: `<a><nested><value>b</value></nested></a>`,
1144		Value: &AnySliceTest{
1145			Nested: "b",
1146		},
1147	},
1148
1149	// Test recursive types.
1150	{
1151		Value: &RecurseA{
1152			A: "a1",
1153			B: &RecurseB{
1154				A: &RecurseA{"a2", nil},
1155				B: "b1",
1156			},
1157		},
1158		ExpectXML: `<RecurseA><A>a1</A><B><A><A>a2</A></A><B>b1</B></B></RecurseA>`,
1159	},
1160
1161	// Test ignoring fields via "-" tag
1162	{
1163		ExpectXML: `<IgnoreTest></IgnoreTest>`,
1164		Value:     &IgnoreTest{},
1165	},
1166	{
1167		ExpectXML:   `<IgnoreTest></IgnoreTest>`,
1168		Value:       &IgnoreTest{PublicSecret: "can't tell"},
1169		MarshalOnly: true,
1170	},
1171	{
1172		ExpectXML:     `<IgnoreTest><PublicSecret>ignore me</PublicSecret></IgnoreTest>`,
1173		Value:         &IgnoreTest{},
1174		UnmarshalOnly: true,
1175	},
1176
1177	// Test escaping.
1178	{
1179		ExpectXML: `<a><nested><value>dquote: &#34;; squote: &#39;; ampersand: &amp;; less: &lt;; greater: &gt;;</value></nested><empty></empty></a>`,
1180		Value: &AnyTest{
1181			Nested:   `dquote: "; squote: '; ampersand: &; less: <; greater: >;`,
1182			AnyField: AnyHolder{XMLName: Name{Local: "empty"}},
1183		},
1184	},
1185	{
1186		ExpectXML: `<a><nested><value>newline: &#xA;; cr: &#xD;; tab: &#x9;;</value></nested><AnyField></AnyField></a>`,
1187		Value: &AnyTest{
1188			Nested:   "newline: \n; cr: \r; tab: \t;",
1189			AnyField: AnyHolder{XMLName: Name{Local: "AnyField"}},
1190		},
1191	},
1192	{
1193		ExpectXML: "<a><nested><value>1\r2\r\n3\n\r4\n5</value></nested></a>",
1194		Value: &AnyTest{
1195			Nested: "1\n2\n3\n\n4\n5",
1196		},
1197		UnmarshalOnly: true,
1198	},
1199	{
1200		ExpectXML: `<EmbedInt><MyInt>42</MyInt></EmbedInt>`,
1201		Value: &EmbedInt{
1202			MyInt: 42,
1203		},
1204	},
1205	// Test outputting CDATA-wrapped text.
1206	{
1207		ExpectXML: `<CDataTest></CDataTest>`,
1208		Value:     &CDataTest{},
1209	},
1210	{
1211		ExpectXML: `<CDataTest><![CDATA[http://example.com/tests/1?foo=1&bar=baz]]></CDataTest>`,
1212		Value: &CDataTest{
1213			Chardata: "http://example.com/tests/1?foo=1&bar=baz",
1214		},
1215	},
1216	{
1217		ExpectXML: `<CDataTest><![CDATA[Literal <![CDATA[Nested]]]]><![CDATA[>!]]></CDataTest>`,
1218		Value: &CDataTest{
1219			Chardata: "Literal <![CDATA[Nested]]>!",
1220		},
1221	},
1222	{
1223		ExpectXML: `<CDataTest><![CDATA[<![CDATA[Nested]]]]><![CDATA[> Literal!]]></CDataTest>`,
1224		Value: &CDataTest{
1225			Chardata: "<![CDATA[Nested]]> Literal!",
1226		},
1227	},
1228	{
1229		ExpectXML: `<CDataTest><![CDATA[<![CDATA[Nested]]]]><![CDATA[> Literal! <![CDATA[Nested]]]]><![CDATA[> Literal!]]></CDataTest>`,
1230		Value: &CDataTest{
1231			Chardata: "<![CDATA[Nested]]> Literal! <![CDATA[Nested]]> Literal!",
1232		},
1233	},
1234	{
1235		ExpectXML: `<CDataTest><![CDATA[<![CDATA[<![CDATA[Nested]]]]><![CDATA[>]]]]><![CDATA[>]]></CDataTest>`,
1236		Value: &CDataTest{
1237			Chardata: "<![CDATA[<![CDATA[Nested]]>]]>",
1238		},
1239	},
1240
1241	// Test omitempty with parent chain; see golang.org/issue/4168.
1242	{
1243		ExpectXML: `<Strings><A></A></Strings>`,
1244		Value:     &Strings{},
1245	},
1246	// Custom marshalers.
1247	{
1248		ExpectXML: `<MyMarshalerTest>hello world</MyMarshalerTest>`,
1249		Value:     &MyMarshalerTest{},
1250	},
1251	{
1252		ExpectXML: `<MarshalerStruct Foo="hello world"></MarshalerStruct>`,
1253		Value:     &MarshalerStruct{},
1254	},
1255	{
1256		ExpectXML: `<outer xmlns="testns" int="10"></outer>`,
1257		Value:     &OuterStruct{IntAttr: 10},
1258	},
1259	{
1260		ExpectXML: `<test xmlns="outerns" int="10"></test>`,
1261		Value:     &OuterNamedStruct{XMLName: Name{Space: "outerns", Local: "test"}, IntAttr: 10},
1262	},
1263	{
1264		ExpectXML: `<test xmlns="outerns" int="10"></test>`,
1265		Value:     &OuterNamedOrderedStruct{XMLName: Name{Space: "outerns", Local: "test"}, IntAttr: 10},
1266	},
1267	{
1268		ExpectXML: `<outer xmlns="testns" int="10"></outer>`,
1269		Value:     &OuterOuterStruct{OuterStruct{IntAttr: 10}},
1270	},
1271	{
1272		ExpectXML: `<NestedAndChardata><A><B></B><B></B></A>test</NestedAndChardata>`,
1273		Value:     &NestedAndChardata{AB: make([]string, 2), Chardata: "test"},
1274	},
1275	{
1276		ExpectXML: `<NestedAndComment><A><B></B><B></B></A><!--test--></NestedAndComment>`,
1277		Value:     &NestedAndComment{AB: make([]string, 2), Comment: "test"},
1278	},
1279	{
1280		ExpectXML: `<NestedAndCData><A><B></B><B></B></A><![CDATA[test]]></NestedAndCData>`,
1281		Value:     &NestedAndCData{AB: make([]string, 2), CDATA: "test"},
1282	},
1283	// Test pointer indirection in various kinds of fields.
1284	// https://golang.org/issue/19063
1285	{
1286		ExpectXML:   `<IndirComment><T1></T1><!--hi--><T2></T2></IndirComment>`,
1287		Value:       &IndirComment{Comment: stringptr("hi")},
1288		MarshalOnly: true,
1289	},
1290	{
1291		ExpectXML:   `<IndirComment><T1></T1><T2></T2></IndirComment>`,
1292		Value:       &IndirComment{Comment: stringptr("")},
1293		MarshalOnly: true,
1294	},
1295	{
1296		ExpectXML:    `<IndirComment><T1></T1><T2></T2></IndirComment>`,
1297		Value:        &IndirComment{Comment: nil},
1298		MarshalError: "xml: bad type for comment field of xml.IndirComment",
1299	},
1300	{
1301		ExpectXML:     `<IndirComment><T1></T1><!--hi--><T2></T2></IndirComment>`,
1302		Value:         &IndirComment{Comment: nil},
1303		UnmarshalOnly: true,
1304	},
1305	{
1306		ExpectXML:   `<IfaceComment><T1></T1><!--hi--><T2></T2></IfaceComment>`,
1307		Value:       &IfaceComment{Comment: "hi"},
1308		MarshalOnly: true,
1309	},
1310	{
1311		ExpectXML:     `<IfaceComment><T1></T1><!--hi--><T2></T2></IfaceComment>`,
1312		Value:         &IfaceComment{Comment: nil},
1313		UnmarshalOnly: true,
1314	},
1315	{
1316		ExpectXML:    `<IfaceComment><T1></T1><T2></T2></IfaceComment>`,
1317		Value:        &IfaceComment{Comment: nil},
1318		MarshalError: "xml: bad type for comment field of xml.IfaceComment",
1319	},
1320	{
1321		ExpectXML:     `<IfaceComment><T1></T1><T2></T2></IfaceComment>`,
1322		Value:         &IfaceComment{Comment: nil},
1323		UnmarshalOnly: true,
1324	},
1325	{
1326		ExpectXML: `<DirectComment><T1></T1><!--hi--><T2></T2></DirectComment>`,
1327		Value:     &DirectComment{Comment: string("hi")},
1328	},
1329	{
1330		ExpectXML: `<DirectComment><T1></T1><T2></T2></DirectComment>`,
1331		Value:     &DirectComment{Comment: string("")},
1332	},
1333	{
1334		ExpectXML: `<IndirChardata><T1></T1>hi<T2></T2></IndirChardata>`,
1335		Value:     &IndirChardata{Chardata: stringptr("hi")},
1336	},
1337	{
1338		ExpectXML:     `<IndirChardata><T1></T1><![CDATA[hi]]><T2></T2></IndirChardata>`,
1339		Value:         &IndirChardata{Chardata: stringptr("hi")},
1340		UnmarshalOnly: true, // marshals without CDATA
1341	},
1342	{
1343		ExpectXML: `<IndirChardata><T1></T1><T2></T2></IndirChardata>`,
1344		Value:     &IndirChardata{Chardata: stringptr("")},
1345	},
1346	{
1347		ExpectXML:   `<IndirChardata><T1></T1><T2></T2></IndirChardata>`,
1348		Value:       &IndirChardata{Chardata: nil},
1349		MarshalOnly: true, // unmarshal leaves Chardata=stringptr("")
1350	},
1351	{
1352		ExpectXML:      `<IfaceChardata><T1></T1>hi<T2></T2></IfaceChardata>`,
1353		Value:          &IfaceChardata{Chardata: string("hi")},
1354		UnmarshalError: "cannot unmarshal into interface {}",
1355	},
1356	{
1357		ExpectXML:      `<IfaceChardata><T1></T1><![CDATA[hi]]><T2></T2></IfaceChardata>`,
1358		Value:          &IfaceChardata{Chardata: string("hi")},
1359		UnmarshalOnly:  true, // marshals without CDATA
1360		UnmarshalError: "cannot unmarshal into interface {}",
1361	},
1362	{
1363		ExpectXML:      `<IfaceChardata><T1></T1><T2></T2></IfaceChardata>`,
1364		Value:          &IfaceChardata{Chardata: string("")},
1365		UnmarshalError: "cannot unmarshal into interface {}",
1366	},
1367	{
1368		ExpectXML:      `<IfaceChardata><T1></T1><T2></T2></IfaceChardata>`,
1369		Value:          &IfaceChardata{Chardata: nil},
1370		UnmarshalError: "cannot unmarshal into interface {}",
1371	},
1372	{
1373		ExpectXML: `<DirectChardata><T1></T1>hi<T2></T2></DirectChardata>`,
1374		Value:     &DirectChardata{Chardata: string("hi")},
1375	},
1376	{
1377		ExpectXML:     `<DirectChardata><T1></T1><![CDATA[hi]]><T2></T2></DirectChardata>`,
1378		Value:         &DirectChardata{Chardata: string("hi")},
1379		UnmarshalOnly: true, // marshals without CDATA
1380	},
1381	{
1382		ExpectXML: `<DirectChardata><T1></T1><T2></T2></DirectChardata>`,
1383		Value:     &DirectChardata{Chardata: string("")},
1384	},
1385	{
1386		ExpectXML: `<IndirCDATA><T1></T1><![CDATA[hi]]><T2></T2></IndirCDATA>`,
1387		Value:     &IndirCDATA{CDATA: stringptr("hi")},
1388	},
1389	{
1390		ExpectXML:     `<IndirCDATA><T1></T1>hi<T2></T2></IndirCDATA>`,
1391		Value:         &IndirCDATA{CDATA: stringptr("hi")},
1392		UnmarshalOnly: true, // marshals with CDATA
1393	},
1394	{
1395		ExpectXML: `<IndirCDATA><T1></T1><T2></T2></IndirCDATA>`,
1396		Value:     &IndirCDATA{CDATA: stringptr("")},
1397	},
1398	{
1399		ExpectXML:   `<IndirCDATA><T1></T1><T2></T2></IndirCDATA>`,
1400		Value:       &IndirCDATA{CDATA: nil},
1401		MarshalOnly: true, // unmarshal leaves CDATA=stringptr("")
1402	},
1403	{
1404		ExpectXML:      `<IfaceCDATA><T1></T1><![CDATA[hi]]><T2></T2></IfaceCDATA>`,
1405		Value:          &IfaceCDATA{CDATA: string("hi")},
1406		UnmarshalError: "cannot unmarshal into interface {}",
1407	},
1408	{
1409		ExpectXML:      `<IfaceCDATA><T1></T1>hi<T2></T2></IfaceCDATA>`,
1410		Value:          &IfaceCDATA{CDATA: string("hi")},
1411		UnmarshalOnly:  true, // marshals with CDATA
1412		UnmarshalError: "cannot unmarshal into interface {}",
1413	},
1414	{
1415		ExpectXML:      `<IfaceCDATA><T1></T1><T2></T2></IfaceCDATA>`,
1416		Value:          &IfaceCDATA{CDATA: string("")},
1417		UnmarshalError: "cannot unmarshal into interface {}",
1418	},
1419	{
1420		ExpectXML:      `<IfaceCDATA><T1></T1><T2></T2></IfaceCDATA>`,
1421		Value:          &IfaceCDATA{CDATA: nil},
1422		UnmarshalError: "cannot unmarshal into interface {}",
1423	},
1424	{
1425		ExpectXML: `<DirectCDATA><T1></T1><![CDATA[hi]]><T2></T2></DirectCDATA>`,
1426		Value:     &DirectCDATA{CDATA: string("hi")},
1427	},
1428	{
1429		ExpectXML:     `<DirectCDATA><T1></T1>hi<T2></T2></DirectCDATA>`,
1430		Value:         &DirectCDATA{CDATA: string("hi")},
1431		UnmarshalOnly: true, // marshals with CDATA
1432	},
1433	{
1434		ExpectXML: `<DirectCDATA><T1></T1><T2></T2></DirectCDATA>`,
1435		Value:     &DirectCDATA{CDATA: string("")},
1436	},
1437	{
1438		ExpectXML:   `<IndirInnerXML><T1></T1><hi/><T2></T2></IndirInnerXML>`,
1439		Value:       &IndirInnerXML{InnerXML: stringptr("<hi/>")},
1440		MarshalOnly: true,
1441	},
1442	{
1443		ExpectXML:   `<IndirInnerXML><T1></T1><T2></T2></IndirInnerXML>`,
1444		Value:       &IndirInnerXML{InnerXML: stringptr("")},
1445		MarshalOnly: true,
1446	},
1447	{
1448		ExpectXML: `<IndirInnerXML><T1></T1><T2></T2></IndirInnerXML>`,
1449		Value:     &IndirInnerXML{InnerXML: nil},
1450	},
1451	{
1452		ExpectXML:     `<IndirInnerXML><T1></T1><hi/><T2></T2></IndirInnerXML>`,
1453		Value:         &IndirInnerXML{InnerXML: nil},
1454		UnmarshalOnly: true,
1455	},
1456	{
1457		ExpectXML:   `<IfaceInnerXML><T1></T1><hi/><T2></T2></IfaceInnerXML>`,
1458		Value:       &IfaceInnerXML{InnerXML: "<hi/>"},
1459		MarshalOnly: true,
1460	},
1461	{
1462		ExpectXML:     `<IfaceInnerXML><T1></T1><hi/><T2></T2></IfaceInnerXML>`,
1463		Value:         &IfaceInnerXML{InnerXML: nil},
1464		UnmarshalOnly: true,
1465	},
1466	{
1467		ExpectXML: `<IfaceInnerXML><T1></T1><T2></T2></IfaceInnerXML>`,
1468		Value:     &IfaceInnerXML{InnerXML: nil},
1469	},
1470	{
1471		ExpectXML:     `<IfaceInnerXML><T1></T1><T2></T2></IfaceInnerXML>`,
1472		Value:         &IfaceInnerXML{InnerXML: nil},
1473		UnmarshalOnly: true,
1474	},
1475	{
1476		ExpectXML:   `<DirectInnerXML><T1></T1><hi/><T2></T2></DirectInnerXML>`,
1477		Value:       &DirectInnerXML{InnerXML: string("<hi/>")},
1478		MarshalOnly: true,
1479	},
1480	{
1481		ExpectXML:     `<DirectInnerXML><T1></T1><hi/><T2></T2></DirectInnerXML>`,
1482		Value:         &DirectInnerXML{InnerXML: string("<T1></T1><hi/><T2></T2>")},
1483		UnmarshalOnly: true,
1484	},
1485	{
1486		ExpectXML:   `<DirectInnerXML><T1></T1><T2></T2></DirectInnerXML>`,
1487		Value:       &DirectInnerXML{InnerXML: string("")},
1488		MarshalOnly: true,
1489	},
1490	{
1491		ExpectXML:     `<DirectInnerXML><T1></T1><T2></T2></DirectInnerXML>`,
1492		Value:         &DirectInnerXML{InnerXML: string("<T1></T1><T2></T2>")},
1493		UnmarshalOnly: true,
1494	},
1495	{
1496		ExpectXML: `<IndirElement><T1></T1><Element>hi</Element><T2></T2></IndirElement>`,
1497		Value:     &IndirElement{Element: stringptr("hi")},
1498	},
1499	{
1500		ExpectXML: `<IndirElement><T1></T1><Element></Element><T2></T2></IndirElement>`,
1501		Value:     &IndirElement{Element: stringptr("")},
1502	},
1503	{
1504		ExpectXML: `<IndirElement><T1></T1><T2></T2></IndirElement>`,
1505		Value:     &IndirElement{Element: nil},
1506	},
1507	{
1508		ExpectXML:   `<IfaceElement><T1></T1><Element>hi</Element><T2></T2></IfaceElement>`,
1509		Value:       &IfaceElement{Element: "hi"},
1510		MarshalOnly: true,
1511	},
1512	{
1513		ExpectXML:     `<IfaceElement><T1></T1><Element>hi</Element><T2></T2></IfaceElement>`,
1514		Value:         &IfaceElement{Element: nil},
1515		UnmarshalOnly: true,
1516	},
1517	{
1518		ExpectXML: `<IfaceElement><T1></T1><T2></T2></IfaceElement>`,
1519		Value:     &IfaceElement{Element: nil},
1520	},
1521	{
1522		ExpectXML:     `<IfaceElement><T1></T1><T2></T2></IfaceElement>`,
1523		Value:         &IfaceElement{Element: nil},
1524		UnmarshalOnly: true,
1525	},
1526	{
1527		ExpectXML: `<DirectElement><T1></T1><Element>hi</Element><T2></T2></DirectElement>`,
1528		Value:     &DirectElement{Element: string("hi")},
1529	},
1530	{
1531		ExpectXML: `<DirectElement><T1></T1><Element></Element><T2></T2></DirectElement>`,
1532		Value:     &DirectElement{Element: string("")},
1533	},
1534	{
1535		ExpectXML: `<IndirOmitEmpty><T1></T1><OmitEmpty>hi</OmitEmpty><T2></T2></IndirOmitEmpty>`,
1536		Value:     &IndirOmitEmpty{OmitEmpty: stringptr("hi")},
1537	},
1538	{
1539		// Note: Changed in Go 1.8 to include <OmitEmpty> element (because x.OmitEmpty != nil).
1540		ExpectXML:   `<IndirOmitEmpty><T1></T1><OmitEmpty></OmitEmpty><T2></T2></IndirOmitEmpty>`,
1541		Value:       &IndirOmitEmpty{OmitEmpty: stringptr("")},
1542		MarshalOnly: true,
1543	},
1544	{
1545		ExpectXML:     `<IndirOmitEmpty><T1></T1><OmitEmpty></OmitEmpty><T2></T2></IndirOmitEmpty>`,
1546		Value:         &IndirOmitEmpty{OmitEmpty: stringptr("")},
1547		UnmarshalOnly: true,
1548	},
1549	{
1550		ExpectXML: `<IndirOmitEmpty><T1></T1><T2></T2></IndirOmitEmpty>`,
1551		Value:     &IndirOmitEmpty{OmitEmpty: nil},
1552	},
1553	{
1554		ExpectXML:   `<IfaceOmitEmpty><T1></T1><OmitEmpty>hi</OmitEmpty><T2></T2></IfaceOmitEmpty>`,
1555		Value:       &IfaceOmitEmpty{OmitEmpty: "hi"},
1556		MarshalOnly: true,
1557	},
1558	{
1559		ExpectXML:     `<IfaceOmitEmpty><T1></T1><OmitEmpty>hi</OmitEmpty><T2></T2></IfaceOmitEmpty>`,
1560		Value:         &IfaceOmitEmpty{OmitEmpty: nil},
1561		UnmarshalOnly: true,
1562	},
1563	{
1564		ExpectXML: `<IfaceOmitEmpty><T1></T1><T2></T2></IfaceOmitEmpty>`,
1565		Value:     &IfaceOmitEmpty{OmitEmpty: nil},
1566	},
1567	{
1568		ExpectXML:     `<IfaceOmitEmpty><T1></T1><T2></T2></IfaceOmitEmpty>`,
1569		Value:         &IfaceOmitEmpty{OmitEmpty: nil},
1570		UnmarshalOnly: true,
1571	},
1572	{
1573		ExpectXML: `<DirectOmitEmpty><T1></T1><OmitEmpty>hi</OmitEmpty><T2></T2></DirectOmitEmpty>`,
1574		Value:     &DirectOmitEmpty{OmitEmpty: string("hi")},
1575	},
1576	{
1577		ExpectXML: `<DirectOmitEmpty><T1></T1><T2></T2></DirectOmitEmpty>`,
1578		Value:     &DirectOmitEmpty{OmitEmpty: string("")},
1579	},
1580	{
1581		ExpectXML: `<IndirAny><T1></T1><Any>hi</Any><T2></T2></IndirAny>`,
1582		Value:     &IndirAny{Any: stringptr("hi")},
1583	},
1584	{
1585		ExpectXML: `<IndirAny><T1></T1><Any></Any><T2></T2></IndirAny>`,
1586		Value:     &IndirAny{Any: stringptr("")},
1587	},
1588	{
1589		ExpectXML: `<IndirAny><T1></T1><T2></T2></IndirAny>`,
1590		Value:     &IndirAny{Any: nil},
1591	},
1592	{
1593		ExpectXML:   `<IfaceAny><T1></T1><Any>hi</Any><T2></T2></IfaceAny>`,
1594		Value:       &IfaceAny{Any: "hi"},
1595		MarshalOnly: true,
1596	},
1597	{
1598		ExpectXML:     `<IfaceAny><T1></T1><Any>hi</Any><T2></T2></IfaceAny>`,
1599		Value:         &IfaceAny{Any: nil},
1600		UnmarshalOnly: true,
1601	},
1602	{
1603		ExpectXML: `<IfaceAny><T1></T1><T2></T2></IfaceAny>`,
1604		Value:     &IfaceAny{Any: nil},
1605	},
1606	{
1607		ExpectXML:     `<IfaceAny><T1></T1><T2></T2></IfaceAny>`,
1608		Value:         &IfaceAny{Any: nil},
1609		UnmarshalOnly: true,
1610	},
1611	{
1612		ExpectXML: `<DirectAny><T1></T1><Any>hi</Any><T2></T2></DirectAny>`,
1613		Value:     &DirectAny{Any: string("hi")},
1614	},
1615	{
1616		ExpectXML: `<DirectAny><T1></T1><Any></Any><T2></T2></DirectAny>`,
1617		Value:     &DirectAny{Any: string("")},
1618	},
1619	{
1620		ExpectXML:     `<IndirFoo><T1></T1><Foo>hi</Foo><T2></T2></IndirFoo>`,
1621		Value:         &IndirAny{Any: stringptr("hi")},
1622		UnmarshalOnly: true,
1623	},
1624	{
1625		ExpectXML:     `<IndirFoo><T1></T1><Foo></Foo><T2></T2></IndirFoo>`,
1626		Value:         &IndirAny{Any: stringptr("")},
1627		UnmarshalOnly: true,
1628	},
1629	{
1630		ExpectXML:     `<IndirFoo><T1></T1><T2></T2></IndirFoo>`,
1631		Value:         &IndirAny{Any: nil},
1632		UnmarshalOnly: true,
1633	},
1634	{
1635		ExpectXML:     `<IfaceFoo><T1></T1><Foo>hi</Foo><T2></T2></IfaceFoo>`,
1636		Value:         &IfaceAny{Any: nil},
1637		UnmarshalOnly: true,
1638	},
1639	{
1640		ExpectXML:     `<IfaceFoo><T1></T1><T2></T2></IfaceFoo>`,
1641		Value:         &IfaceAny{Any: nil},
1642		UnmarshalOnly: true,
1643	},
1644	{
1645		ExpectXML:     `<IfaceFoo><T1></T1><T2></T2></IfaceFoo>`,
1646		Value:         &IfaceAny{Any: nil},
1647		UnmarshalOnly: true,
1648	},
1649	{
1650		ExpectXML:     `<DirectFoo><T1></T1><Foo>hi</Foo><T2></T2></DirectFoo>`,
1651		Value:         &DirectAny{Any: string("hi")},
1652		UnmarshalOnly: true,
1653	},
1654	{
1655		ExpectXML:     `<DirectFoo><T1></T1><Foo></Foo><T2></T2></DirectFoo>`,
1656		Value:         &DirectAny{Any: string("")},
1657		UnmarshalOnly: true,
1658	},
1659}
1660
1661func TestMarshal(t *testing.T) {
1662	for idx, test := range marshalTests {
1663		if test.UnmarshalOnly {
1664			continue
1665		}
1666
1667		t.Run(fmt.Sprintf("%d", idx), func(t *testing.T) {
1668			data, err := Marshal(test.Value)
1669			if err != nil {
1670				if test.MarshalError == "" {
1671					t.Errorf("marshal(%#v): %s", test.Value, err)
1672					return
1673				}
1674				if !strings.Contains(err.Error(), test.MarshalError) {
1675					t.Errorf("marshal(%#v): %s, want %q", test.Value, err, test.MarshalError)
1676				}
1677				return
1678			}
1679			if test.MarshalError != "" {
1680				t.Errorf("Marshal succeeded, want error %q", test.MarshalError)
1681				return
1682			}
1683			if got, want := string(data), test.ExpectXML; got != want {
1684				if strings.Contains(want, "\n") {
1685					t.Errorf("marshal(%#v):\nHAVE:\n%s\nWANT:\n%s", test.Value, got, want)
1686				} else {
1687					t.Errorf("marshal(%#v):\nhave %#q\nwant %#q", test.Value, got, want)
1688				}
1689			}
1690		})
1691	}
1692}
1693
1694type AttrParent struct {
1695	X string `xml:"X>Y,attr"`
1696}
1697
1698type BadAttr struct {
1699	Name map[string]string `xml:"name,attr"`
1700}
1701
1702var marshalErrorTests = []struct {
1703	Value any
1704	Err   string
1705	Kind  reflect.Kind
1706}{
1707	{
1708		Value: make(chan bool),
1709		Err:   "xml: unsupported type: chan bool",
1710		Kind:  reflect.Chan,
1711	},
1712	{
1713		Value: map[string]string{
1714			"question": "What do you get when you multiply six by nine?",
1715			"answer":   "42",
1716		},
1717		Err:  "xml: unsupported type: map[string]string",
1718		Kind: reflect.Map,
1719	},
1720	{
1721		Value: map[*Ship]bool{nil: false},
1722		Err:   "xml: unsupported type: map[*xml.Ship]bool",
1723		Kind:  reflect.Map,
1724	},
1725	{
1726		Value: &Domain{Comment: []byte("f--bar")},
1727		Err:   `xml: comments must not contain "--"`,
1728	},
1729	// Reject parent chain with attr, never worked; see golang.org/issue/5033.
1730	{
1731		Value: &AttrParent{},
1732		Err:   `xml: X>Y chain not valid with attr flag`,
1733	},
1734	{
1735		Value: BadAttr{map[string]string{"X": "Y"}},
1736		Err:   `xml: unsupported type: map[string]string`,
1737	},
1738}
1739
1740var marshalIndentTests = []struct {
1741	Value     any
1742	Prefix    string
1743	Indent    string
1744	ExpectXML string
1745}{
1746	{
1747		Value: &SecretAgent{
1748			Handle:    "007",
1749			Identity:  "James Bond",
1750			Obfuscate: "<redacted/>",
1751		},
1752		Prefix:    "",
1753		Indent:    "\t",
1754		ExpectXML: "<agent handle=\"007\">\n\t<Identity>James Bond</Identity><redacted/>\n</agent>",
1755	},
1756}
1757
1758func TestMarshalErrors(t *testing.T) {
1759	for idx, test := range marshalErrorTests {
1760		data, err := Marshal(test.Value)
1761		if err == nil {
1762			t.Errorf("#%d: marshal(%#v) = [success] %q, want error %v", idx, test.Value, data, test.Err)
1763			continue
1764		}
1765		if err.Error() != test.Err {
1766			t.Errorf("#%d: marshal(%#v) = [error] %v, want %v", idx, test.Value, err, test.Err)
1767		}
1768		if test.Kind != reflect.Invalid {
1769			if kind := err.(*UnsupportedTypeError).Type.Kind(); kind != test.Kind {
1770				t.Errorf("#%d: marshal(%#v) = [error kind] %s, want %s", idx, test.Value, kind, test.Kind)
1771			}
1772		}
1773	}
1774}
1775
1776// Do invertibility testing on the various structures that we test
1777func TestUnmarshal(t *testing.T) {
1778	for i, test := range marshalTests {
1779		if test.MarshalOnly {
1780			continue
1781		}
1782		if _, ok := test.Value.(*Plain); ok {
1783			continue
1784		}
1785		if test.ExpectXML == `<top>`+
1786			`<x><b xmlns="space">b</b>`+
1787			`<b xmlns="space1">b1</b></x>`+
1788			`</top>` {
1789			// TODO(rogpeppe): re-enable this test in
1790			// https://go-review.googlesource.com/#/c/5910/
1791			continue
1792		}
1793
1794		vt := reflect.TypeOf(test.Value)
1795		dest := reflect.New(vt.Elem()).Interface()
1796		err := Unmarshal([]byte(test.ExpectXML), dest)
1797
1798		t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
1799			switch fix := dest.(type) {
1800			case *Feed:
1801				fix.Author.InnerXML = ""
1802				for i := range fix.Entry {
1803					fix.Entry[i].Author.InnerXML = ""
1804				}
1805			}
1806
1807			if err != nil {
1808				if test.UnmarshalError == "" {
1809					t.Errorf("unmarshal(%#v): %s", test.ExpectXML, err)
1810					return
1811				}
1812				if !strings.Contains(err.Error(), test.UnmarshalError) {
1813					t.Errorf("unmarshal(%#v): %s, want %q", test.ExpectXML, err, test.UnmarshalError)
1814				}
1815				return
1816			}
1817			if got, want := dest, test.Value; !reflect.DeepEqual(got, want) {
1818				t.Errorf("unmarshal(%q):\nhave %#v\nwant %#v", test.ExpectXML, got, want)
1819			}
1820		})
1821	}
1822}
1823
1824func TestMarshalIndent(t *testing.T) {
1825	for i, test := range marshalIndentTests {
1826		data, err := MarshalIndent(test.Value, test.Prefix, test.Indent)
1827		if err != nil {
1828			t.Errorf("#%d: Error: %s", i, err)
1829			continue
1830		}
1831		if got, want := string(data), test.ExpectXML; got != want {
1832			t.Errorf("#%d: MarshalIndent:\nGot:%s\nWant:\n%s", i, got, want)
1833		}
1834	}
1835}
1836
1837type limitedBytesWriter struct {
1838	w      io.Writer
1839	remain int // until writes fail
1840}
1841
1842func (lw *limitedBytesWriter) Write(p []byte) (n int, err error) {
1843	if lw.remain <= 0 {
1844		println("error")
1845		return 0, errors.New("write limit hit")
1846	}
1847	if len(p) > lw.remain {
1848		p = p[:lw.remain]
1849		n, _ = lw.w.Write(p)
1850		lw.remain = 0
1851		return n, errors.New("write limit hit")
1852	}
1853	n, err = lw.w.Write(p)
1854	lw.remain -= n
1855	return n, err
1856}
1857
1858func TestMarshalWriteErrors(t *testing.T) {
1859	var buf bytes.Buffer
1860	const writeCap = 1024
1861	w := &limitedBytesWriter{&buf, writeCap}
1862	enc := NewEncoder(w)
1863	var err error
1864	var i int
1865	const n = 4000
1866	for i = 1; i <= n; i++ {
1867		err = enc.Encode(&Passenger{
1868			Name:   []string{"Alice", "Bob"},
1869			Weight: 5,
1870		})
1871		if err != nil {
1872			break
1873		}
1874	}
1875	if err == nil {
1876		t.Error("expected an error")
1877	}
1878	if i == n {
1879		t.Errorf("expected to fail before the end")
1880	}
1881	if buf.Len() != writeCap {
1882		t.Errorf("buf.Len() = %d; want %d", buf.Len(), writeCap)
1883	}
1884}
1885
1886func TestMarshalWriteIOErrors(t *testing.T) {
1887	enc := NewEncoder(errWriter{})
1888
1889	expectErr := "unwritable"
1890	err := enc.Encode(&Passenger{})
1891	if err == nil || err.Error() != expectErr {
1892		t.Errorf("EscapeTest = [error] %v, want %v", err, expectErr)
1893	}
1894}
1895
1896func TestMarshalFlush(t *testing.T) {
1897	var buf strings.Builder
1898	enc := NewEncoder(&buf)
1899	if err := enc.EncodeToken(CharData("hello world")); err != nil {
1900		t.Fatalf("enc.EncodeToken: %v", err)
1901	}
1902	if buf.Len() > 0 {
1903		t.Fatalf("enc.EncodeToken caused actual write: %q", buf.String())
1904	}
1905	if err := enc.Flush(); err != nil {
1906		t.Fatalf("enc.Flush: %v", err)
1907	}
1908	if buf.String() != "hello world" {
1909		t.Fatalf("after enc.Flush, buf.String() = %q, want %q", buf.String(), "hello world")
1910	}
1911}
1912
1913func BenchmarkMarshal(b *testing.B) {
1914	b.ReportAllocs()
1915	b.RunParallel(func(pb *testing.PB) {
1916		for pb.Next() {
1917			Marshal(atomValue)
1918		}
1919	})
1920}
1921
1922func BenchmarkUnmarshal(b *testing.B) {
1923	b.ReportAllocs()
1924	xml := []byte(atomXML)
1925	b.RunParallel(func(pb *testing.PB) {
1926		for pb.Next() {
1927			Unmarshal(xml, &Feed{})
1928		}
1929	})
1930}
1931
1932// golang.org/issue/6556
1933func TestStructPointerMarshal(t *testing.T) {
1934	type A struct {
1935		XMLName string `xml:"a"`
1936		B       []any
1937	}
1938	type C struct {
1939		XMLName Name
1940		Value   string `xml:"value"`
1941	}
1942
1943	a := new(A)
1944	a.B = append(a.B, &C{
1945		XMLName: Name{Local: "c"},
1946		Value:   "x",
1947	})
1948
1949	b, err := Marshal(a)
1950	if err != nil {
1951		t.Fatal(err)
1952	}
1953	if x := string(b); x != "<a><c><value>x</value></c></a>" {
1954		t.Fatal(x)
1955	}
1956	var v A
1957	err = Unmarshal(b, &v)
1958	if err != nil {
1959		t.Fatal(err)
1960	}
1961}
1962
1963var encodeTokenTests = []struct {
1964	desc string
1965	toks []Token
1966	want string
1967	err  string
1968}{{
1969	desc: "start element with name space",
1970	toks: []Token{
1971		StartElement{Name{"space", "local"}, nil},
1972	},
1973	want: `<local xmlns="space">`,
1974}, {
1975	desc: "start element with no name",
1976	toks: []Token{
1977		StartElement{Name{"space", ""}, nil},
1978	},
1979	err: "xml: start tag with no name",
1980}, {
1981	desc: "end element with no name",
1982	toks: []Token{
1983		EndElement{Name{"space", ""}},
1984	},
1985	err: "xml: end tag with no name",
1986}, {
1987	desc: "char data",
1988	toks: []Token{
1989		CharData("foo"),
1990	},
1991	want: `foo`,
1992}, {
1993	desc: "char data with escaped chars",
1994	toks: []Token{
1995		CharData(" \t\n"),
1996	},
1997	want: " &#x9;\n",
1998}, {
1999	desc: "comment",
2000	toks: []Token{
2001		Comment("foo"),
2002	},
2003	want: `<!--foo-->`,
2004}, {
2005	desc: "comment with invalid content",
2006	toks: []Token{
2007		Comment("foo-->"),
2008	},
2009	err: "xml: EncodeToken of Comment containing --> marker",
2010}, {
2011	desc: "proc instruction",
2012	toks: []Token{
2013		ProcInst{"Target", []byte("Instruction")},
2014	},
2015	want: `<?Target Instruction?>`,
2016}, {
2017	desc: "proc instruction with empty target",
2018	toks: []Token{
2019		ProcInst{"", []byte("Instruction")},
2020	},
2021	err: "xml: EncodeToken of ProcInst with invalid Target",
2022}, {
2023	desc: "proc instruction with bad content",
2024	toks: []Token{
2025		ProcInst{"", []byte("Instruction?>")},
2026	},
2027	err: "xml: EncodeToken of ProcInst with invalid Target",
2028}, {
2029	desc: "directive",
2030	toks: []Token{
2031		Directive("foo"),
2032	},
2033	want: `<!foo>`,
2034}, {
2035	desc: "more complex directive",
2036	toks: []Token{
2037		Directive("DOCTYPE doc [ <!ELEMENT doc '>'> <!-- com>ment --> ]"),
2038	},
2039	want: `<!DOCTYPE doc [ <!ELEMENT doc '>'> <!-- com>ment --> ]>`,
2040}, {
2041	desc: "directive instruction with bad name",
2042	toks: []Token{
2043		Directive("foo>"),
2044	},
2045	err: "xml: EncodeToken of Directive containing wrong < or > markers",
2046}, {
2047	desc: "end tag without start tag",
2048	toks: []Token{
2049		EndElement{Name{"foo", "bar"}},
2050	},
2051	err: "xml: end tag </bar> without start tag",
2052}, {
2053	desc: "mismatching end tag local name",
2054	toks: []Token{
2055		StartElement{Name{"", "foo"}, nil},
2056		EndElement{Name{"", "bar"}},
2057	},
2058	err:  "xml: end tag </bar> does not match start tag <foo>",
2059	want: `<foo>`,
2060}, {
2061	desc: "mismatching end tag namespace",
2062	toks: []Token{
2063		StartElement{Name{"space", "foo"}, nil},
2064		EndElement{Name{"another", "foo"}},
2065	},
2066	err:  "xml: end tag </foo> in namespace another does not match start tag <foo> in namespace space",
2067	want: `<foo xmlns="space">`,
2068}, {
2069	desc: "start element with explicit namespace",
2070	toks: []Token{
2071		StartElement{Name{"space", "local"}, []Attr{
2072			{Name{"xmlns", "x"}, "space"},
2073			{Name{"space", "foo"}, "value"},
2074		}},
2075	},
2076	want: `<local xmlns="space" xmlns:_xmlns="xmlns" _xmlns:x="space" xmlns:space="space" space:foo="value">`,
2077}, {
2078	desc: "start element with explicit namespace and colliding prefix",
2079	toks: []Token{
2080		StartElement{Name{"space", "local"}, []Attr{
2081			{Name{"xmlns", "x"}, "space"},
2082			{Name{"space", "foo"}, "value"},
2083			{Name{"x", "bar"}, "other"},
2084		}},
2085	},
2086	want: `<local xmlns="space" xmlns:_xmlns="xmlns" _xmlns:x="space" xmlns:space="space" space:foo="value" xmlns:x="x" x:bar="other">`,
2087}, {
2088	desc: "start element using previously defined namespace",
2089	toks: []Token{
2090		StartElement{Name{"", "local"}, []Attr{
2091			{Name{"xmlns", "x"}, "space"},
2092		}},
2093		StartElement{Name{"space", "foo"}, []Attr{
2094			{Name{"space", "x"}, "y"},
2095		}},
2096	},
2097	want: `<local xmlns:_xmlns="xmlns" _xmlns:x="space"><foo xmlns="space" xmlns:space="space" space:x="y">`,
2098}, {
2099	desc: "nested name space with same prefix",
2100	toks: []Token{
2101		StartElement{Name{"", "foo"}, []Attr{
2102			{Name{"xmlns", "x"}, "space1"},
2103		}},
2104		StartElement{Name{"", "foo"}, []Attr{
2105			{Name{"xmlns", "x"}, "space2"},
2106		}},
2107		StartElement{Name{"", "foo"}, []Attr{
2108			{Name{"space1", "a"}, "space1 value"},
2109			{Name{"space2", "b"}, "space2 value"},
2110		}},
2111		EndElement{Name{"", "foo"}},
2112		EndElement{Name{"", "foo"}},
2113		StartElement{Name{"", "foo"}, []Attr{
2114			{Name{"space1", "a"}, "space1 value"},
2115			{Name{"space2", "b"}, "space2 value"},
2116		}},
2117	},
2118	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">`,
2119}, {
2120	desc: "start element defining several prefixes for the same name space",
2121	toks: []Token{
2122		StartElement{Name{"space", "foo"}, []Attr{
2123			{Name{"xmlns", "a"}, "space"},
2124			{Name{"xmlns", "b"}, "space"},
2125			{Name{"space", "x"}, "value"},
2126		}},
2127	},
2128	want: `<foo xmlns="space" xmlns:_xmlns="xmlns" _xmlns:a="space" _xmlns:b="space" xmlns:space="space" space:x="value">`,
2129}, {
2130	desc: "nested element redefines name space",
2131	toks: []Token{
2132		StartElement{Name{"", "foo"}, []Attr{
2133			{Name{"xmlns", "x"}, "space"},
2134		}},
2135		StartElement{Name{"space", "foo"}, []Attr{
2136			{Name{"xmlns", "y"}, "space"},
2137			{Name{"space", "a"}, "value"},
2138		}},
2139	},
2140	want: `<foo xmlns:_xmlns="xmlns" _xmlns:x="space"><foo xmlns="space" _xmlns:y="space" xmlns:space="space" space:a="value">`,
2141}, {
2142	desc: "nested element creates alias for default name space",
2143	toks: []Token{
2144		StartElement{Name{"space", "foo"}, []Attr{
2145			{Name{"", "xmlns"}, "space"},
2146		}},
2147		StartElement{Name{"space", "foo"}, []Attr{
2148			{Name{"xmlns", "y"}, "space"},
2149			{Name{"space", "a"}, "value"},
2150		}},
2151	},
2152	want: `<foo xmlns="space" xmlns="space"><foo xmlns="space" xmlns:_xmlns="xmlns" _xmlns:y="space" xmlns:space="space" space:a="value">`,
2153}, {
2154	desc: "nested element defines default name space with existing prefix",
2155	toks: []Token{
2156		StartElement{Name{"", "foo"}, []Attr{
2157			{Name{"xmlns", "x"}, "space"},
2158		}},
2159		StartElement{Name{"space", "foo"}, []Attr{
2160			{Name{"", "xmlns"}, "space"},
2161			{Name{"space", "a"}, "value"},
2162		}},
2163	},
2164	want: `<foo xmlns:_xmlns="xmlns" _xmlns:x="space"><foo xmlns="space" xmlns="space" xmlns:space="space" space:a="value">`,
2165}, {
2166	desc: "nested element uses empty attribute name space when default ns defined",
2167	toks: []Token{
2168		StartElement{Name{"space", "foo"}, []Attr{
2169			{Name{"", "xmlns"}, "space"},
2170		}},
2171		StartElement{Name{"space", "foo"}, []Attr{
2172			{Name{"", "attr"}, "value"},
2173		}},
2174	},
2175	want: `<foo xmlns="space" xmlns="space"><foo xmlns="space" attr="value">`,
2176}, {
2177	desc: "redefine xmlns",
2178	toks: []Token{
2179		StartElement{Name{"", "foo"}, []Attr{
2180			{Name{"foo", "xmlns"}, "space"},
2181		}},
2182	},
2183	want: `<foo xmlns:foo="foo" foo:xmlns="space">`,
2184}, {
2185	desc: "xmlns with explicit name space #1",
2186	toks: []Token{
2187		StartElement{Name{"space", "foo"}, []Attr{
2188			{Name{"xml", "xmlns"}, "space"},
2189		}},
2190	},
2191	want: `<foo xmlns="space" xmlns:_xml="xml" _xml:xmlns="space">`,
2192}, {
2193	desc: "xmlns with explicit name space #2",
2194	toks: []Token{
2195		StartElement{Name{"space", "foo"}, []Attr{
2196			{Name{xmlURL, "xmlns"}, "space"},
2197		}},
2198	},
2199	want: `<foo xmlns="space" xml:xmlns="space">`,
2200}, {
2201	desc: "empty name space declaration is ignored",
2202	toks: []Token{
2203		StartElement{Name{"", "foo"}, []Attr{
2204			{Name{"xmlns", "foo"}, ""},
2205		}},
2206	},
2207	want: `<foo xmlns:_xmlns="xmlns" _xmlns:foo="">`,
2208}, {
2209	desc: "attribute with no name is ignored",
2210	toks: []Token{
2211		StartElement{Name{"", "foo"}, []Attr{
2212			{Name{"", ""}, "value"},
2213		}},
2214	},
2215	want: `<foo>`,
2216}, {
2217	desc: "namespace URL with non-valid name",
2218	toks: []Token{
2219		StartElement{Name{"/34", "foo"}, []Attr{
2220			{Name{"/34", "x"}, "value"},
2221		}},
2222	},
2223	want: `<foo xmlns="/34" xmlns:_="/34" _:x="value">`,
2224}, {
2225	desc: "nested element resets default namespace to empty",
2226	toks: []Token{
2227		StartElement{Name{"space", "foo"}, []Attr{
2228			{Name{"", "xmlns"}, "space"},
2229		}},
2230		StartElement{Name{"", "foo"}, []Attr{
2231			{Name{"", "xmlns"}, ""},
2232			{Name{"", "x"}, "value"},
2233			{Name{"space", "x"}, "value"},
2234		}},
2235	},
2236	want: `<foo xmlns="space" xmlns="space"><foo xmlns="" x="value" xmlns:space="space" space:x="value">`,
2237}, {
2238	desc: "nested element requires empty default name space",
2239	toks: []Token{
2240		StartElement{Name{"space", "foo"}, []Attr{
2241			{Name{"", "xmlns"}, "space"},
2242		}},
2243		StartElement{Name{"", "foo"}, nil},
2244	},
2245	want: `<foo xmlns="space" xmlns="space"><foo>`,
2246}, {
2247	desc: "attribute uses name space from xmlns",
2248	toks: []Token{
2249		StartElement{Name{"some/space", "foo"}, []Attr{
2250			{Name{"", "attr"}, "value"},
2251			{Name{"some/space", "other"}, "other value"},
2252		}},
2253	},
2254	want: `<foo xmlns="some/space" attr="value" xmlns:space="some/space" space:other="other value">`,
2255}, {
2256	desc: "default name space should not be used by attributes",
2257	toks: []Token{
2258		StartElement{Name{"space", "foo"}, []Attr{
2259			{Name{"", "xmlns"}, "space"},
2260			{Name{"xmlns", "bar"}, "space"},
2261			{Name{"space", "baz"}, "foo"},
2262		}},
2263		StartElement{Name{"space", "baz"}, nil},
2264		EndElement{Name{"space", "baz"}},
2265		EndElement{Name{"space", "foo"}},
2266	},
2267	want: `<foo xmlns="space" xmlns="space" xmlns:_xmlns="xmlns" _xmlns:bar="space" xmlns:space="space" space:baz="foo"><baz xmlns="space"></baz></foo>`,
2268}, {
2269	desc: "default name space not used by attributes, not explicitly defined",
2270	toks: []Token{
2271		StartElement{Name{"space", "foo"}, []Attr{
2272			{Name{"", "xmlns"}, "space"},
2273			{Name{"space", "baz"}, "foo"},
2274		}},
2275		StartElement{Name{"space", "baz"}, nil},
2276		EndElement{Name{"space", "baz"}},
2277		EndElement{Name{"space", "foo"}},
2278	},
2279	want: `<foo xmlns="space" xmlns="space" xmlns:space="space" space:baz="foo"><baz xmlns="space"></baz></foo>`,
2280}, {
2281	desc: "impossible xmlns declaration",
2282	toks: []Token{
2283		StartElement{Name{"", "foo"}, []Attr{
2284			{Name{"", "xmlns"}, "space"},
2285		}},
2286		StartElement{Name{"space", "bar"}, []Attr{
2287			{Name{"space", "attr"}, "value"},
2288		}},
2289	},
2290	want: `<foo xmlns="space"><bar xmlns="space" xmlns:space="space" space:attr="value">`,
2291}, {
2292	desc: "reserved namespace prefix -- all lower case",
2293	toks: []Token{
2294		StartElement{Name{"", "foo"}, []Attr{
2295			{Name{"http://www.w3.org/2001/xmlSchema-instance", "nil"}, "true"},
2296		}},
2297	},
2298	want: `<foo xmlns:_xmlSchema-instance="http://www.w3.org/2001/xmlSchema-instance" _xmlSchema-instance:nil="true">`,
2299}, {
2300	desc: "reserved namespace prefix -- all upper case",
2301	toks: []Token{
2302		StartElement{Name{"", "foo"}, []Attr{
2303			{Name{"http://www.w3.org/2001/XMLSchema-instance", "nil"}, "true"},
2304		}},
2305	},
2306	want: `<foo xmlns:_XMLSchema-instance="http://www.w3.org/2001/XMLSchema-instance" _XMLSchema-instance:nil="true">`,
2307}, {
2308	desc: "reserved namespace prefix -- all mixed case",
2309	toks: []Token{
2310		StartElement{Name{"", "foo"}, []Attr{
2311			{Name{"http://www.w3.org/2001/XmLSchema-instance", "nil"}, "true"},
2312		}},
2313	},
2314	want: `<foo xmlns:_XmLSchema-instance="http://www.w3.org/2001/XmLSchema-instance" _XmLSchema-instance:nil="true">`,
2315}}
2316
2317func TestEncodeToken(t *testing.T) {
2318loop:
2319	for i, tt := range encodeTokenTests {
2320		var buf strings.Builder
2321		enc := NewEncoder(&buf)
2322		var err error
2323		for j, tok := range tt.toks {
2324			err = enc.EncodeToken(tok)
2325			if err != nil && j < len(tt.toks)-1 {
2326				t.Errorf("#%d %s token #%d: %v", i, tt.desc, j, err)
2327				continue loop
2328			}
2329		}
2330		errorf := func(f string, a ...any) {
2331			t.Errorf("#%d %s token #%d:%s", i, tt.desc, len(tt.toks)-1, fmt.Sprintf(f, a...))
2332		}
2333		switch {
2334		case tt.err != "" && err == nil:
2335			errorf(" expected error; got none")
2336			continue
2337		case tt.err == "" && err != nil:
2338			errorf(" got error: %v", err)
2339			continue
2340		case tt.err != "" && err != nil && tt.err != err.Error():
2341			errorf(" error mismatch; got %v, want %v", err, tt.err)
2342			continue
2343		}
2344		if err := enc.Flush(); err != nil {
2345			errorf(" %v", err)
2346			continue
2347		}
2348		if got := buf.String(); got != tt.want {
2349			errorf("\ngot  %v\nwant %v", got, tt.want)
2350			continue
2351		}
2352	}
2353}
2354
2355func TestProcInstEncodeToken(t *testing.T) {
2356	var buf bytes.Buffer
2357	enc := NewEncoder(&buf)
2358
2359	if err := enc.EncodeToken(ProcInst{"xml", []byte("Instruction")}); err != nil {
2360		t.Fatalf("enc.EncodeToken: expected to be able to encode xml target ProcInst as first token, %s", err)
2361	}
2362
2363	if err := enc.EncodeToken(ProcInst{"Target", []byte("Instruction")}); err != nil {
2364		t.Fatalf("enc.EncodeToken: expected to be able to add non-xml target ProcInst")
2365	}
2366
2367	if err := enc.EncodeToken(ProcInst{"xml", []byte("Instruction")}); err == nil {
2368		t.Fatalf("enc.EncodeToken: expected to not be allowed to encode xml target ProcInst when not first token")
2369	}
2370}
2371
2372func TestDecodeEncode(t *testing.T) {
2373	var in, out bytes.Buffer
2374	in.WriteString(`<?xml version="1.0" encoding="UTF-8"?>
2375<?Target Instruction?>
2376<root>
2377</root>
2378`)
2379	dec := NewDecoder(&in)
2380	enc := NewEncoder(&out)
2381	for tok, err := dec.Token(); err == nil; tok, err = dec.Token() {
2382		err = enc.EncodeToken(tok)
2383		if err != nil {
2384			t.Fatalf("enc.EncodeToken: Unable to encode token (%#v), %v", tok, err)
2385		}
2386	}
2387}
2388
2389// Issue 9796. Used to fail with GORACE="halt_on_error=1" -race.
2390func TestRace9796(t *testing.T) {
2391	type A struct{}
2392	type B struct {
2393		C []A `xml:"X>Y"`
2394	}
2395	var wg sync.WaitGroup
2396	for i := 0; i < 2; i++ {
2397		wg.Add(1)
2398		go func() {
2399			Marshal(B{[]A{{}}})
2400			wg.Done()
2401		}()
2402	}
2403	wg.Wait()
2404}
2405
2406func TestIsValidDirective(t *testing.T) {
2407	testOK := []string{
2408		"<>",
2409		"< < > >",
2410		"<!DOCTYPE '<' '>' '>' <!--nothing-->>",
2411		"<!DOCTYPE doc [ <!ELEMENT doc ANY> <!ELEMENT doc ANY> ]>",
2412		"<!DOCTYPE doc [ <!ELEMENT doc \"ANY> '<' <!E\" LEMENT '>' doc ANY> ]>",
2413		"<!DOCTYPE doc <!-- just>>>> a < comment --> [ <!ITEM anything> ] >",
2414	}
2415	testKO := []string{
2416		"<",
2417		">",
2418		"<!--",
2419		"-->",
2420		"< > > < < >",
2421		"<!dummy <!-- > -->",
2422		"<!DOCTYPE doc '>",
2423		"<!DOCTYPE doc '>'",
2424		"<!DOCTYPE doc <!--comment>",
2425	}
2426	for _, s := range testOK {
2427		if !isValidDirective(Directive(s)) {
2428			t.Errorf("Directive %q is expected to be valid", s)
2429		}
2430	}
2431	for _, s := range testKO {
2432		if isValidDirective(Directive(s)) {
2433			t.Errorf("Directive %q is expected to be invalid", s)
2434		}
2435	}
2436}
2437
2438// Issue 11719. EncodeToken used to silently eat tokens with an invalid type.
2439func TestSimpleUseOfEncodeToken(t *testing.T) {
2440	var buf strings.Builder
2441	enc := NewEncoder(&buf)
2442	if err := enc.EncodeToken(&StartElement{Name: Name{"", "object1"}}); err == nil {
2443		t.Errorf("enc.EncodeToken: pointer type should be rejected")
2444	}
2445	if err := enc.EncodeToken(&EndElement{Name: Name{"", "object1"}}); err == nil {
2446		t.Errorf("enc.EncodeToken: pointer type should be rejected")
2447	}
2448	if err := enc.EncodeToken(StartElement{Name: Name{"", "object2"}}); err != nil {
2449		t.Errorf("enc.EncodeToken: StartElement %s", err)
2450	}
2451	if err := enc.EncodeToken(EndElement{Name: Name{"", "object2"}}); err != nil {
2452		t.Errorf("enc.EncodeToken: EndElement %s", err)
2453	}
2454	if err := enc.EncodeToken(Universe{}); err == nil {
2455		t.Errorf("enc.EncodeToken: invalid type not caught")
2456	}
2457	if err := enc.Flush(); err != nil {
2458		t.Errorf("enc.Flush: %s", err)
2459	}
2460	if buf.Len() == 0 {
2461		t.Errorf("enc.EncodeToken: empty buffer")
2462	}
2463	want := "<object2></object2>"
2464	if buf.String() != want {
2465		t.Errorf("enc.EncodeToken: expected %q; got %q", want, buf.String())
2466	}
2467}
2468
2469// Issue 16158. Decoder.unmarshalAttr ignores the return value of copyValue.
2470func TestIssue16158(t *testing.T) {
2471	const data = `<foo b="HELLOWORLD"></foo>`
2472	err := Unmarshal([]byte(data), &struct {
2473		B byte `xml:"b,attr,omitempty"`
2474	}{})
2475	if err == nil {
2476		t.Errorf("Unmarshal: expected error, got nil")
2477	}
2478}
2479
2480// Issue 20953. Crash on invalid XMLName attribute.
2481
2482type InvalidXMLName struct {
2483	XMLName Name `xml:"error"`
2484	Type    struct {
2485		XMLName Name `xml:"type,attr"`
2486	}
2487}
2488
2489func TestInvalidXMLName(t *testing.T) {
2490	var buf bytes.Buffer
2491	enc := NewEncoder(&buf)
2492	if err := enc.Encode(InvalidXMLName{}); err == nil {
2493		t.Error("unexpected success")
2494	} else if want := "invalid tag"; !strings.Contains(err.Error(), want) {
2495		t.Errorf("error %q does not contain %q", err, want)
2496	}
2497}
2498
2499// Issue 50164. Crash on zero value XML attribute.
2500type LayerOne struct {
2501	XMLName Name `xml:"l1"`
2502
2503	Value     *float64 `xml:"value,omitempty"`
2504	*LayerTwo `xml:",omitempty"`
2505}
2506
2507type LayerTwo struct {
2508	ValueTwo *int `xml:"value_two,attr,omitempty"`
2509}
2510
2511func TestMarshalZeroValue(t *testing.T) {
2512	proofXml := `<l1><value>1.2345</value></l1>`
2513	var l1 LayerOne
2514	err := Unmarshal([]byte(proofXml), &l1)
2515	if err != nil {
2516		t.Fatalf("unmarshal XML error: %v", err)
2517	}
2518	want := float64(1.2345)
2519	got := *l1.Value
2520	if got != want {
2521		t.Fatalf("unexpected unmarshal result, want %f but got %f", want, got)
2522	}
2523
2524	// Marshal again (or Encode again)
2525	// In issue 50164, here `Marshal(l1)` will panic because of the zero value of xml attribute ValueTwo `value_two`.
2526	anotherXML, err := Marshal(l1)
2527	if err != nil {
2528		t.Fatalf("marshal XML error: %v", err)
2529	}
2530	if string(anotherXML) != proofXml {
2531		t.Fatalf("unexpected unmarshal result, want %q but got %q", proofXml, anotherXML)
2532	}
2533}
2534
2535var closeTests = []struct {
2536	desc string
2537	toks []Token
2538	want string
2539	err  string
2540}{{
2541	desc: "unclosed start element",
2542	toks: []Token{
2543		StartElement{Name{"", "foo"}, nil},
2544	},
2545	want: `<foo>`,
2546	err:  "unclosed tag <foo>",
2547}, {
2548	desc: "closed element",
2549	toks: []Token{
2550		StartElement{Name{"", "foo"}, nil},
2551		EndElement{Name{"", "foo"}},
2552	},
2553	want: `<foo></foo>`,
2554}, {
2555	desc: "directive",
2556	toks: []Token{
2557		Directive("foo"),
2558	},
2559	want: `<!foo>`,
2560}}
2561
2562func TestClose(t *testing.T) {
2563	for _, tt := range closeTests {
2564		tt := tt
2565		t.Run(tt.desc, func(t *testing.T) {
2566			var out strings.Builder
2567			enc := NewEncoder(&out)
2568			for j, tok := range tt.toks {
2569				if err := enc.EncodeToken(tok); err != nil {
2570					t.Fatalf("token #%d: %v", j, err)
2571				}
2572			}
2573			err := enc.Close()
2574			switch {
2575			case tt.err != "" && err == nil:
2576				t.Error(" expected error; got none")
2577			case tt.err == "" && err != nil:
2578				t.Errorf(" got error: %v", err)
2579			case tt.err != "" && err != nil && tt.err != err.Error():
2580				t.Errorf(" error mismatch; got %v, want %v", err, tt.err)
2581			}
2582			if got := out.String(); got != tt.want {
2583				t.Errorf("\ngot  %v\nwant %v", got, tt.want)
2584			}
2585			t.Log(enc.p.closed)
2586			if err := enc.EncodeToken(Directive("foo")); err == nil {
2587				t.Errorf("unexpected success when encoding after Close")
2588			}
2589		})
2590	}
2591}
2592