libgo: update to go1.9
[official-gcc.git] / libgo / go / encoding / xml / marshal_test.go
blob674c6b5b3f4de3a401613babb8260738ec1c7234
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.
5 package xml
7 import (
8 "bytes"
9 "errors"
10 "fmt"
11 "io"
12 "reflect"
13 "strconv"
14 "strings"
15 "sync"
16 "testing"
17 "time"
20 type DriveType int
22 const (
23 HyperDrive DriveType = iota
24 ImprobabilityDrive
27 type Passenger struct {
28 Name []string `xml:"name"`
29 Weight float32 `xml:"weight"`
32 type Ship struct {
33 XMLName struct{} `xml:"spaceship"`
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
43 type NamedType string
45 type Port struct {
46 XMLName struct{} `xml:"port"`
47 Type string `xml:"type,attr,omitempty"`
48 Comment string `xml:",comment"`
49 Number string `xml:",chardata"`
52 type Domain struct {
53 XMLName struct{} `xml:"domain"`
54 Country string `xml:",attr,omitempty"`
55 Name []byte `xml:",chardata"`
56 Comment []byte `xml:",comment"`
59 type Book struct {
60 XMLName struct{} `xml:"book"`
61 Title string `xml:",chardata"`
64 type Event struct {
65 XMLName struct{} `xml:"event"`
66 Year int `xml:",chardata"`
69 type Movie struct {
70 XMLName struct{} `xml:"movie"`
71 Length uint `xml:",chardata"`
74 type Pi struct {
75 XMLName struct{} `xml:"pi"`
76 Approximation float32 `xml:",chardata"`
79 type Universe struct {
80 XMLName struct{} `xml:"universe"`
81 Visible float64 `xml:",chardata"`
84 type Particle struct {
85 XMLName struct{} `xml:"particle"`
86 HasMass bool `xml:",chardata"`
89 type Departure struct {
90 XMLName struct{} `xml:"departure"`
91 When time.Time `xml:",chardata"`
94 type SecretAgent struct {
95 XMLName struct{} `xml:"agent"`
96 Handle string `xml:"handle,attr"`
97 Identity string
98 Obfuscate string `xml:",innerxml"`
101 type NestedItems struct {
102 XMLName struct{} `xml:"result"`
103 Items []string `xml:">item"`
104 Item1 []string `xml:"Items>item1"`
107 type 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"`
114 type 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"`
122 type NilTest struct {
123 A interface{} `xml:"parent1>parent2>a"`
124 B interface{} `xml:"parent1>b"`
125 C interface{} `xml:"parent1>parent2>c"`
128 type 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"`
136 var nilStruct *Ship
138 type EmbedA struct {
139 EmbedC
140 EmbedB EmbedB
141 FieldA string
142 embedD
145 type EmbedB struct {
146 FieldB string
147 *EmbedC
150 type EmbedC struct {
151 FieldA1 string `xml:"FieldA>A1"`
152 FieldA2 string `xml:"FieldA>A2"`
153 FieldB string
154 FieldC string
157 type embedD struct {
158 fieldD string
159 FieldE string // Promoted and visible when embedD is embedded.
162 type 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"`
170 type NamePrecedence struct {
171 XMLName Name `xml:"Parent"`
172 FromTag XMLNameWithoutTag `xml:"InTag"`
173 FromNameVal XMLNameWithoutTag
174 FromNameTag XMLNameWithTag
175 InFieldName string
178 type XMLNameWithTag struct {
179 XMLName Name `xml:"InXMLNameTag"`
180 Value string `xml:",chardata"`
183 type XMLNameWithoutTag struct {
184 XMLName Name
185 Value string `xml:",chardata"`
188 type NameInField struct {
189 Foo Name `xml:"ns foo"`
192 type 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"`
202 type 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"`
213 type 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"`
224 type 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"`
236 type AnyTest struct {
237 XMLName struct{} `xml:"a"`
238 Nested string `xml:"nested>value"`
239 AnyField AnyHolder `xml:",any"`
242 type AnyOmitTest struct {
243 XMLName struct{} `xml:"a"`
244 Nested string `xml:"nested>value"`
245 AnyField *AnyHolder `xml:",any,omitempty"`
248 type AnySliceTest struct {
249 XMLName struct{} `xml:"a"`
250 Nested string `xml:"nested>value"`
251 AnyField []AnyHolder `xml:",any"`
254 type AnyHolder struct {
255 XMLName Name
256 XML string `xml:",innerxml"`
259 type RecurseA struct {
260 A string
261 B *RecurseB
264 type RecurseB struct {
265 A *RecurseA
266 B string
269 type PresenceTest struct {
270 Exists *struct{}
273 type IgnoreTest struct {
274 PublicSecret string `xml:"-"`
277 type MyBytes []byte
279 type Data struct {
280 Bytes []byte
281 Attr []byte `xml:",attr"`
282 Custom MyBytes
285 type Plain struct {
286 V interface{}
289 type MyInt int
291 type EmbedInt struct {
292 MyInt
295 type Strings struct {
296 X []string `xml:"A>B,omitempty"`
299 type 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"`
307 type ChardataEmptyTest struct {
308 XMLName Name `xml:"test"`
309 Contents *string `xml:",chardata"`
312 type MyMarshalerTest struct {
315 var _ Marshaler = (*MyMarshalerTest)(nil)
317 func (m *MyMarshalerTest) MarshalXML(e *Encoder, start StartElement) error {
318 e.EncodeToken(start)
319 e.EncodeToken(CharData([]byte("hello world")))
320 e.EncodeToken(EndElement{start.Name})
321 return nil
324 type MyMarshalerAttrTest struct {
327 var _ MarshalerAttr = (*MyMarshalerAttrTest)(nil)
329 func (m *MyMarshalerAttrTest) MarshalXMLAttr(name Name) (Attr, error) {
330 return Attr{name, "hello world"}, nil
333 func (m *MyMarshalerAttrTest) UnmarshalXMLAttr(attr Attr) error {
334 return nil
337 type MarshalerStruct struct {
338 Foo MyMarshalerAttrTest `xml:",attr"`
341 type InnerStruct struct {
342 XMLName Name `xml:"testns outer"`
345 type OuterStruct struct {
346 InnerStruct
347 IntAttr int `xml:"int,attr"`
350 type OuterNamedStruct struct {
351 InnerStruct
352 XMLName Name `xml:"outerns test"`
353 IntAttr int `xml:"int,attr"`
356 type OuterNamedOrderedStruct struct {
357 XMLName Name `xml:"outerns test"`
358 InnerStruct
359 IntAttr int `xml:"int,attr"`
362 type OuterOuterStruct struct {
363 OuterStruct
366 type NestedAndChardata struct {
367 AB []string `xml:"A>B"`
368 Chardata string `xml:",chardata"`
371 type NestedAndComment struct {
372 AB []string `xml:"A>B"`
373 Comment string `xml:",comment"`
376 type CDataTest struct {
377 Chardata string `xml:",cdata"`
380 type NestedAndCData struct {
381 AB []string `xml:"A>B"`
382 CDATA string `xml:",cdata"`
385 func ifaceptr(x interface{}) interface{} {
386 return &x
389 func stringptr(x string) *string {
390 return &x
393 type T1 struct{}
394 type T2 struct{}
395 type T3 struct{}
397 type IndirComment struct {
398 T1 T1
399 Comment *string `xml:",comment"`
400 T2 T2
403 type DirectComment struct {
404 T1 T1
405 Comment string `xml:",comment"`
406 T2 T2
409 type IfaceComment struct {
410 T1 T1
411 Comment interface{} `xml:",comment"`
412 T2 T2
415 type IndirChardata struct {
416 T1 T1
417 Chardata *string `xml:",chardata"`
418 T2 T2
421 type DirectChardata struct {
422 T1 T1
423 Chardata string `xml:",chardata"`
424 T2 T2
427 type IfaceChardata struct {
428 T1 T1
429 Chardata interface{} `xml:",chardata"`
430 T2 T2
433 type IndirCDATA struct {
434 T1 T1
435 CDATA *string `xml:",cdata"`
436 T2 T2
439 type DirectCDATA struct {
440 T1 T1
441 CDATA string `xml:",cdata"`
442 T2 T2
445 type IfaceCDATA struct {
446 T1 T1
447 CDATA interface{} `xml:",cdata"`
448 T2 T2
451 type IndirInnerXML struct {
452 T1 T1
453 InnerXML *string `xml:",innerxml"`
454 T2 T2
457 type DirectInnerXML struct {
458 T1 T1
459 InnerXML string `xml:",innerxml"`
460 T2 T2
463 type IfaceInnerXML struct {
464 T1 T1
465 InnerXML interface{} `xml:",innerxml"`
466 T2 T2
469 type IndirElement struct {
470 T1 T1
471 Element *string
472 T2 T2
475 type DirectElement struct {
476 T1 T1
477 Element string
478 T2 T2
481 type IfaceElement struct {
482 T1 T1
483 Element interface{}
484 T2 T2
487 type IndirOmitEmpty struct {
488 T1 T1
489 OmitEmpty *string `xml:",omitempty"`
490 T2 T2
493 type DirectOmitEmpty struct {
494 T1 T1
495 OmitEmpty string `xml:",omitempty"`
496 T2 T2
499 type IfaceOmitEmpty struct {
500 T1 T1
501 OmitEmpty interface{} `xml:",omitempty"`
502 T2 T2
505 type IndirAny struct {
506 T1 T1
507 Any *string `xml:",any"`
508 T2 T2
511 type DirectAny struct {
512 T1 T1
513 Any string `xml:",any"`
514 T2 T2
517 type IfaceAny struct {
518 T1 T1
519 Any interface{} `xml:",any"`
520 T2 T2
523 var (
524 nameAttr = "Sarah"
525 ageAttr = uint(12)
526 contentsAttr = "lorem ipsum"
527 empty = ""
530 // Unless explicitly stated as such (or *Plain), all of the
531 // tests below are two-way tests. When introducing new tests,
532 // please try to make them two-way as well to ensure that
533 // marshaling and unmarshaling are as symmetrical as feasible.
534 var marshalTests = []struct {
535 Value interface{}
536 ExpectXML string
537 MarshalOnly bool
538 MarshalError string
539 UnmarshalOnly bool
540 UnmarshalError string
542 // Test nil marshals to nothing
543 {Value: nil, ExpectXML: ``, MarshalOnly: true},
544 {Value: nilStruct, ExpectXML: ``, MarshalOnly: true},
546 // Test value types
547 {Value: &Plain{true}, ExpectXML: `<Plain><V>true</V></Plain>`},
548 {Value: &Plain{false}, ExpectXML: `<Plain><V>false</V></Plain>`},
549 {Value: &Plain{int(42)}, ExpectXML: `<Plain><V>42</V></Plain>`},
550 {Value: &Plain{int8(42)}, ExpectXML: `<Plain><V>42</V></Plain>`},
551 {Value: &Plain{int16(42)}, ExpectXML: `<Plain><V>42</V></Plain>`},
552 {Value: &Plain{int32(42)}, ExpectXML: `<Plain><V>42</V></Plain>`},
553 {Value: &Plain{uint(42)}, ExpectXML: `<Plain><V>42</V></Plain>`},
554 {Value: &Plain{uint8(42)}, ExpectXML: `<Plain><V>42</V></Plain>`},
555 {Value: &Plain{uint16(42)}, ExpectXML: `<Plain><V>42</V></Plain>`},
556 {Value: &Plain{uint32(42)}, ExpectXML: `<Plain><V>42</V></Plain>`},
557 {Value: &Plain{float32(1.25)}, ExpectXML: `<Plain><V>1.25</V></Plain>`},
558 {Value: &Plain{float64(1.25)}, ExpectXML: `<Plain><V>1.25</V></Plain>`},
559 {Value: &Plain{uintptr(0xFFDD)}, ExpectXML: `<Plain><V>65501</V></Plain>`},
560 {Value: &Plain{"gopher"}, ExpectXML: `<Plain><V>gopher</V></Plain>`},
561 {Value: &Plain{[]byte("gopher")}, ExpectXML: `<Plain><V>gopher</V></Plain>`},
562 {Value: &Plain{"</>"}, ExpectXML: `<Plain><V>&lt;/&gt;</V></Plain>`},
563 {Value: &Plain{[]byte("</>")}, ExpectXML: `<Plain><V>&lt;/&gt;</V></Plain>`},
564 {Value: &Plain{[3]byte{'<', '/', '>'}}, ExpectXML: `<Plain><V>&lt;/&gt;</V></Plain>`},
565 {Value: &Plain{NamedType("potato")}, ExpectXML: `<Plain><V>potato</V></Plain>`},
566 {Value: &Plain{[]int{1, 2, 3}}, ExpectXML: `<Plain><V>1</V><V>2</V><V>3</V></Plain>`},
567 {Value: &Plain{[3]int{1, 2, 3}}, ExpectXML: `<Plain><V>1</V><V>2</V><V>3</V></Plain>`},
568 {Value: ifaceptr(true), MarshalOnly: true, ExpectXML: `<bool>true</bool>`},
570 // Test time.
572 Value: &Plain{time.Unix(1e9, 123456789).UTC()},
573 ExpectXML: `<Plain><V>2001-09-09T01:46:40.123456789Z</V></Plain>`,
576 // A pointer to struct{} may be used to test for an element's presence.
578 Value: &PresenceTest{new(struct{})},
579 ExpectXML: `<PresenceTest><Exists></Exists></PresenceTest>`,
582 Value: &PresenceTest{},
583 ExpectXML: `<PresenceTest></PresenceTest>`,
586 // A pointer to struct{} may be used to test for an element's presence.
588 Value: &PresenceTest{new(struct{})},
589 ExpectXML: `<PresenceTest><Exists></Exists></PresenceTest>`,
592 Value: &PresenceTest{},
593 ExpectXML: `<PresenceTest></PresenceTest>`,
596 // A []byte field is only nil if the element was not found.
598 Value: &Data{},
599 ExpectXML: `<Data></Data>`,
600 UnmarshalOnly: true,
603 Value: &Data{Bytes: []byte{}, Custom: MyBytes{}, Attr: []byte{}},
604 ExpectXML: `<Data Attr=""><Bytes></Bytes><Custom></Custom></Data>`,
605 UnmarshalOnly: true,
608 // Check that []byte works, including named []byte types.
610 Value: &Data{Bytes: []byte("ab"), Custom: MyBytes("cd"), Attr: []byte{'v'}},
611 ExpectXML: `<Data Attr="v"><Bytes>ab</Bytes><Custom>cd</Custom></Data>`,
614 // Test innerxml
616 Value: &SecretAgent{
617 Handle: "007",
618 Identity: "James Bond",
619 Obfuscate: "<redacted/>",
621 ExpectXML: `<agent handle="007"><Identity>James Bond</Identity><redacted/></agent>`,
622 MarshalOnly: true,
625 Value: &SecretAgent{
626 Handle: "007",
627 Identity: "James Bond",
628 Obfuscate: "<Identity>James Bond</Identity><redacted/>",
630 ExpectXML: `<agent handle="007"><Identity>James Bond</Identity><redacted/></agent>`,
631 UnmarshalOnly: true,
634 // Test structs
635 {Value: &Port{Type: "ssl", Number: "443"}, ExpectXML: `<port type="ssl">443</port>`},
636 {Value: &Port{Number: "443"}, ExpectXML: `<port>443</port>`},
637 {Value: &Port{Type: "<unix>"}, ExpectXML: `<port type="&lt;unix&gt;"></port>`},
638 {Value: &Port{Number: "443", Comment: "https"}, ExpectXML: `<port><!--https-->443</port>`},
639 {Value: &Port{Number: "443", Comment: "add space-"}, ExpectXML: `<port><!--add space- -->443</port>`, MarshalOnly: true},
640 {Value: &Domain{Name: []byte("google.com&friends")}, ExpectXML: `<domain>google.com&amp;friends</domain>`},
641 {Value: &Domain{Name: []byte("google.com"), Comment: []byte(" &friends ")}, ExpectXML: `<domain>google.com<!-- &friends --></domain>`},
642 {Value: &Book{Title: "Pride & Prejudice"}, ExpectXML: `<book>Pride &amp; Prejudice</book>`},
643 {Value: &Event{Year: -3114}, ExpectXML: `<event>-3114</event>`},
644 {Value: &Movie{Length: 13440}, ExpectXML: `<movie>13440</movie>`},
645 {Value: &Pi{Approximation: 3.14159265}, ExpectXML: `<pi>3.1415927</pi>`},
646 {Value: &Universe{Visible: 9.3e13}, ExpectXML: `<universe>9.3e+13</universe>`},
647 {Value: &Particle{HasMass: true}, ExpectXML: `<particle>true</particle>`},
648 {Value: &Departure{When: ParseTime("2013-01-09T00:15:00-09:00")}, ExpectXML: `<departure>2013-01-09T00:15:00-09:00</departure>`},
649 {Value: atomValue, ExpectXML: atomXml},
651 Value: &Ship{
652 Name: "Heart of Gold",
653 Pilot: "Computer",
654 Age: 1,
655 Drive: ImprobabilityDrive,
656 Passenger: []*Passenger{
658 Name: []string{"Zaphod", "Beeblebrox"},
659 Weight: 7.25,
662 Name: []string{"Trisha", "McMillen"},
663 Weight: 5.5,
666 Name: []string{"Ford", "Prefect"},
667 Weight: 7,
670 Name: []string{"Arthur", "Dent"},
671 Weight: 6.75,
675 ExpectXML: `<spaceship name="Heart of Gold" pilot="Computer">` +
676 `<drive>` + strconv.Itoa(int(ImprobabilityDrive)) + `</drive>` +
677 `<age>1</age>` +
678 `<passenger>` +
679 `<name>Zaphod</name>` +
680 `<name>Beeblebrox</name>` +
681 `<weight>7.25</weight>` +
682 `</passenger>` +
683 `<passenger>` +
684 `<name>Trisha</name>` +
685 `<name>McMillen</name>` +
686 `<weight>5.5</weight>` +
687 `</passenger>` +
688 `<passenger>` +
689 `<name>Ford</name>` +
690 `<name>Prefect</name>` +
691 `<weight>7</weight>` +
692 `</passenger>` +
693 `<passenger>` +
694 `<name>Arthur</name>` +
695 `<name>Dent</name>` +
696 `<weight>6.75</weight>` +
697 `</passenger>` +
698 `</spaceship>`,
701 // Test a>b
703 Value: &NestedItems{Items: nil, Item1: nil},
704 ExpectXML: `<result>` +
705 `<Items>` +
706 `</Items>` +
707 `</result>`,
710 Value: &NestedItems{Items: []string{}, Item1: []string{}},
711 ExpectXML: `<result>` +
712 `<Items>` +
713 `</Items>` +
714 `</result>`,
715 MarshalOnly: true,
718 Value: &NestedItems{Items: nil, Item1: []string{"A"}},
719 ExpectXML: `<result>` +
720 `<Items>` +
721 `<item1>A</item1>` +
722 `</Items>` +
723 `</result>`,
726 Value: &NestedItems{Items: []string{"A", "B"}, Item1: nil},
727 ExpectXML: `<result>` +
728 `<Items>` +
729 `<item>A</item>` +
730 `<item>B</item>` +
731 `</Items>` +
732 `</result>`,
735 Value: &NestedItems{Items: []string{"A", "B"}, Item1: []string{"C"}},
736 ExpectXML: `<result>` +
737 `<Items>` +
738 `<item>A</item>` +
739 `<item>B</item>` +
740 `<item1>C</item1>` +
741 `</Items>` +
742 `</result>`,
745 Value: &NestedOrder{Field1: "C", Field2: "B", Field3: "A"},
746 ExpectXML: `<result>` +
747 `<parent>` +
748 `<c>C</c>` +
749 `<b>B</b>` +
750 `<a>A</a>` +
751 `</parent>` +
752 `</result>`,
755 Value: &NilTest{A: "A", B: nil, C: "C"},
756 ExpectXML: `<NilTest>` +
757 `<parent1>` +
758 `<parent2><a>A</a></parent2>` +
759 `<parent2><c>C</c></parent2>` +
760 `</parent1>` +
761 `</NilTest>`,
762 MarshalOnly: true, // Uses interface{}
765 Value: &MixedNested{A: "A", B: "B", C: "C", D: "D"},
766 ExpectXML: `<result>` +
767 `<parent1><a>A</a></parent1>` +
768 `<b>B</b>` +
769 `<parent1>` +
770 `<parent2><c>C</c></parent2>` +
771 `<d>D</d>` +
772 `</parent1>` +
773 `</result>`,
776 Value: &Service{Port: &Port{Number: "80"}},
777 ExpectXML: `<service><host><port>80</port></host></service>`,
780 Value: &Service{},
781 ExpectXML: `<service></service>`,
784 Value: &Service{Port: &Port{Number: "80"}, Extra1: "A", Extra2: "B"},
785 ExpectXML: `<service>` +
786 `<host><port>80</port></host>` +
787 `<Extra1>A</Extra1>` +
788 `<host><extra2>B</extra2></host>` +
789 `</service>`,
790 MarshalOnly: true,
793 Value: &Service{Port: &Port{Number: "80"}, Extra2: "example"},
794 ExpectXML: `<service>` +
795 `<host><port>80</port></host>` +
796 `<host><extra2>example</extra2></host>` +
797 `</service>`,
798 MarshalOnly: true,
801 Value: &struct {
802 XMLName struct{} `xml:"space top"`
803 A string `xml:"x>a"`
804 B string `xml:"x>b"`
805 C string `xml:"space x>c"`
806 C1 string `xml:"space1 x>c"`
807 D1 string `xml:"space1 x>d"`
809 A: "a",
810 B: "b",
811 C: "c",
812 C1: "c1",
813 D1: "d1",
815 ExpectXML: `<top xmlns="space">` +
816 `<x><a>a</a><b>b</b><c xmlns="space">c</c>` +
817 `<c xmlns="space1">c1</c>` +
818 `<d xmlns="space1">d1</d>` +
819 `</x>` +
820 `</top>`,
823 Value: &struct {
824 XMLName Name
825 A string `xml:"x>a"`
826 B string `xml:"x>b"`
827 C string `xml:"space x>c"`
828 C1 string `xml:"space1 x>c"`
829 D1 string `xml:"space1 x>d"`
831 XMLName: Name{
832 Space: "space0",
833 Local: "top",
835 A: "a",
836 B: "b",
837 C: "c",
838 C1: "c1",
839 D1: "d1",
841 ExpectXML: `<top xmlns="space0">` +
842 `<x><a>a</a><b>b</b>` +
843 `<c xmlns="space">c</c>` +
844 `<c xmlns="space1">c1</c>` +
845 `<d xmlns="space1">d1</d>` +
846 `</x>` +
847 `</top>`,
850 Value: &struct {
851 XMLName struct{} `xml:"top"`
852 B string `xml:"space x>b"`
853 B1 string `xml:"space1 x>b"`
855 B: "b",
856 B1: "b1",
858 ExpectXML: `<top>` +
859 `<x><b xmlns="space">b</b>` +
860 `<b xmlns="space1">b1</b></x>` +
861 `</top>`,
864 // Test struct embedding
866 Value: &EmbedA{
867 EmbedC: EmbedC{
868 FieldA1: "", // Shadowed by A.A
869 FieldA2: "", // Shadowed by A.A
870 FieldB: "A.C.B",
871 FieldC: "A.C.C",
873 EmbedB: EmbedB{
874 FieldB: "A.B.B",
875 EmbedC: &EmbedC{
876 FieldA1: "A.B.C.A1",
877 FieldA2: "A.B.C.A2",
878 FieldB: "", // Shadowed by A.B.B
879 FieldC: "A.B.C.C",
882 FieldA: "A.A",
883 embedD: embedD{
884 FieldE: "A.D.E",
887 ExpectXML: `<EmbedA>` +
888 `<FieldB>A.C.B</FieldB>` +
889 `<FieldC>A.C.C</FieldC>` +
890 `<EmbedB>` +
891 `<FieldB>A.B.B</FieldB>` +
892 `<FieldA>` +
893 `<A1>A.B.C.A1</A1>` +
894 `<A2>A.B.C.A2</A2>` +
895 `</FieldA>` +
896 `<FieldC>A.B.C.C</FieldC>` +
897 `</EmbedB>` +
898 `<FieldA>A.A</FieldA>` +
899 `<FieldE>A.D.E</FieldE>` +
900 `</EmbedA>`,
903 // Test that name casing matters
905 Value: &NameCasing{Xy: "mixed", XY: "upper", XyA: "mixedA", XYA: "upperA"},
906 ExpectXML: `<casing Xy="mixedA" XY="upperA"><Xy>mixed</Xy><XY>upper</XY></casing>`,
909 // Test the order in which the XML element name is chosen
911 Value: &NamePrecedence{
912 FromTag: XMLNameWithoutTag{Value: "A"},
913 FromNameVal: XMLNameWithoutTag{XMLName: Name{Local: "InXMLName"}, Value: "B"},
914 FromNameTag: XMLNameWithTag{Value: "C"},
915 InFieldName: "D",
917 ExpectXML: `<Parent>` +
918 `<InTag>A</InTag>` +
919 `<InXMLName>B</InXMLName>` +
920 `<InXMLNameTag>C</InXMLNameTag>` +
921 `<InFieldName>D</InFieldName>` +
922 `</Parent>`,
923 MarshalOnly: true,
926 Value: &NamePrecedence{
927 XMLName: Name{Local: "Parent"},
928 FromTag: XMLNameWithoutTag{XMLName: Name{Local: "InTag"}, Value: "A"},
929 FromNameVal: XMLNameWithoutTag{XMLName: Name{Local: "FromNameVal"}, Value: "B"},
930 FromNameTag: XMLNameWithTag{XMLName: Name{Local: "InXMLNameTag"}, Value: "C"},
931 InFieldName: "D",
933 ExpectXML: `<Parent>` +
934 `<InTag>A</InTag>` +
935 `<FromNameVal>B</FromNameVal>` +
936 `<InXMLNameTag>C</InXMLNameTag>` +
937 `<InFieldName>D</InFieldName>` +
938 `</Parent>`,
939 UnmarshalOnly: true,
942 // xml.Name works in a plain field as well.
944 Value: &NameInField{Name{Space: "ns", Local: "foo"}},
945 ExpectXML: `<NameInField><foo xmlns="ns"></foo></NameInField>`,
948 Value: &NameInField{Name{Space: "ns", Local: "foo"}},
949 ExpectXML: `<NameInField><foo xmlns="ns"><ignore></ignore></foo></NameInField>`,
950 UnmarshalOnly: true,
953 // Marshaling zero xml.Name uses the tag or field name.
955 Value: &NameInField{},
956 ExpectXML: `<NameInField><foo xmlns="ns"></foo></NameInField>`,
957 MarshalOnly: true,
960 // Test attributes
962 Value: &AttrTest{
963 Int: 8,
964 Named: 9,
965 Float: 23.5,
966 Uint8: 255,
967 Bool: true,
968 Str: "str",
969 Bytes: []byte("byt"),
971 ExpectXML: `<AttrTest Int="8" int="9" Float="23.5" Uint8="255"` +
972 ` Bool="true" Str="str" Bytes="byt"></AttrTest>`,
975 Value: &AttrTest{Bytes: []byte{}},
976 ExpectXML: `<AttrTest Int="0" int="0" Float="0" Uint8="0"` +
977 ` Bool="false" Str="" Bytes=""></AttrTest>`,
980 Value: &AttrsTest{
981 Attrs: []Attr{
982 {Name: Name{Local: "Answer"}, Value: "42"},
983 {Name: Name{Local: "Int"}, Value: "8"},
984 {Name: Name{Local: "int"}, Value: "9"},
985 {Name: Name{Local: "Float"}, Value: "23.5"},
986 {Name: Name{Local: "Uint8"}, Value: "255"},
987 {Name: Name{Local: "Bool"}, Value: "true"},
988 {Name: Name{Local: "Str"}, Value: "str"},
989 {Name: Name{Local: "Bytes"}, Value: "byt"},
992 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>`,
993 MarshalOnly: true,
996 Value: &AttrsTest{
997 Attrs: []Attr{
998 {Name: Name{Local: "Answer"}, Value: "42"},
1000 Int: 8,
1001 Named: 9,
1002 Float: 23.5,
1003 Uint8: 255,
1004 Bool: true,
1005 Str: "str",
1006 Bytes: []byte("byt"),
1008 ExpectXML: `<AttrsTest Answer="42" Int="8" int="9" Float="23.5" Uint8="255" Bool="true" Str="str" Bytes="byt"></AttrsTest>`,
1011 Value: &AttrsTest{
1012 Attrs: []Attr{
1013 {Name: Name{Local: "Int"}, Value: "0"},
1014 {Name: Name{Local: "int"}, Value: "0"},
1015 {Name: Name{Local: "Float"}, Value: "0"},
1016 {Name: Name{Local: "Uint8"}, Value: "0"},
1017 {Name: Name{Local: "Bool"}, Value: "false"},
1018 {Name: Name{Local: "Str"}},
1019 {Name: Name{Local: "Bytes"}},
1021 Bytes: []byte{},
1023 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>`,
1024 MarshalOnly: true,
1027 Value: &OmitAttrTest{
1028 Int: 8,
1029 Named: 9,
1030 Float: 23.5,
1031 Uint8: 255,
1032 Bool: true,
1033 Str: "str",
1034 Bytes: []byte("byt"),
1035 PStr: &empty,
1037 ExpectXML: `<OmitAttrTest Int="8" int="9" Float="23.5" Uint8="255"` +
1038 ` Bool="true" Str="str" Bytes="byt" PStr=""></OmitAttrTest>`,
1041 Value: &OmitAttrTest{},
1042 ExpectXML: `<OmitAttrTest></OmitAttrTest>`,
1045 // pointer fields
1047 Value: &PointerFieldsTest{Name: &nameAttr, Age: &ageAttr, Contents: &contentsAttr},
1048 ExpectXML: `<dummy name="Sarah" age="12">lorem ipsum</dummy>`,
1049 MarshalOnly: true,
1052 // empty chardata pointer field
1054 Value: &ChardataEmptyTest{},
1055 ExpectXML: `<test></test>`,
1056 MarshalOnly: true,
1059 // omitempty on fields
1061 Value: &OmitFieldTest{
1062 Int: 8,
1063 Named: 9,
1064 Float: 23.5,
1065 Uint8: 255,
1066 Bool: true,
1067 Str: "str",
1068 Bytes: []byte("byt"),
1069 PStr: &empty,
1070 Ptr: &PresenceTest{},
1072 ExpectXML: `<OmitFieldTest>` +
1073 `<Int>8</Int>` +
1074 `<int>9</int>` +
1075 `<Float>23.5</Float>` +
1076 `<Uint8>255</Uint8>` +
1077 `<Bool>true</Bool>` +
1078 `<Str>str</Str>` +
1079 `<Bytes>byt</Bytes>` +
1080 `<PStr></PStr>` +
1081 `<Ptr></Ptr>` +
1082 `</OmitFieldTest>`,
1085 Value: &OmitFieldTest{},
1086 ExpectXML: `<OmitFieldTest></OmitFieldTest>`,
1089 // Test ",any"
1091 ExpectXML: `<a><nested><value>known</value></nested><other><sub>unknown</sub></other></a>`,
1092 Value: &AnyTest{
1093 Nested: "known",
1094 AnyField: AnyHolder{
1095 XMLName: Name{Local: "other"},
1096 XML: "<sub>unknown</sub>",
1101 Value: &AnyTest{Nested: "known",
1102 AnyField: AnyHolder{
1103 XML: "<unknown/>",
1104 XMLName: Name{Local: "AnyField"},
1107 ExpectXML: `<a><nested><value>known</value></nested><AnyField><unknown/></AnyField></a>`,
1110 ExpectXML: `<a><nested><value>b</value></nested></a>`,
1111 Value: &AnyOmitTest{
1112 Nested: "b",
1116 ExpectXML: `<a><nested><value>b</value></nested><c><d>e</d></c><g xmlns="f"><h>i</h></g></a>`,
1117 Value: &AnySliceTest{
1118 Nested: "b",
1119 AnyField: []AnyHolder{
1121 XMLName: Name{Local: "c"},
1122 XML: "<d>e</d>",
1125 XMLName: Name{Space: "f", Local: "g"},
1126 XML: "<h>i</h>",
1132 ExpectXML: `<a><nested><value>b</value></nested></a>`,
1133 Value: &AnySliceTest{
1134 Nested: "b",
1138 // Test recursive types.
1140 Value: &RecurseA{
1141 A: "a1",
1142 B: &RecurseB{
1143 A: &RecurseA{"a2", nil},
1144 B: "b1",
1147 ExpectXML: `<RecurseA><A>a1</A><B><A><A>a2</A></A><B>b1</B></B></RecurseA>`,
1150 // Test ignoring fields via "-" tag
1152 ExpectXML: `<IgnoreTest></IgnoreTest>`,
1153 Value: &IgnoreTest{},
1156 ExpectXML: `<IgnoreTest></IgnoreTest>`,
1157 Value: &IgnoreTest{PublicSecret: "can't tell"},
1158 MarshalOnly: true,
1161 ExpectXML: `<IgnoreTest><PublicSecret>ignore me</PublicSecret></IgnoreTest>`,
1162 Value: &IgnoreTest{},
1163 UnmarshalOnly: true,
1166 // Test escaping.
1168 ExpectXML: `<a><nested><value>dquote: &#34;; squote: &#39;; ampersand: &amp;; less: &lt;; greater: &gt;;</value></nested><empty></empty></a>`,
1169 Value: &AnyTest{
1170 Nested: `dquote: "; squote: '; ampersand: &; less: <; greater: >;`,
1171 AnyField: AnyHolder{XMLName: Name{Local: "empty"}},
1175 ExpectXML: `<a><nested><value>newline: &#xA;; cr: &#xD;; tab: &#x9;;</value></nested><AnyField></AnyField></a>`,
1176 Value: &AnyTest{
1177 Nested: "newline: \n; cr: \r; tab: \t;",
1178 AnyField: AnyHolder{XMLName: Name{Local: "AnyField"}},
1182 ExpectXML: "<a><nested><value>1\r2\r\n3\n\r4\n5</value></nested></a>",
1183 Value: &AnyTest{
1184 Nested: "1\n2\n3\n\n4\n5",
1186 UnmarshalOnly: true,
1189 ExpectXML: `<EmbedInt><MyInt>42</MyInt></EmbedInt>`,
1190 Value: &EmbedInt{
1191 MyInt: 42,
1194 // Test outputting CDATA-wrapped text.
1196 ExpectXML: `<CDataTest></CDataTest>`,
1197 Value: &CDataTest{},
1200 ExpectXML: `<CDataTest><![CDATA[http://example.com/tests/1?foo=1&bar=baz]]></CDataTest>`,
1201 Value: &CDataTest{
1202 Chardata: "http://example.com/tests/1?foo=1&bar=baz",
1206 ExpectXML: `<CDataTest><![CDATA[Literal <![CDATA[Nested]]]]><![CDATA[>!]]></CDataTest>`,
1207 Value: &CDataTest{
1208 Chardata: "Literal <![CDATA[Nested]]>!",
1212 ExpectXML: `<CDataTest><![CDATA[<![CDATA[Nested]]]]><![CDATA[> Literal!]]></CDataTest>`,
1213 Value: &CDataTest{
1214 Chardata: "<![CDATA[Nested]]> Literal!",
1218 ExpectXML: `<CDataTest><![CDATA[<![CDATA[Nested]]]]><![CDATA[> Literal! <![CDATA[Nested]]]]><![CDATA[> Literal!]]></CDataTest>`,
1219 Value: &CDataTest{
1220 Chardata: "<![CDATA[Nested]]> Literal! <![CDATA[Nested]]> Literal!",
1224 ExpectXML: `<CDataTest><![CDATA[<![CDATA[<![CDATA[Nested]]]]><![CDATA[>]]]]><![CDATA[>]]></CDataTest>`,
1225 Value: &CDataTest{
1226 Chardata: "<![CDATA[<![CDATA[Nested]]>]]>",
1230 // Test omitempty with parent chain; see golang.org/issue/4168.
1232 ExpectXML: `<Strings><A></A></Strings>`,
1233 Value: &Strings{},
1235 // Custom marshalers.
1237 ExpectXML: `<MyMarshalerTest>hello world</MyMarshalerTest>`,
1238 Value: &MyMarshalerTest{},
1241 ExpectXML: `<MarshalerStruct Foo="hello world"></MarshalerStruct>`,
1242 Value: &MarshalerStruct{},
1245 ExpectXML: `<outer xmlns="testns" int="10"></outer>`,
1246 Value: &OuterStruct{IntAttr: 10},
1249 ExpectXML: `<test xmlns="outerns" int="10"></test>`,
1250 Value: &OuterNamedStruct{XMLName: Name{Space: "outerns", Local: "test"}, IntAttr: 10},
1253 ExpectXML: `<test xmlns="outerns" int="10"></test>`,
1254 Value: &OuterNamedOrderedStruct{XMLName: Name{Space: "outerns", Local: "test"}, IntAttr: 10},
1257 ExpectXML: `<outer xmlns="testns" int="10"></outer>`,
1258 Value: &OuterOuterStruct{OuterStruct{IntAttr: 10}},
1261 ExpectXML: `<NestedAndChardata><A><B></B><B></B></A>test</NestedAndChardata>`,
1262 Value: &NestedAndChardata{AB: make([]string, 2), Chardata: "test"},
1265 ExpectXML: `<NestedAndComment><A><B></B><B></B></A><!--test--></NestedAndComment>`,
1266 Value: &NestedAndComment{AB: make([]string, 2), Comment: "test"},
1269 ExpectXML: `<NestedAndCData><A><B></B><B></B></A><![CDATA[test]]></NestedAndCData>`,
1270 Value: &NestedAndCData{AB: make([]string, 2), CDATA: "test"},
1272 // Test pointer indirection in various kinds of fields.
1273 // https://golang.org/issue/19063
1275 ExpectXML: `<IndirComment><T1></T1><!--hi--><T2></T2></IndirComment>`,
1276 Value: &IndirComment{Comment: stringptr("hi")},
1277 MarshalOnly: true,
1280 ExpectXML: `<IndirComment><T1></T1><T2></T2></IndirComment>`,
1281 Value: &IndirComment{Comment: stringptr("")},
1282 MarshalOnly: true,
1285 ExpectXML: `<IndirComment><T1></T1><T2></T2></IndirComment>`,
1286 Value: &IndirComment{Comment: nil},
1287 MarshalError: "xml: bad type for comment field of xml.IndirComment",
1290 ExpectXML: `<IndirComment><T1></T1><!--hi--><T2></T2></IndirComment>`,
1291 Value: &IndirComment{Comment: nil},
1292 UnmarshalOnly: true,
1295 ExpectXML: `<IfaceComment><T1></T1><!--hi--><T2></T2></IfaceComment>`,
1296 Value: &IfaceComment{Comment: "hi"},
1297 MarshalOnly: true,
1300 ExpectXML: `<IfaceComment><T1></T1><!--hi--><T2></T2></IfaceComment>`,
1301 Value: &IfaceComment{Comment: nil},
1302 UnmarshalOnly: true,
1305 ExpectXML: `<IfaceComment><T1></T1><T2></T2></IfaceComment>`,
1306 Value: &IfaceComment{Comment: nil},
1307 MarshalError: "xml: bad type for comment field of xml.IfaceComment",
1310 ExpectXML: `<IfaceComment><T1></T1><T2></T2></IfaceComment>`,
1311 Value: &IfaceComment{Comment: nil},
1312 UnmarshalOnly: true,
1315 ExpectXML: `<DirectComment><T1></T1><!--hi--><T2></T2></DirectComment>`,
1316 Value: &DirectComment{Comment: string("hi")},
1319 ExpectXML: `<DirectComment><T1></T1><T2></T2></DirectComment>`,
1320 Value: &DirectComment{Comment: string("")},
1323 ExpectXML: `<IndirChardata><T1></T1>hi<T2></T2></IndirChardata>`,
1324 Value: &IndirChardata{Chardata: stringptr("hi")},
1327 ExpectXML: `<IndirChardata><T1></T1><![CDATA[hi]]><T2></T2></IndirChardata>`,
1328 Value: &IndirChardata{Chardata: stringptr("hi")},
1329 UnmarshalOnly: true, // marshals without CDATA
1332 ExpectXML: `<IndirChardata><T1></T1><T2></T2></IndirChardata>`,
1333 Value: &IndirChardata{Chardata: stringptr("")},
1336 ExpectXML: `<IndirChardata><T1></T1><T2></T2></IndirChardata>`,
1337 Value: &IndirChardata{Chardata: nil},
1338 MarshalOnly: true, // unmarshal leaves Chardata=stringptr("")
1341 ExpectXML: `<IfaceChardata><T1></T1>hi<T2></T2></IfaceChardata>`,
1342 Value: &IfaceChardata{Chardata: string("hi")},
1343 UnmarshalError: "cannot unmarshal into interface {}",
1346 ExpectXML: `<IfaceChardata><T1></T1><![CDATA[hi]]><T2></T2></IfaceChardata>`,
1347 Value: &IfaceChardata{Chardata: string("hi")},
1348 UnmarshalOnly: true, // marshals without CDATA
1349 UnmarshalError: "cannot unmarshal into interface {}",
1352 ExpectXML: `<IfaceChardata><T1></T1><T2></T2></IfaceChardata>`,
1353 Value: &IfaceChardata{Chardata: string("")},
1354 UnmarshalError: "cannot unmarshal into interface {}",
1357 ExpectXML: `<IfaceChardata><T1></T1><T2></T2></IfaceChardata>`,
1358 Value: &IfaceChardata{Chardata: nil},
1359 UnmarshalError: "cannot unmarshal into interface {}",
1362 ExpectXML: `<DirectChardata><T1></T1>hi<T2></T2></DirectChardata>`,
1363 Value: &DirectChardata{Chardata: string("hi")},
1366 ExpectXML: `<DirectChardata><T1></T1><![CDATA[hi]]><T2></T2></DirectChardata>`,
1367 Value: &DirectChardata{Chardata: string("hi")},
1368 UnmarshalOnly: true, // marshals without CDATA
1371 ExpectXML: `<DirectChardata><T1></T1><T2></T2></DirectChardata>`,
1372 Value: &DirectChardata{Chardata: string("")},
1375 ExpectXML: `<IndirCDATA><T1></T1><![CDATA[hi]]><T2></T2></IndirCDATA>`,
1376 Value: &IndirCDATA{CDATA: stringptr("hi")},
1379 ExpectXML: `<IndirCDATA><T1></T1>hi<T2></T2></IndirCDATA>`,
1380 Value: &IndirCDATA{CDATA: stringptr("hi")},
1381 UnmarshalOnly: true, // marshals with CDATA
1384 ExpectXML: `<IndirCDATA><T1></T1><T2></T2></IndirCDATA>`,
1385 Value: &IndirCDATA{CDATA: stringptr("")},
1388 ExpectXML: `<IndirCDATA><T1></T1><T2></T2></IndirCDATA>`,
1389 Value: &IndirCDATA{CDATA: nil},
1390 MarshalOnly: true, // unmarshal leaves CDATA=stringptr("")
1393 ExpectXML: `<IfaceCDATA><T1></T1><![CDATA[hi]]><T2></T2></IfaceCDATA>`,
1394 Value: &IfaceCDATA{CDATA: string("hi")},
1395 UnmarshalError: "cannot unmarshal into interface {}",
1398 ExpectXML: `<IfaceCDATA><T1></T1>hi<T2></T2></IfaceCDATA>`,
1399 Value: &IfaceCDATA{CDATA: string("hi")},
1400 UnmarshalOnly: true, // marshals with CDATA
1401 UnmarshalError: "cannot unmarshal into interface {}",
1404 ExpectXML: `<IfaceCDATA><T1></T1><T2></T2></IfaceCDATA>`,
1405 Value: &IfaceCDATA{CDATA: string("")},
1406 UnmarshalError: "cannot unmarshal into interface {}",
1409 ExpectXML: `<IfaceCDATA><T1></T1><T2></T2></IfaceCDATA>`,
1410 Value: &IfaceCDATA{CDATA: nil},
1411 UnmarshalError: "cannot unmarshal into interface {}",
1414 ExpectXML: `<DirectCDATA><T1></T1><![CDATA[hi]]><T2></T2></DirectCDATA>`,
1415 Value: &DirectCDATA{CDATA: string("hi")},
1418 ExpectXML: `<DirectCDATA><T1></T1>hi<T2></T2></DirectCDATA>`,
1419 Value: &DirectCDATA{CDATA: string("hi")},
1420 UnmarshalOnly: true, // marshals with CDATA
1423 ExpectXML: `<DirectCDATA><T1></T1><T2></T2></DirectCDATA>`,
1424 Value: &DirectCDATA{CDATA: string("")},
1427 ExpectXML: `<IndirInnerXML><T1></T1><hi/><T2></T2></IndirInnerXML>`,
1428 Value: &IndirInnerXML{InnerXML: stringptr("<hi/>")},
1429 MarshalOnly: true,
1432 ExpectXML: `<IndirInnerXML><T1></T1><T2></T2></IndirInnerXML>`,
1433 Value: &IndirInnerXML{InnerXML: stringptr("")},
1434 MarshalOnly: true,
1437 ExpectXML: `<IndirInnerXML><T1></T1><T2></T2></IndirInnerXML>`,
1438 Value: &IndirInnerXML{InnerXML: nil},
1441 ExpectXML: `<IndirInnerXML><T1></T1><hi/><T2></T2></IndirInnerXML>`,
1442 Value: &IndirInnerXML{InnerXML: nil},
1443 UnmarshalOnly: true,
1446 ExpectXML: `<IfaceInnerXML><T1></T1><hi/><T2></T2></IfaceInnerXML>`,
1447 Value: &IfaceInnerXML{InnerXML: "<hi/>"},
1448 MarshalOnly: true,
1451 ExpectXML: `<IfaceInnerXML><T1></T1><hi/><T2></T2></IfaceInnerXML>`,
1452 Value: &IfaceInnerXML{InnerXML: nil},
1453 UnmarshalOnly: true,
1456 ExpectXML: `<IfaceInnerXML><T1></T1><T2></T2></IfaceInnerXML>`,
1457 Value: &IfaceInnerXML{InnerXML: nil},
1460 ExpectXML: `<IfaceInnerXML><T1></T1><T2></T2></IfaceInnerXML>`,
1461 Value: &IfaceInnerXML{InnerXML: nil},
1462 UnmarshalOnly: true,
1465 ExpectXML: `<DirectInnerXML><T1></T1><hi/><T2></T2></DirectInnerXML>`,
1466 Value: &DirectInnerXML{InnerXML: string("<hi/>")},
1467 MarshalOnly: true,
1470 ExpectXML: `<DirectInnerXML><T1></T1><hi/><T2></T2></DirectInnerXML>`,
1471 Value: &DirectInnerXML{InnerXML: string("<T1></T1><hi/><T2></T2>")},
1472 UnmarshalOnly: true,
1475 ExpectXML: `<DirectInnerXML><T1></T1><T2></T2></DirectInnerXML>`,
1476 Value: &DirectInnerXML{InnerXML: string("")},
1477 MarshalOnly: true,
1480 ExpectXML: `<DirectInnerXML><T1></T1><T2></T2></DirectInnerXML>`,
1481 Value: &DirectInnerXML{InnerXML: string("<T1></T1><T2></T2>")},
1482 UnmarshalOnly: true,
1485 ExpectXML: `<IndirElement><T1></T1><Element>hi</Element><T2></T2></IndirElement>`,
1486 Value: &IndirElement{Element: stringptr("hi")},
1489 ExpectXML: `<IndirElement><T1></T1><Element></Element><T2></T2></IndirElement>`,
1490 Value: &IndirElement{Element: stringptr("")},
1493 ExpectXML: `<IndirElement><T1></T1><T2></T2></IndirElement>`,
1494 Value: &IndirElement{Element: nil},
1497 ExpectXML: `<IfaceElement><T1></T1><Element>hi</Element><T2></T2></IfaceElement>`,
1498 Value: &IfaceElement{Element: "hi"},
1499 MarshalOnly: true,
1502 ExpectXML: `<IfaceElement><T1></T1><Element>hi</Element><T2></T2></IfaceElement>`,
1503 Value: &IfaceElement{Element: nil},
1504 UnmarshalOnly: true,
1507 ExpectXML: `<IfaceElement><T1></T1><T2></T2></IfaceElement>`,
1508 Value: &IfaceElement{Element: nil},
1511 ExpectXML: `<IfaceElement><T1></T1><T2></T2></IfaceElement>`,
1512 Value: &IfaceElement{Element: nil},
1513 UnmarshalOnly: true,
1516 ExpectXML: `<DirectElement><T1></T1><Element>hi</Element><T2></T2></DirectElement>`,
1517 Value: &DirectElement{Element: string("hi")},
1520 ExpectXML: `<DirectElement><T1></T1><Element></Element><T2></T2></DirectElement>`,
1521 Value: &DirectElement{Element: string("")},
1524 ExpectXML: `<IndirOmitEmpty><T1></T1><OmitEmpty>hi</OmitEmpty><T2></T2></IndirOmitEmpty>`,
1525 Value: &IndirOmitEmpty{OmitEmpty: stringptr("hi")},
1528 // Note: Changed in Go 1.8 to include <OmitEmpty> element (because x.OmitEmpty != nil).
1529 ExpectXML: `<IndirOmitEmpty><T1></T1><OmitEmpty></OmitEmpty><T2></T2></IndirOmitEmpty>`,
1530 Value: &IndirOmitEmpty{OmitEmpty: stringptr("")},
1531 MarshalOnly: true,
1534 ExpectXML: `<IndirOmitEmpty><T1></T1><OmitEmpty></OmitEmpty><T2></T2></IndirOmitEmpty>`,
1535 Value: &IndirOmitEmpty{OmitEmpty: stringptr("")},
1536 UnmarshalOnly: true,
1539 ExpectXML: `<IndirOmitEmpty><T1></T1><T2></T2></IndirOmitEmpty>`,
1540 Value: &IndirOmitEmpty{OmitEmpty: nil},
1543 ExpectXML: `<IfaceOmitEmpty><T1></T1><OmitEmpty>hi</OmitEmpty><T2></T2></IfaceOmitEmpty>`,
1544 Value: &IfaceOmitEmpty{OmitEmpty: "hi"},
1545 MarshalOnly: true,
1548 ExpectXML: `<IfaceOmitEmpty><T1></T1><OmitEmpty>hi</OmitEmpty><T2></T2></IfaceOmitEmpty>`,
1549 Value: &IfaceOmitEmpty{OmitEmpty: nil},
1550 UnmarshalOnly: true,
1553 ExpectXML: `<IfaceOmitEmpty><T1></T1><T2></T2></IfaceOmitEmpty>`,
1554 Value: &IfaceOmitEmpty{OmitEmpty: nil},
1557 ExpectXML: `<IfaceOmitEmpty><T1></T1><T2></T2></IfaceOmitEmpty>`,
1558 Value: &IfaceOmitEmpty{OmitEmpty: nil},
1559 UnmarshalOnly: true,
1562 ExpectXML: `<DirectOmitEmpty><T1></T1><OmitEmpty>hi</OmitEmpty><T2></T2></DirectOmitEmpty>`,
1563 Value: &DirectOmitEmpty{OmitEmpty: string("hi")},
1566 ExpectXML: `<DirectOmitEmpty><T1></T1><T2></T2></DirectOmitEmpty>`,
1567 Value: &DirectOmitEmpty{OmitEmpty: string("")},
1570 ExpectXML: `<IndirAny><T1></T1><Any>hi</Any><T2></T2></IndirAny>`,
1571 Value: &IndirAny{Any: stringptr("hi")},
1574 ExpectXML: `<IndirAny><T1></T1><Any></Any><T2></T2></IndirAny>`,
1575 Value: &IndirAny{Any: stringptr("")},
1578 ExpectXML: `<IndirAny><T1></T1><T2></T2></IndirAny>`,
1579 Value: &IndirAny{Any: nil},
1582 ExpectXML: `<IfaceAny><T1></T1><Any>hi</Any><T2></T2></IfaceAny>`,
1583 Value: &IfaceAny{Any: "hi"},
1584 MarshalOnly: true,
1587 ExpectXML: `<IfaceAny><T1></T1><Any>hi</Any><T2></T2></IfaceAny>`,
1588 Value: &IfaceAny{Any: nil},
1589 UnmarshalOnly: true,
1592 ExpectXML: `<IfaceAny><T1></T1><T2></T2></IfaceAny>`,
1593 Value: &IfaceAny{Any: nil},
1596 ExpectXML: `<IfaceAny><T1></T1><T2></T2></IfaceAny>`,
1597 Value: &IfaceAny{Any: nil},
1598 UnmarshalOnly: true,
1601 ExpectXML: `<DirectAny><T1></T1><Any>hi</Any><T2></T2></DirectAny>`,
1602 Value: &DirectAny{Any: string("hi")},
1605 ExpectXML: `<DirectAny><T1></T1><Any></Any><T2></T2></DirectAny>`,
1606 Value: &DirectAny{Any: string("")},
1609 ExpectXML: `<IndirFoo><T1></T1><Foo>hi</Foo><T2></T2></IndirFoo>`,
1610 Value: &IndirAny{Any: stringptr("hi")},
1611 UnmarshalOnly: true,
1614 ExpectXML: `<IndirFoo><T1></T1><Foo></Foo><T2></T2></IndirFoo>`,
1615 Value: &IndirAny{Any: stringptr("")},
1616 UnmarshalOnly: true,
1619 ExpectXML: `<IndirFoo><T1></T1><T2></T2></IndirFoo>`,
1620 Value: &IndirAny{Any: nil},
1621 UnmarshalOnly: true,
1624 ExpectXML: `<IfaceFoo><T1></T1><Foo>hi</Foo><T2></T2></IfaceFoo>`,
1625 Value: &IfaceAny{Any: nil},
1626 UnmarshalOnly: true,
1629 ExpectXML: `<IfaceFoo><T1></T1><T2></T2></IfaceFoo>`,
1630 Value: &IfaceAny{Any: nil},
1631 UnmarshalOnly: true,
1634 ExpectXML: `<IfaceFoo><T1></T1><T2></T2></IfaceFoo>`,
1635 Value: &IfaceAny{Any: nil},
1636 UnmarshalOnly: true,
1639 ExpectXML: `<DirectFoo><T1></T1><Foo>hi</Foo><T2></T2></DirectFoo>`,
1640 Value: &DirectAny{Any: string("hi")},
1641 UnmarshalOnly: true,
1644 ExpectXML: `<DirectFoo><T1></T1><Foo></Foo><T2></T2></DirectFoo>`,
1645 Value: &DirectAny{Any: string("")},
1646 UnmarshalOnly: true,
1650 func TestMarshal(t *testing.T) {
1651 for idx, test := range marshalTests {
1652 if test.UnmarshalOnly {
1653 continue
1656 t.Run(fmt.Sprintf("%d", idx), func(t *testing.T) {
1657 data, err := Marshal(test.Value)
1658 if err != nil {
1659 if test.MarshalError == "" {
1660 t.Errorf("marshal(%#v): %s", test.Value, err)
1661 return
1663 if !strings.Contains(err.Error(), test.MarshalError) {
1664 t.Errorf("marshal(%#v): %s, want %q", test.Value, err, test.MarshalError)
1666 return
1668 if test.MarshalError != "" {
1669 t.Errorf("Marshal succeeded, want error %q", test.MarshalError)
1670 return
1672 if got, want := string(data), test.ExpectXML; got != want {
1673 if strings.Contains(want, "\n") {
1674 t.Errorf("marshal(%#v):\nHAVE:\n%s\nWANT:\n%s", test.Value, got, want)
1675 } else {
1676 t.Errorf("marshal(%#v):\nhave %#q\nwant %#q", test.Value, got, want)
1683 type AttrParent struct {
1684 X string `xml:"X>Y,attr"`
1687 type BadAttr struct {
1688 Name map[string]string `xml:"name,attr"`
1691 var marshalErrorTests = []struct {
1692 Value interface{}
1693 Err string
1694 Kind reflect.Kind
1697 Value: make(chan bool),
1698 Err: "xml: unsupported type: chan bool",
1699 Kind: reflect.Chan,
1702 Value: map[string]string{
1703 "question": "What do you get when you multiply six by nine?",
1704 "answer": "42",
1706 Err: "xml: unsupported type: map[string]string",
1707 Kind: reflect.Map,
1710 Value: map[*Ship]bool{nil: false},
1711 Err: "xml: unsupported type: map[*xml.Ship]bool",
1712 Kind: reflect.Map,
1715 Value: &Domain{Comment: []byte("f--bar")},
1716 Err: `xml: comments must not contain "--"`,
1718 // Reject parent chain with attr, never worked; see golang.org/issue/5033.
1720 Value: &AttrParent{},
1721 Err: `xml: X>Y chain not valid with attr flag`,
1724 Value: BadAttr{map[string]string{"X": "Y"}},
1725 Err: `xml: unsupported type: map[string]string`,
1729 var marshalIndentTests = []struct {
1730 Value interface{}
1731 Prefix string
1732 Indent string
1733 ExpectXML string
1736 Value: &SecretAgent{
1737 Handle: "007",
1738 Identity: "James Bond",
1739 Obfuscate: "<redacted/>",
1741 Prefix: "",
1742 Indent: "\t",
1743 ExpectXML: fmt.Sprintf("<agent handle=\"007\">\n\t<Identity>James Bond</Identity><redacted/>\n</agent>"),
1747 func TestMarshalErrors(t *testing.T) {
1748 for idx, test := range marshalErrorTests {
1749 data, err := Marshal(test.Value)
1750 if err == nil {
1751 t.Errorf("#%d: marshal(%#v) = [success] %q, want error %v", idx, test.Value, data, test.Err)
1752 continue
1754 if err.Error() != test.Err {
1755 t.Errorf("#%d: marshal(%#v) = [error] %v, want %v", idx, test.Value, err, test.Err)
1757 if test.Kind != reflect.Invalid {
1758 if kind := err.(*UnsupportedTypeError).Type.Kind(); kind != test.Kind {
1759 t.Errorf("#%d: marshal(%#v) = [error kind] %s, want %s", idx, test.Value, kind, test.Kind)
1765 // Do invertibility testing on the various structures that we test
1766 func TestUnmarshal(t *testing.T) {
1767 for i, test := range marshalTests {
1768 if test.MarshalOnly {
1769 continue
1771 if _, ok := test.Value.(*Plain); ok {
1772 continue
1774 if test.ExpectXML == `<top>`+
1775 `<x><b xmlns="space">b</b>`+
1776 `<b xmlns="space1">b1</b></x>`+
1777 `</top>` {
1778 // TODO(rogpeppe): re-enable this test in
1779 // https://go-review.googlesource.com/#/c/5910/
1780 continue
1783 vt := reflect.TypeOf(test.Value)
1784 dest := reflect.New(vt.Elem()).Interface()
1785 err := Unmarshal([]byte(test.ExpectXML), dest)
1787 t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
1788 switch fix := dest.(type) {
1789 case *Feed:
1790 fix.Author.InnerXML = ""
1791 for i := range fix.Entry {
1792 fix.Entry[i].Author.InnerXML = ""
1796 if err != nil {
1797 if test.UnmarshalError == "" {
1798 t.Errorf("unmarshal(%#v): %s", test.ExpectXML, err)
1799 return
1801 if !strings.Contains(err.Error(), test.UnmarshalError) {
1802 t.Errorf("unmarshal(%#v): %s, want %q", test.ExpectXML, err, test.UnmarshalError)
1804 return
1806 if got, want := dest, test.Value; !reflect.DeepEqual(got, want) {
1807 t.Errorf("unmarshal(%q):\nhave %#v\nwant %#v", test.ExpectXML, got, want)
1813 func TestMarshalIndent(t *testing.T) {
1814 for i, test := range marshalIndentTests {
1815 data, err := MarshalIndent(test.Value, test.Prefix, test.Indent)
1816 if err != nil {
1817 t.Errorf("#%d: Error: %s", i, err)
1818 continue
1820 if got, want := string(data), test.ExpectXML; got != want {
1821 t.Errorf("#%d: MarshalIndent:\nGot:%s\nWant:\n%s", i, got, want)
1826 type limitedBytesWriter struct {
1827 w io.Writer
1828 remain int // until writes fail
1831 func (lw *limitedBytesWriter) Write(p []byte) (n int, err error) {
1832 if lw.remain <= 0 {
1833 println("error")
1834 return 0, errors.New("write limit hit")
1836 if len(p) > lw.remain {
1837 p = p[:lw.remain]
1838 n, _ = lw.w.Write(p)
1839 lw.remain = 0
1840 return n, errors.New("write limit hit")
1842 n, err = lw.w.Write(p)
1843 lw.remain -= n
1844 return n, err
1847 func TestMarshalWriteErrors(t *testing.T) {
1848 var buf bytes.Buffer
1849 const writeCap = 1024
1850 w := &limitedBytesWriter{&buf, writeCap}
1851 enc := NewEncoder(w)
1852 var err error
1853 var i int
1854 const n = 4000
1855 for i = 1; i <= n; i++ {
1856 err = enc.Encode(&Passenger{
1857 Name: []string{"Alice", "Bob"},
1858 Weight: 5,
1860 if err != nil {
1861 break
1864 if err == nil {
1865 t.Error("expected an error")
1867 if i == n {
1868 t.Errorf("expected to fail before the end")
1870 if buf.Len() != writeCap {
1871 t.Errorf("buf.Len() = %d; want %d", buf.Len(), writeCap)
1875 func TestMarshalWriteIOErrors(t *testing.T) {
1876 enc := NewEncoder(errWriter{})
1878 expectErr := "unwritable"
1879 err := enc.Encode(&Passenger{})
1880 if err == nil || err.Error() != expectErr {
1881 t.Errorf("EscapeTest = [error] %v, want %v", err, expectErr)
1885 func TestMarshalFlush(t *testing.T) {
1886 var buf bytes.Buffer
1887 enc := NewEncoder(&buf)
1888 if err := enc.EncodeToken(CharData("hello world")); err != nil {
1889 t.Fatalf("enc.EncodeToken: %v", err)
1891 if buf.Len() > 0 {
1892 t.Fatalf("enc.EncodeToken caused actual write: %q", buf.Bytes())
1894 if err := enc.Flush(); err != nil {
1895 t.Fatalf("enc.Flush: %v", err)
1897 if buf.String() != "hello world" {
1898 t.Fatalf("after enc.Flush, buf.String() = %q, want %q", buf.String(), "hello world")
1902 func BenchmarkMarshal(b *testing.B) {
1903 b.ReportAllocs()
1904 b.RunParallel(func(pb *testing.PB) {
1905 for pb.Next() {
1906 Marshal(atomValue)
1911 func BenchmarkUnmarshal(b *testing.B) {
1912 b.ReportAllocs()
1913 xml := []byte(atomXml)
1914 b.RunParallel(func(pb *testing.PB) {
1915 for pb.Next() {
1916 Unmarshal(xml, &Feed{})
1921 // golang.org/issue/6556
1922 func TestStructPointerMarshal(t *testing.T) {
1923 type A struct {
1924 XMLName string `xml:"a"`
1925 B []interface{}
1927 type C struct {
1928 XMLName Name
1929 Value string `xml:"value"`
1932 a := new(A)
1933 a.B = append(a.B, &C{
1934 XMLName: Name{Local: "c"},
1935 Value: "x",
1938 b, err := Marshal(a)
1939 if err != nil {
1940 t.Fatal(err)
1942 if x := string(b); x != "<a><c><value>x</value></c></a>" {
1943 t.Fatal(x)
1945 var v A
1946 err = Unmarshal(b, &v)
1947 if err != nil {
1948 t.Fatal(err)
1952 var encodeTokenTests = []struct {
1953 desc string
1954 toks []Token
1955 want string
1956 err string
1958 desc: "start element with name space",
1959 toks: []Token{
1960 StartElement{Name{"space", "local"}, nil},
1962 want: `<local xmlns="space">`,
1963 }, {
1964 desc: "start element with no name",
1965 toks: []Token{
1966 StartElement{Name{"space", ""}, nil},
1968 err: "xml: start tag with no name",
1969 }, {
1970 desc: "end element with no name",
1971 toks: []Token{
1972 EndElement{Name{"space", ""}},
1974 err: "xml: end tag with no name",
1975 }, {
1976 desc: "char data",
1977 toks: []Token{
1978 CharData("foo"),
1980 want: `foo`,
1981 }, {
1982 desc: "char data with escaped chars",
1983 toks: []Token{
1984 CharData(" \t\n"),
1986 want: " &#x9;\n",
1987 }, {
1988 desc: "comment",
1989 toks: []Token{
1990 Comment("foo"),
1992 want: `<!--foo-->`,
1993 }, {
1994 desc: "comment with invalid content",
1995 toks: []Token{
1996 Comment("foo-->"),
1998 err: "xml: EncodeToken of Comment containing --> marker",
1999 }, {
2000 desc: "proc instruction",
2001 toks: []Token{
2002 ProcInst{"Target", []byte("Instruction")},
2004 want: `<?Target Instruction?>`,
2005 }, {
2006 desc: "proc instruction with empty target",
2007 toks: []Token{
2008 ProcInst{"", []byte("Instruction")},
2010 err: "xml: EncodeToken of ProcInst with invalid Target",
2011 }, {
2012 desc: "proc instruction with bad content",
2013 toks: []Token{
2014 ProcInst{"", []byte("Instruction?>")},
2016 err: "xml: EncodeToken of ProcInst with invalid Target",
2017 }, {
2018 desc: "directive",
2019 toks: []Token{
2020 Directive("foo"),
2022 want: `<!foo>`,
2023 }, {
2024 desc: "more complex directive",
2025 toks: []Token{
2026 Directive("DOCTYPE doc [ <!ELEMENT doc '>'> <!-- com>ment --> ]"),
2028 want: `<!DOCTYPE doc [ <!ELEMENT doc '>'> <!-- com>ment --> ]>`,
2029 }, {
2030 desc: "directive instruction with bad name",
2031 toks: []Token{
2032 Directive("foo>"),
2034 err: "xml: EncodeToken of Directive containing wrong < or > markers",
2035 }, {
2036 desc: "end tag without start tag",
2037 toks: []Token{
2038 EndElement{Name{"foo", "bar"}},
2040 err: "xml: end tag </bar> without start tag",
2041 }, {
2042 desc: "mismatching end tag local name",
2043 toks: []Token{
2044 StartElement{Name{"", "foo"}, nil},
2045 EndElement{Name{"", "bar"}},
2047 err: "xml: end tag </bar> does not match start tag <foo>",
2048 want: `<foo>`,
2049 }, {
2050 desc: "mismatching end tag namespace",
2051 toks: []Token{
2052 StartElement{Name{"space", "foo"}, nil},
2053 EndElement{Name{"another", "foo"}},
2055 err: "xml: end tag </foo> in namespace another does not match start tag <foo> in namespace space",
2056 want: `<foo xmlns="space">`,
2057 }, {
2058 desc: "start element with explicit namespace",
2059 toks: []Token{
2060 StartElement{Name{"space", "local"}, []Attr{
2061 {Name{"xmlns", "x"}, "space"},
2062 {Name{"space", "foo"}, "value"},
2065 want: `<local xmlns="space" xmlns:_xmlns="xmlns" _xmlns:x="space" xmlns:space="space" space:foo="value">`,
2066 }, {
2067 desc: "start element with explicit namespace and colliding prefix",
2068 toks: []Token{
2069 StartElement{Name{"space", "local"}, []Attr{
2070 {Name{"xmlns", "x"}, "space"},
2071 {Name{"space", "foo"}, "value"},
2072 {Name{"x", "bar"}, "other"},
2075 want: `<local xmlns="space" xmlns:_xmlns="xmlns" _xmlns:x="space" xmlns:space="space" space:foo="value" xmlns:x="x" x:bar="other">`,
2076 }, {
2077 desc: "start element using previously defined namespace",
2078 toks: []Token{
2079 StartElement{Name{"", "local"}, []Attr{
2080 {Name{"xmlns", "x"}, "space"},
2082 StartElement{Name{"space", "foo"}, []Attr{
2083 {Name{"space", "x"}, "y"},
2086 want: `<local xmlns:_xmlns="xmlns" _xmlns:x="space"><foo xmlns="space" xmlns:space="space" space:x="y">`,
2087 }, {
2088 desc: "nested name space with same prefix",
2089 toks: []Token{
2090 StartElement{Name{"", "foo"}, []Attr{
2091 {Name{"xmlns", "x"}, "space1"},
2093 StartElement{Name{"", "foo"}, []Attr{
2094 {Name{"xmlns", "x"}, "space2"},
2096 StartElement{Name{"", "foo"}, []Attr{
2097 {Name{"space1", "a"}, "space1 value"},
2098 {Name{"space2", "b"}, "space2 value"},
2100 EndElement{Name{"", "foo"}},
2101 EndElement{Name{"", "foo"}},
2102 StartElement{Name{"", "foo"}, []Attr{
2103 {Name{"space1", "a"}, "space1 value"},
2104 {Name{"space2", "b"}, "space2 value"},
2107 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">`,
2108 }, {
2109 desc: "start element defining several prefixes for the same name space",
2110 toks: []Token{
2111 StartElement{Name{"space", "foo"}, []Attr{
2112 {Name{"xmlns", "a"}, "space"},
2113 {Name{"xmlns", "b"}, "space"},
2114 {Name{"space", "x"}, "value"},
2117 want: `<foo xmlns="space" xmlns:_xmlns="xmlns" _xmlns:a="space" _xmlns:b="space" xmlns:space="space" space:x="value">`,
2118 }, {
2119 desc: "nested element redefines name space",
2120 toks: []Token{
2121 StartElement{Name{"", "foo"}, []Attr{
2122 {Name{"xmlns", "x"}, "space"},
2124 StartElement{Name{"space", "foo"}, []Attr{
2125 {Name{"xmlns", "y"}, "space"},
2126 {Name{"space", "a"}, "value"},
2129 want: `<foo xmlns:_xmlns="xmlns" _xmlns:x="space"><foo xmlns="space" _xmlns:y="space" xmlns:space="space" space:a="value">`,
2130 }, {
2131 desc: "nested element creates alias for default name space",
2132 toks: []Token{
2133 StartElement{Name{"space", "foo"}, []Attr{
2134 {Name{"", "xmlns"}, "space"},
2136 StartElement{Name{"space", "foo"}, []Attr{
2137 {Name{"xmlns", "y"}, "space"},
2138 {Name{"space", "a"}, "value"},
2141 want: `<foo xmlns="space" xmlns="space"><foo xmlns="space" xmlns:_xmlns="xmlns" _xmlns:y="space" xmlns:space="space" space:a="value">`,
2142 }, {
2143 desc: "nested element defines default name space with existing prefix",
2144 toks: []Token{
2145 StartElement{Name{"", "foo"}, []Attr{
2146 {Name{"xmlns", "x"}, "space"},
2148 StartElement{Name{"space", "foo"}, []Attr{
2149 {Name{"", "xmlns"}, "space"},
2150 {Name{"space", "a"}, "value"},
2153 want: `<foo xmlns:_xmlns="xmlns" _xmlns:x="space"><foo xmlns="space" xmlns="space" xmlns:space="space" space:a="value">`,
2154 }, {
2155 desc: "nested element uses empty attribute name space when default ns defined",
2156 toks: []Token{
2157 StartElement{Name{"space", "foo"}, []Attr{
2158 {Name{"", "xmlns"}, "space"},
2160 StartElement{Name{"space", "foo"}, []Attr{
2161 {Name{"", "attr"}, "value"},
2164 want: `<foo xmlns="space" xmlns="space"><foo xmlns="space" attr="value">`,
2165 }, {
2166 desc: "redefine xmlns",
2167 toks: []Token{
2168 StartElement{Name{"", "foo"}, []Attr{
2169 {Name{"foo", "xmlns"}, "space"},
2172 want: `<foo xmlns:foo="foo" foo:xmlns="space">`,
2173 }, {
2174 desc: "xmlns with explicit name space #1",
2175 toks: []Token{
2176 StartElement{Name{"space", "foo"}, []Attr{
2177 {Name{"xml", "xmlns"}, "space"},
2180 want: `<foo xmlns="space" xmlns:_xml="xml" _xml:xmlns="space">`,
2181 }, {
2182 desc: "xmlns with explicit name space #2",
2183 toks: []Token{
2184 StartElement{Name{"space", "foo"}, []Attr{
2185 {Name{xmlURL, "xmlns"}, "space"},
2188 want: `<foo xmlns="space" xml:xmlns="space">`,
2189 }, {
2190 desc: "empty name space declaration is ignored",
2191 toks: []Token{
2192 StartElement{Name{"", "foo"}, []Attr{
2193 {Name{"xmlns", "foo"}, ""},
2196 want: `<foo xmlns:_xmlns="xmlns" _xmlns:foo="">`,
2197 }, {
2198 desc: "attribute with no name is ignored",
2199 toks: []Token{
2200 StartElement{Name{"", "foo"}, []Attr{
2201 {Name{"", ""}, "value"},
2204 want: `<foo>`,
2205 }, {
2206 desc: "namespace URL with non-valid name",
2207 toks: []Token{
2208 StartElement{Name{"/34", "foo"}, []Attr{
2209 {Name{"/34", "x"}, "value"},
2212 want: `<foo xmlns="/34" xmlns:_="/34" _:x="value">`,
2213 }, {
2214 desc: "nested element resets default namespace to empty",
2215 toks: []Token{
2216 StartElement{Name{"space", "foo"}, []Attr{
2217 {Name{"", "xmlns"}, "space"},
2219 StartElement{Name{"", "foo"}, []Attr{
2220 {Name{"", "xmlns"}, ""},
2221 {Name{"", "x"}, "value"},
2222 {Name{"space", "x"}, "value"},
2225 want: `<foo xmlns="space" xmlns="space"><foo xmlns="" x="value" xmlns:space="space" space:x="value">`,
2226 }, {
2227 desc: "nested element requires empty default name space",
2228 toks: []Token{
2229 StartElement{Name{"space", "foo"}, []Attr{
2230 {Name{"", "xmlns"}, "space"},
2232 StartElement{Name{"", "foo"}, nil},
2234 want: `<foo xmlns="space" xmlns="space"><foo>`,
2235 }, {
2236 desc: "attribute uses name space from xmlns",
2237 toks: []Token{
2238 StartElement{Name{"some/space", "foo"}, []Attr{
2239 {Name{"", "attr"}, "value"},
2240 {Name{"some/space", "other"}, "other value"},
2243 want: `<foo xmlns="some/space" attr="value" xmlns:space="some/space" space:other="other value">`,
2244 }, {
2245 desc: "default name space should not be used by attributes",
2246 toks: []Token{
2247 StartElement{Name{"space", "foo"}, []Attr{
2248 {Name{"", "xmlns"}, "space"},
2249 {Name{"xmlns", "bar"}, "space"},
2250 {Name{"space", "baz"}, "foo"},
2252 StartElement{Name{"space", "baz"}, nil},
2253 EndElement{Name{"space", "baz"}},
2254 EndElement{Name{"space", "foo"}},
2256 want: `<foo xmlns="space" xmlns="space" xmlns:_xmlns="xmlns" _xmlns:bar="space" xmlns:space="space" space:baz="foo"><baz xmlns="space"></baz></foo>`,
2257 }, {
2258 desc: "default name space not used by attributes, not explicitly defined",
2259 toks: []Token{
2260 StartElement{Name{"space", "foo"}, []Attr{
2261 {Name{"", "xmlns"}, "space"},
2262 {Name{"space", "baz"}, "foo"},
2264 StartElement{Name{"space", "baz"}, nil},
2265 EndElement{Name{"space", "baz"}},
2266 EndElement{Name{"space", "foo"}},
2268 want: `<foo xmlns="space" xmlns="space" xmlns:space="space" space:baz="foo"><baz xmlns="space"></baz></foo>`,
2269 }, {
2270 desc: "impossible xmlns declaration",
2271 toks: []Token{
2272 StartElement{Name{"", "foo"}, []Attr{
2273 {Name{"", "xmlns"}, "space"},
2275 StartElement{Name{"space", "bar"}, []Attr{
2276 {Name{"space", "attr"}, "value"},
2279 want: `<foo xmlns="space"><bar xmlns="space" xmlns:space="space" space:attr="value">`,
2282 func TestEncodeToken(t *testing.T) {
2283 loop:
2284 for i, tt := range encodeTokenTests {
2285 var buf bytes.Buffer
2286 enc := NewEncoder(&buf)
2287 var err error
2288 for j, tok := range tt.toks {
2289 err = enc.EncodeToken(tok)
2290 if err != nil && j < len(tt.toks)-1 {
2291 t.Errorf("#%d %s token #%d: %v", i, tt.desc, j, err)
2292 continue loop
2295 errorf := func(f string, a ...interface{}) {
2296 t.Errorf("#%d %s token #%d:%s", i, tt.desc, len(tt.toks)-1, fmt.Sprintf(f, a...))
2298 switch {
2299 case tt.err != "" && err == nil:
2300 errorf(" expected error; got none")
2301 continue
2302 case tt.err == "" && err != nil:
2303 errorf(" got error: %v", err)
2304 continue
2305 case tt.err != "" && err != nil && tt.err != err.Error():
2306 errorf(" error mismatch; got %v, want %v", err, tt.err)
2307 continue
2309 if err := enc.Flush(); err != nil {
2310 errorf(" %v", err)
2311 continue
2313 if got := buf.String(); got != tt.want {
2314 errorf("\ngot %v\nwant %v", got, tt.want)
2315 continue
2320 func TestProcInstEncodeToken(t *testing.T) {
2321 var buf bytes.Buffer
2322 enc := NewEncoder(&buf)
2324 if err := enc.EncodeToken(ProcInst{"xml", []byte("Instruction")}); err != nil {
2325 t.Fatalf("enc.EncodeToken: expected to be able to encode xml target ProcInst as first token, %s", err)
2328 if err := enc.EncodeToken(ProcInst{"Target", []byte("Instruction")}); err != nil {
2329 t.Fatalf("enc.EncodeToken: expected to be able to add non-xml target ProcInst")
2332 if err := enc.EncodeToken(ProcInst{"xml", []byte("Instruction")}); err == nil {
2333 t.Fatalf("enc.EncodeToken: expected to not be allowed to encode xml target ProcInst when not first token")
2337 func TestDecodeEncode(t *testing.T) {
2338 var in, out bytes.Buffer
2339 in.WriteString(`<?xml version="1.0" encoding="UTF-8"?>
2340 <?Target Instruction?>
2341 <root>
2342 </root>
2344 dec := NewDecoder(&in)
2345 enc := NewEncoder(&out)
2346 for tok, err := dec.Token(); err == nil; tok, err = dec.Token() {
2347 err = enc.EncodeToken(tok)
2348 if err != nil {
2349 t.Fatalf("enc.EncodeToken: Unable to encode token (%#v), %v", tok, err)
2354 // Issue 9796. Used to fail with GORACE="halt_on_error=1" -race.
2355 func TestRace9796(t *testing.T) {
2356 type A struct{}
2357 type B struct {
2358 C []A `xml:"X>Y"`
2360 var wg sync.WaitGroup
2361 for i := 0; i < 2; i++ {
2362 wg.Add(1)
2363 go func() {
2364 Marshal(B{[]A{{}}})
2365 wg.Done()
2368 wg.Wait()
2371 func TestIsValidDirective(t *testing.T) {
2372 testOK := []string{
2373 "<>",
2374 "< < > >",
2375 "<!DOCTYPE '<' '>' '>' <!--nothing-->>",
2376 "<!DOCTYPE doc [ <!ELEMENT doc ANY> <!ELEMENT doc ANY> ]>",
2377 "<!DOCTYPE doc [ <!ELEMENT doc \"ANY> '<' <!E\" LEMENT '>' doc ANY> ]>",
2378 "<!DOCTYPE doc <!-- just>>>> a < comment --> [ <!ITEM anything> ] >",
2380 testKO := []string{
2381 "<",
2382 ">",
2383 "<!--",
2384 "-->",
2385 "< > > < < >",
2386 "<!dummy <!-- > -->",
2387 "<!DOCTYPE doc '>",
2388 "<!DOCTYPE doc '>'",
2389 "<!DOCTYPE doc <!--comment>",
2391 for _, s := range testOK {
2392 if !isValidDirective(Directive(s)) {
2393 t.Errorf("Directive %q is expected to be valid", s)
2396 for _, s := range testKO {
2397 if isValidDirective(Directive(s)) {
2398 t.Errorf("Directive %q is expected to be invalid", s)
2403 // Issue 11719. EncodeToken used to silently eat tokens with an invalid type.
2404 func TestSimpleUseOfEncodeToken(t *testing.T) {
2405 var buf bytes.Buffer
2406 enc := NewEncoder(&buf)
2407 if err := enc.EncodeToken(&StartElement{Name: Name{"", "object1"}}); err == nil {
2408 t.Errorf("enc.EncodeToken: pointer type should be rejected")
2410 if err := enc.EncodeToken(&EndElement{Name: Name{"", "object1"}}); err == nil {
2411 t.Errorf("enc.EncodeToken: pointer type should be rejected")
2413 if err := enc.EncodeToken(StartElement{Name: Name{"", "object2"}}); err != nil {
2414 t.Errorf("enc.EncodeToken: StartElement %s", err)
2416 if err := enc.EncodeToken(EndElement{Name: Name{"", "object2"}}); err != nil {
2417 t.Errorf("enc.EncodeToken: EndElement %s", err)
2419 if err := enc.EncodeToken(Universe{}); err == nil {
2420 t.Errorf("enc.EncodeToken: invalid type not caught")
2422 if err := enc.Flush(); err != nil {
2423 t.Errorf("enc.Flush: %s", err)
2425 if buf.Len() == 0 {
2426 t.Errorf("enc.EncodeToken: empty buffer")
2428 want := "<object2></object2>"
2429 if buf.String() != want {
2430 t.Errorf("enc.EncodeToken: expected %q; got %q", want, buf.String())
2434 // Issue 16158. Decoder.unmarshalAttr ignores the return value of copyValue.
2435 func TestIssue16158(t *testing.T) {
2436 const data = `<foo b="HELLOWORLD"></foo>`
2437 err := Unmarshal([]byte(data), &struct {
2438 B byte `xml:"b,attr,omitempty"`
2439 }{})
2440 if err == nil {
2441 t.Errorf("Unmarshal: expected error, got nil")