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.
23 HyperDrive DriveType = iota
27 type Passenger struct {
28 Name []string `xml:"name"`
29 Weight float32 `xml:"weight"`
33 XMLName struct{} `xml:"spaceship"`
35 Name string `xml:"name,attr"`
36 Pilot string `xml:"pilot,attr"`
37 Drive DriveType `xml:"drive"`
39 Passenger []*Passenger `xml:"passenger"`
46 XMLName struct{} `xml:"port"`
47 Type string `xml:"type,attr,omitempty"`
48 Comment string `xml:",comment"`
49 Number string `xml:",chardata"`
53 XMLName struct{} `xml:"domain"`
54 Country string `xml:",attr,omitempty"`
55 Name []byte `xml:",chardata"`
56 Comment []byte `xml:",comment"`
60 XMLName struct{} `xml:"book"`
61 Title string `xml:",chardata"`
65 XMLName struct{} `xml:"event"`
66 Year int `xml:",chardata"`
70 XMLName struct{} `xml:"movie"`
71 Length uint `xml:",chardata"`
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"`
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"`
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"`
133 Extra2 interface{} `xml:"host>extra2"`
150 FieldA1 string `xml:"FieldA>A1"`
151 FieldA2 string `xml:"FieldA>A2"`
156 type NameCasing struct {
157 XMLName struct{} `xml:"casing"`
160 XyA string `xml:"Xy,attr"`
161 XYA string `xml:"XY,attr"`
164 type NamePrecedence struct {
165 XMLName Name `xml:"Parent"`
166 FromTag XMLNameWithoutTag `xml:"InTag"`
167 FromNameVal XMLNameWithoutTag
168 FromNameTag XMLNameWithTag
172 type XMLNameWithTag struct {
173 XMLName Name `xml:"InXMLNameTag"`
174 Value string `xml:",chardata"`
177 type XMLNameWithNSTag struct {
178 XMLName Name `xml:"ns InXMLNameWithNSTag"`
179 Value string `xml:",chardata"`
182 type XMLNameWithoutTag struct {
184 Value string `xml:",chardata"`
187 type NameInField struct {
188 Foo Name `xml:"ns foo"`
191 type AttrTest struct {
192 Int int `xml:",attr"`
193 Named int `xml:"int,attr"`
194 Float float64 `xml:",attr"`
195 Uint8 uint8 `xml:",attr"`
196 Bool bool `xml:",attr"`
197 Str string `xml:",attr"`
198 Bytes []byte `xml:",attr"`
201 type OmitAttrTest struct {
202 Int int `xml:",attr,omitempty"`
203 Named int `xml:"int,attr,omitempty"`
204 Float float64 `xml:",attr,omitempty"`
205 Uint8 uint8 `xml:",attr,omitempty"`
206 Bool bool `xml:",attr,omitempty"`
207 Str string `xml:",attr,omitempty"`
208 Bytes []byte `xml:",attr,omitempty"`
211 type OmitFieldTest struct {
212 Int int `xml:",omitempty"`
213 Named int `xml:"int,omitempty"`
214 Float float64 `xml:",omitempty"`
215 Uint8 uint8 `xml:",omitempty"`
216 Bool bool `xml:",omitempty"`
217 Str string `xml:",omitempty"`
218 Bytes []byte `xml:",omitempty"`
219 Ptr *PresenceTest `xml:",omitempty"`
222 type AnyTest struct {
223 XMLName struct{} `xml:"a"`
224 Nested string `xml:"nested>value"`
225 AnyField AnyHolder `xml:",any"`
228 type AnyOmitTest struct {
229 XMLName struct{} `xml:"a"`
230 Nested string `xml:"nested>value"`
231 AnyField *AnyHolder `xml:",any,omitempty"`
234 type AnySliceTest struct {
235 XMLName struct{} `xml:"a"`
236 Nested string `xml:"nested>value"`
237 AnyField []AnyHolder `xml:",any"`
240 type AnyHolder struct {
242 XML string `xml:",innerxml"`
245 type RecurseA struct {
250 type RecurseB struct {
255 type PresenceTest struct {
259 type IgnoreTest struct {
260 PublicSecret string `xml:"-"`
267 Attr []byte `xml:",attr"`
277 type EmbedInt struct {
281 type Strings struct {
282 X []string `xml:"A>B,omitempty"`
285 type PointerFieldsTest struct {
286 XMLName Name `xml:"dummy"`
287 Name *string `xml:"name,attr"`
288 Age *uint `xml:"age,attr"`
289 Empty *string `xml:"empty,attr"`
290 Contents *string `xml:",chardata"`
293 type ChardataEmptyTest struct {
294 XMLName Name `xml:"test"`
295 Contents *string `xml:",chardata"`
298 type MyMarshalerTest struct {
301 var _ Marshaler = (*MyMarshalerTest)(nil)
303 func (m *MyMarshalerTest) MarshalXML(e *Encoder, start StartElement) error {
305 e.EncodeToken(CharData([]byte("hello world")))
306 e.EncodeToken(EndElement{start.Name})
310 type MyMarshalerAttrTest struct{}
312 var _ MarshalerAttr = (*MyMarshalerAttrTest)(nil)
314 func (m *MyMarshalerAttrTest) MarshalXMLAttr(name Name) (Attr, error) {
315 return Attr{name, "hello world"}, nil
318 type MyMarshalerValueAttrTest struct{}
320 var _ MarshalerAttr = MyMarshalerValueAttrTest{}
322 func (m MyMarshalerValueAttrTest) MarshalXMLAttr(name Name) (Attr, error) {
323 return Attr{name, "hello world"}, nil
326 type MarshalerStruct struct {
327 Foo MyMarshalerAttrTest `xml:",attr"`
330 type MarshalerValueStruct struct {
331 Foo MyMarshalerValueAttrTest `xml:",attr"`
334 type InnerStruct struct {
335 XMLName Name `xml:"testns outer"`
338 type OuterStruct struct {
340 IntAttr int `xml:"int,attr"`
343 type OuterNamedStruct struct {
345 XMLName Name `xml:"outerns test"`
346 IntAttr int `xml:"int,attr"`
349 type OuterNamedOrderedStruct struct {
350 XMLName Name `xml:"outerns test"`
352 IntAttr int `xml:"int,attr"`
355 type OuterOuterStruct struct {
359 type NestedAndChardata struct {
360 AB []string `xml:"A>B"`
361 Chardata string `xml:",chardata"`
364 type NestedAndComment struct {
365 AB []string `xml:"A>B"`
366 Comment string `xml:",comment"`
369 type XMLNSFieldStruct struct {
370 Ns string `xml:"xmlns,attr"`
374 type NamedXMLNSFieldStruct struct {
375 XMLName struct{} `xml:"testns test"`
376 Ns string `xml:"xmlns,attr"`
380 type XMLNSFieldStructWithOmitEmpty struct {
381 Ns string `xml:"xmlns,attr,omitempty"`
385 type NamedXMLNSFieldStructWithEmptyNamespace struct {
386 XMLName struct{} `xml:"test"`
387 Ns string `xml:"xmlns,attr"`
391 type RecursiveXMLNSFieldStruct struct {
392 Ns string `xml:"xmlns,attr"`
393 Body *RecursiveXMLNSFieldStruct `xml:",omitempty"`
394 Text string `xml:",omitempty"`
397 func ifaceptr(x interface{}) interface{} {
404 contentsAttr = "lorem ipsum"
407 // Unless explicitly stated as such (or *Plain), all of the
408 // tests below are two-way tests. When introducing new tests,
409 // please try to make them two-way as well to ensure that
410 // marshalling and unmarshalling are as symmetrical as feasible.
411 var marshalTests = []struct {
417 // Test nil marshals to nothing
418 {Value: nil, ExpectXML: ``, MarshalOnly: true},
419 {Value: nilStruct, ExpectXML: ``, MarshalOnly: true},
422 {Value: &Plain{true}, ExpectXML: `<Plain><V>true</V></Plain>`},
423 {Value: &Plain{false}, ExpectXML: `<Plain><V>false</V></Plain>`},
424 {Value: &Plain{int(42)}, ExpectXML: `<Plain><V>42</V></Plain>`},
425 {Value: &Plain{int8(42)}, ExpectXML: `<Plain><V>42</V></Plain>`},
426 {Value: &Plain{int16(42)}, ExpectXML: `<Plain><V>42</V></Plain>`},
427 {Value: &Plain{int32(42)}, ExpectXML: `<Plain><V>42</V></Plain>`},
428 {Value: &Plain{uint(42)}, ExpectXML: `<Plain><V>42</V></Plain>`},
429 {Value: &Plain{uint8(42)}, ExpectXML: `<Plain><V>42</V></Plain>`},
430 {Value: &Plain{uint16(42)}, ExpectXML: `<Plain><V>42</V></Plain>`},
431 {Value: &Plain{uint32(42)}, ExpectXML: `<Plain><V>42</V></Plain>`},
432 {Value: &Plain{float32(1.25)}, ExpectXML: `<Plain><V>1.25</V></Plain>`},
433 {Value: &Plain{float64(1.25)}, ExpectXML: `<Plain><V>1.25</V></Plain>`},
434 {Value: &Plain{uintptr(0xFFDD)}, ExpectXML: `<Plain><V>65501</V></Plain>`},
435 {Value: &Plain{"gopher"}, ExpectXML: `<Plain><V>gopher</V></Plain>`},
436 {Value: &Plain{[]byte("gopher")}, ExpectXML: `<Plain><V>gopher</V></Plain>`},
437 {Value: &Plain{"</>"}, ExpectXML: `<Plain><V></></V></Plain>`},
438 {Value: &Plain{[]byte("</>")}, ExpectXML: `<Plain><V></></V></Plain>`},
439 {Value: &Plain{[3]byte{'<', '/', '>'}}, ExpectXML: `<Plain><V></></V></Plain>`},
440 {Value: &Plain{NamedType("potato")}, ExpectXML: `<Plain><V>potato</V></Plain>`},
441 {Value: &Plain{[]int{1, 2, 3}}, ExpectXML: `<Plain><V>1</V><V>2</V><V>3</V></Plain>`},
442 {Value: &Plain{[3]int{1, 2, 3}}, ExpectXML: `<Plain><V>1</V><V>2</V><V>3</V></Plain>`},
443 {Value: ifaceptr(true), MarshalOnly: true, ExpectXML: `<bool>true</bool>`},
447 Value: &Plain{time.Unix(1e9, 123456789).UTC()},
448 ExpectXML: `<Plain><V>2001-09-09T01:46:40.123456789Z</V></Plain>`,
451 // A pointer to struct{} may be used to test for an element's presence.
453 Value: &PresenceTest{new(struct{})},
454 ExpectXML: `<PresenceTest><Exists></Exists></PresenceTest>`,
457 Value: &PresenceTest{},
458 ExpectXML: `<PresenceTest></PresenceTest>`,
461 // A pointer to struct{} may be used to test for an element's presence.
463 Value: &PresenceTest{new(struct{})},
464 ExpectXML: `<PresenceTest><Exists></Exists></PresenceTest>`,
467 Value: &PresenceTest{},
468 ExpectXML: `<PresenceTest></PresenceTest>`,
471 // A []byte field is only nil if the element was not found.
474 ExpectXML: `<Data></Data>`,
478 Value: &Data{Bytes: []byte{}, Custom: MyBytes{}, Attr: []byte{}},
479 ExpectXML: `<Data Attr=""><Bytes></Bytes><Custom></Custom></Data>`,
483 // Check that []byte works, including named []byte types.
485 Value: &Data{Bytes: []byte("ab"), Custom: MyBytes("cd"), Attr: []byte{'v'}},
486 ExpectXML: `<Data Attr="v"><Bytes>ab</Bytes><Custom>cd</Custom></Data>`,
493 Identity: "James Bond",
494 Obfuscate: "<redacted/>",
496 ExpectXML: `<agent handle="007"><Identity>James Bond</Identity><redacted/></agent>`,
502 Identity: "James Bond",
503 Obfuscate: "<Identity>James Bond</Identity><redacted/>",
505 ExpectXML: `<agent handle="007"><Identity>James Bond</Identity><redacted/></agent>`,
510 {Value: &Port{Type: "ssl", Number: "443"}, ExpectXML: `<port type="ssl">443</port>`},
511 {Value: &Port{Number: "443"}, ExpectXML: `<port>443</port>`},
512 {Value: &Port{Type: "<unix>"}, ExpectXML: `<port type="<unix>"></port>`},
513 {Value: &Port{Number: "443", Comment: "https"}, ExpectXML: `<port><!--https-->443</port>`},
514 {Value: &Port{Number: "443", Comment: "add space-"}, ExpectXML: `<port><!--add space- -->443</port>`, MarshalOnly: true},
515 {Value: &Domain{Name: []byte("google.com&friends")}, ExpectXML: `<domain>google.com&friends</domain>`},
516 {Value: &Domain{Name: []byte("google.com"), Comment: []byte(" &friends ")}, ExpectXML: `<domain>google.com<!-- &friends --></domain>`},
517 {Value: &Book{Title: "Pride & Prejudice"}, ExpectXML: `<book>Pride & Prejudice</book>`},
518 {Value: &Event{Year: -3114}, ExpectXML: `<event>-3114</event>`},
519 {Value: &Movie{Length: 13440}, ExpectXML: `<movie>13440</movie>`},
520 {Value: &Pi{Approximation: 3.14159265}, ExpectXML: `<pi>3.1415927</pi>`},
521 {Value: &Universe{Visible: 9.3e13}, ExpectXML: `<universe>9.3e+13</universe>`},
522 {Value: &Particle{HasMass: true}, ExpectXML: `<particle>true</particle>`},
523 {Value: &Departure{When: ParseTime("2013-01-09T00:15:00-09:00")}, ExpectXML: `<departure>2013-01-09T00:15:00-09:00</departure>`},
524 {Value: atomValue, ExpectXML: atomXml},
527 Name: "Heart of Gold",
530 Drive: ImprobabilityDrive,
531 Passenger: []*Passenger{
533 Name: []string{"Zaphod", "Beeblebrox"},
537 Name: []string{"Trisha", "McMillen"},
541 Name: []string{"Ford", "Prefect"},
545 Name: []string{"Arthur", "Dent"},
550 ExpectXML: `<spaceship name="Heart of Gold" pilot="Computer">` +
551 `<drive>` + strconv.Itoa(int(ImprobabilityDrive)) + `</drive>` +
554 `<name>Zaphod</name>` +
555 `<name>Beeblebrox</name>` +
556 `<weight>7.25</weight>` +
559 `<name>Trisha</name>` +
560 `<name>McMillen</name>` +
561 `<weight>5.5</weight>` +
564 `<name>Ford</name>` +
565 `<name>Prefect</name>` +
566 `<weight>7</weight>` +
569 `<name>Arthur</name>` +
570 `<name>Dent</name>` +
571 `<weight>6.75</weight>` +
578 Value: &NestedItems{Items: nil, Item1: nil},
579 ExpectXML: `<result>` +
585 Value: &NestedItems{Items: []string{}, Item1: []string{}},
586 ExpectXML: `<result>` +
593 Value: &NestedItems{Items: nil, Item1: []string{"A"}},
594 ExpectXML: `<result>` +
601 Value: &NestedItems{Items: []string{"A", "B"}, Item1: nil},
602 ExpectXML: `<result>` +
610 Value: &NestedItems{Items: []string{"A", "B"}, Item1: []string{"C"}},
611 ExpectXML: `<result>` +
620 Value: &NestedOrder{Field1: "C", Field2: "B", Field3: "A"},
621 ExpectXML: `<result>` +
630 Value: &NilTest{A: "A", B: nil, C: "C"},
631 ExpectXML: `<NilTest>` +
633 `<parent2><a>A</a></parent2>` +
634 `<parent2><c>C</c></parent2>` +
637 MarshalOnly: true, // Uses interface{}
640 Value: &MixedNested{A: "A", B: "B", C: "C", D: "D"},
641 ExpectXML: `<result>` +
642 `<parent1><a>A</a></parent1>` +
645 `<parent2><c>C</c></parent2>` +
651 Value: &Service{Port: &Port{Number: "80"}},
652 ExpectXML: `<service><host><port>80</port></host></service>`,
656 ExpectXML: `<service></service>`,
659 Value: &Service{Port: &Port{Number: "80"}, Extra1: "A", Extra2: "B"},
660 ExpectXML: `<service>` +
661 `<host><port>80</port></host>` +
662 `<Extra1>A</Extra1>` +
663 `<host><extra2>B</extra2></host>` +
668 Value: &Service{Port: &Port{Number: "80"}, Extra2: "example"},
669 ExpectXML: `<service>` +
670 `<host><port>80</port></host>` +
671 `<host><extra2>example</extra2></host>` +
677 XMLName struct{} `xml:"space top"`
680 C string `xml:"space x>c"`
681 C1 string `xml:"space1 x>c"`
682 D1 string `xml:"space1 x>d"`
683 E1 string `xml:"x>e"`
692 ExpectXML: `<top xmlns="space">` +
693 `<x><a>a</a><b>b</b><c>c</c></x>` +
694 `<x xmlns="space1">` +
708 C string `xml:"space x>c"`
709 C1 string `xml:"space1 x>c"`
710 D1 string `xml:"space1 x>d"`
722 ExpectXML: `<top xmlns="space0">` +
723 `<x><a>a</a><b>b</b></x>` +
724 `<x xmlns="space"><c>c</c></x>` +
725 `<x xmlns="space1">` +
733 XMLName struct{} `xml:"top"`
734 B string `xml:"space x>b"`
735 B1 string `xml:"space1 x>b"`
741 `<x xmlns="space"><b>b</b></x>` +
742 `<x xmlns="space1"><b>b1</b></x>` +
746 // Test struct embedding
750 FieldA1: "", // Shadowed by A.A
751 FieldA2: "", // Shadowed by A.A
760 FieldB: "", // Shadowed by A.B.B
766 ExpectXML: `<EmbedA>` +
767 `<FieldB>A.C.B</FieldB>` +
768 `<FieldC>A.C.C</FieldC>` +
770 `<FieldB>A.B.B</FieldB>` +
772 `<A1>A.B.C.A1</A1>` +
773 `<A2>A.B.C.A2</A2>` +
775 `<FieldC>A.B.C.C</FieldC>` +
777 `<FieldA>A.A</FieldA>` +
781 // Test that name casing matters
783 Value: &NameCasing{Xy: "mixed", XY: "upper", XyA: "mixedA", XYA: "upperA"},
784 ExpectXML: `<casing Xy="mixedA" XY="upperA"><Xy>mixed</Xy><XY>upper</XY></casing>`,
787 // Test the order in which the XML element name is chosen
789 Value: &NamePrecedence{
790 FromTag: XMLNameWithoutTag{Value: "A"},
791 FromNameVal: XMLNameWithoutTag{XMLName: Name{Local: "InXMLName"}, Value: "B"},
792 FromNameTag: XMLNameWithTag{Value: "C"},
795 ExpectXML: `<Parent>` +
797 `<InXMLName>B</InXMLName>` +
798 `<InXMLNameTag>C</InXMLNameTag>` +
799 `<InFieldName>D</InFieldName>` +
804 Value: &NamePrecedence{
805 XMLName: Name{Local: "Parent"},
806 FromTag: XMLNameWithoutTag{XMLName: Name{Local: "InTag"}, Value: "A"},
807 FromNameVal: XMLNameWithoutTag{XMLName: Name{Local: "FromNameVal"}, Value: "B"},
808 FromNameTag: XMLNameWithTag{XMLName: Name{Local: "InXMLNameTag"}, Value: "C"},
811 ExpectXML: `<Parent>` +
813 `<FromNameVal>B</FromNameVal>` +
814 `<InXMLNameTag>C</InXMLNameTag>` +
815 `<InFieldName>D</InFieldName>` +
820 // xml.Name works in a plain field as well.
822 Value: &NameInField{Name{Space: "ns", Local: "foo"}},
823 ExpectXML: `<NameInField><foo xmlns="ns"></foo></NameInField>`,
826 Value: &NameInField{Name{Space: "ns", Local: "foo"}},
827 ExpectXML: `<NameInField><foo xmlns="ns"><ignore></ignore></foo></NameInField>`,
831 // Marshaling zero xml.Name uses the tag or field name.
833 Value: &NameInField{},
834 ExpectXML: `<NameInField><foo xmlns="ns"></foo></NameInField>`,
847 Bytes: []byte("byt"),
849 ExpectXML: `<AttrTest Int="8" int="9" Float="23.5" Uint8="255"` +
850 ` Bool="true" Str="str" Bytes="byt"></AttrTest>`,
853 Value: &AttrTest{Bytes: []byte{}},
854 ExpectXML: `<AttrTest Int="0" int="0" Float="0" Uint8="0"` +
855 ` Bool="false" Str="" Bytes=""></AttrTest>`,
858 Value: &OmitAttrTest{
865 Bytes: []byte("byt"),
867 ExpectXML: `<OmitAttrTest Int="8" int="9" Float="23.5" Uint8="255"` +
868 ` Bool="true" Str="str" Bytes="byt"></OmitAttrTest>`,
871 Value: &OmitAttrTest{},
872 ExpectXML: `<OmitAttrTest></OmitAttrTest>`,
877 Value: &PointerFieldsTest{Name: &nameAttr, Age: &ageAttr, Contents: &contentsAttr},
878 ExpectXML: `<dummy name="Sarah" age="12">lorem ipsum</dummy>`,
882 // empty chardata pointer field
884 Value: &ChardataEmptyTest{},
885 ExpectXML: `<test></test>`,
889 // omitempty on fields
891 Value: &OmitFieldTest{
898 Bytes: []byte("byt"),
899 Ptr: &PresenceTest{},
901 ExpectXML: `<OmitFieldTest>` +
904 `<Float>23.5</Float>` +
905 `<Uint8>255</Uint8>` +
906 `<Bool>true</Bool>` +
908 `<Bytes>byt</Bytes>` +
913 Value: &OmitFieldTest{},
914 ExpectXML: `<OmitFieldTest></OmitFieldTest>`,
919 ExpectXML: `<a><nested><value>known</value></nested><other><sub>unknown</sub></other></a>`,
923 XMLName: Name{Local: "other"},
924 XML: "<sub>unknown</sub>",
929 Value: &AnyTest{Nested: "known",
932 XMLName: Name{Local: "AnyField"},
935 ExpectXML: `<a><nested><value>known</value></nested><AnyField><unknown/></AnyField></a>`,
938 ExpectXML: `<a><nested><value>b</value></nested></a>`,
944 ExpectXML: `<a><nested><value>b</value></nested><c><d>e</d></c><g xmlns="f"><h>i</h></g></a>`,
945 Value: &AnySliceTest{
947 AnyField: []AnyHolder{
949 XMLName: Name{Local: "c"},
953 XMLName: Name{Space: "f", Local: "g"},
960 ExpectXML: `<a><nested><value>b</value></nested></a>`,
961 Value: &AnySliceTest{
966 // Test recursive types.
971 A: &RecurseA{"a2", nil},
975 ExpectXML: `<RecurseA><A>a1</A><B><A><A>a2</A></A><B>b1</B></B></RecurseA>`,
978 // Test ignoring fields via "-" tag
980 ExpectXML: `<IgnoreTest></IgnoreTest>`,
981 Value: &IgnoreTest{},
984 ExpectXML: `<IgnoreTest></IgnoreTest>`,
985 Value: &IgnoreTest{PublicSecret: "can't tell"},
989 ExpectXML: `<IgnoreTest><PublicSecret>ignore me</PublicSecret></IgnoreTest>`,
990 Value: &IgnoreTest{},
996 ExpectXML: `<a><nested><value>dquote: "; squote: '; ampersand: &; less: <; greater: >;</value></nested><empty></empty></a>`,
998 Nested: `dquote: "; squote: '; ampersand: &; less: <; greater: >;`,
999 AnyField: AnyHolder{XMLName: Name{Local: "empty"}},
1003 ExpectXML: `<a><nested><value>newline: 
; cr: 
; tab: 	;</value></nested><AnyField></AnyField></a>`,
1005 Nested: "newline: \n; cr: \r; tab: \t;",
1006 AnyField: AnyHolder{XMLName: Name{Local: "AnyField"}},
1010 ExpectXML: "<a><nested><value>1\r2\r\n3\n\r4\n5</value></nested></a>",
1012 Nested: "1\n2\n3\n\n4\n5",
1014 UnmarshalOnly: true,
1017 ExpectXML: `<EmbedInt><MyInt>42</MyInt></EmbedInt>`,
1022 // Test omitempty with parent chain; see golang.org/issue/4168.
1024 ExpectXML: `<Strings><A></A></Strings>`,
1027 // Custom marshalers.
1029 ExpectXML: `<MyMarshalerTest>hello world</MyMarshalerTest>`,
1030 Value: &MyMarshalerTest{},
1033 ExpectXML: `<MarshalerStruct Foo="hello world"></MarshalerStruct>`,
1034 Value: &MarshalerStruct{},
1037 ExpectXML: `<MarshalerValueStruct Foo="hello world"></MarshalerValueStruct>`,
1038 Value: &MarshalerValueStruct{},
1041 ExpectXML: `<outer xmlns="testns" int="10"></outer>`,
1042 Value: &OuterStruct{IntAttr: 10},
1045 ExpectXML: `<test xmlns="outerns" int="10"></test>`,
1046 Value: &OuterNamedStruct{XMLName: Name{Space: "outerns", Local: "test"}, IntAttr: 10},
1049 ExpectXML: `<test xmlns="outerns" int="10"></test>`,
1050 Value: &OuterNamedOrderedStruct{XMLName: Name{Space: "outerns", Local: "test"}, IntAttr: 10},
1053 ExpectXML: `<outer xmlns="testns" int="10"></outer>`,
1054 Value: &OuterOuterStruct{OuterStruct{IntAttr: 10}},
1057 ExpectXML: `<NestedAndChardata><A><B></B><B></B></A>test</NestedAndChardata>`,
1058 Value: &NestedAndChardata{AB: make([]string, 2), Chardata: "test"},
1061 ExpectXML: `<NestedAndComment><A><B></B><B></B></A><!--test--></NestedAndComment>`,
1062 Value: &NestedAndComment{AB: make([]string, 2), Comment: "test"},
1065 ExpectXML: `<XMLNSFieldStruct xmlns="http://example.com/ns"><Body>hello world</Body></XMLNSFieldStruct>`,
1066 Value: &XMLNSFieldStruct{Ns: "http://example.com/ns", Body: "hello world"},
1069 ExpectXML: `<testns:test xmlns:testns="testns" xmlns="http://example.com/ns"><Body>hello world</Body></testns:test>`,
1070 Value: &NamedXMLNSFieldStruct{Ns: "http://example.com/ns", Body: "hello world"},
1073 ExpectXML: `<testns:test xmlns:testns="testns"><Body>hello world</Body></testns:test>`,
1074 Value: &NamedXMLNSFieldStruct{Ns: "", Body: "hello world"},
1077 ExpectXML: `<XMLNSFieldStructWithOmitEmpty><Body>hello world</Body></XMLNSFieldStructWithOmitEmpty>`,
1078 Value: &XMLNSFieldStructWithOmitEmpty{Body: "hello world"},
1081 // The xmlns attribute must be ignored because the <test>
1082 // element is in the empty namespace, so it's not possible
1083 // to set the default namespace to something non-empty.
1084 ExpectXML: `<test><Body>hello world</Body></test>`,
1085 Value: &NamedXMLNSFieldStructWithEmptyNamespace{Ns: "foo", Body: "hello world"},
1089 ExpectXML: `<RecursiveXMLNSFieldStruct xmlns="foo"><Body xmlns=""><Text>hello world</Text></Body></RecursiveXMLNSFieldStruct>`,
1090 Value: &RecursiveXMLNSFieldStruct{
1092 Body: &RecursiveXMLNSFieldStruct{
1093 Text: "hello world",
1099 func TestMarshal(t *testing.T) {
1100 for idx, test := range marshalTests {
1101 if test.UnmarshalOnly {
1104 data, err := Marshal(test.Value)
1106 t.Errorf("#%d: marshal(%#v): %s", idx, test.Value, err)
1109 if got, want := string(data), test.ExpectXML; got != want {
1110 if strings.Contains(want, "\n") {
1111 t.Errorf("#%d: marshal(%#v):\nHAVE:\n%s\nWANT:\n%s", idx, test.Value, got, want)
1113 t.Errorf("#%d: marshal(%#v):\nhave %#q\nwant %#q", idx, test.Value, got, want)
1119 type AttrParent struct {
1120 X string `xml:"X>Y,attr"`
1123 type BadAttr struct {
1124 Name []string `xml:"name,attr"`
1127 var marshalErrorTests = []struct {
1133 Value: make(chan bool),
1134 Err: "xml: unsupported type: chan bool",
1138 Value: map[string]string{
1139 "question": "What do you get when you multiply six by nine?",
1142 Err: "xml: unsupported type: map[string]string",
1146 Value: map[*Ship]bool{nil: false},
1147 Err: "xml: unsupported type: map[*xml.Ship]bool",
1151 Value: &Domain{Comment: []byte("f--bar")},
1152 Err: `xml: comments must not contain "--"`,
1154 // Reject parent chain with attr, never worked; see golang.org/issue/5033.
1156 Value: &AttrParent{},
1157 Err: `xml: X>Y chain not valid with attr flag`,
1160 Value: BadAttr{[]string{"X", "Y"}},
1161 Err: `xml: unsupported type: []string`,
1165 var marshalIndentTests = []struct {
1172 Value: &SecretAgent{
1174 Identity: "James Bond",
1175 Obfuscate: "<redacted/>",
1179 ExpectXML: fmt.Sprintf("<agent handle=\"007\">\n\t<Identity>James Bond</Identity><redacted/>\n</agent>"),
1183 func TestMarshalErrors(t *testing.T) {
1184 for idx, test := range marshalErrorTests {
1185 data, err := Marshal(test.Value)
1187 t.Errorf("#%d: marshal(%#v) = [success] %q, want error %v", idx, test.Value, data, test.Err)
1190 if err.Error() != test.Err {
1191 t.Errorf("#%d: marshal(%#v) = [error] %v, want %v", idx, test.Value, err, test.Err)
1193 if test.Kind != reflect.Invalid {
1194 if kind := err.(*UnsupportedTypeError).Type.Kind(); kind != test.Kind {
1195 t.Errorf("#%d: marshal(%#v) = [error kind] %s, want %s", idx, test.Value, kind, test.Kind)
1201 // Do invertibility testing on the various structures that we test
1202 func TestUnmarshal(t *testing.T) {
1203 for i, test := range marshalTests {
1204 if test.MarshalOnly {
1207 if _, ok := test.Value.(*Plain); ok {
1210 vt := reflect.TypeOf(test.Value)
1211 dest := reflect.New(vt.Elem()).Interface()
1212 err := Unmarshal([]byte(test.ExpectXML), dest)
1214 switch fix := dest.(type) {
1216 fix.Author.InnerXML = ""
1217 for i := range fix.Entry {
1218 fix.Entry[i].Author.InnerXML = ""
1223 t.Errorf("#%d: unexpected error: %#v", i, err)
1224 } else if got, want := dest, test.Value; !reflect.DeepEqual(got, want) {
1225 t.Errorf("#%d: unmarshal(%q):\nhave %#v\nwant %#v", i, test.ExpectXML, got, want)
1230 func TestMarshalIndent(t *testing.T) {
1231 for i, test := range marshalIndentTests {
1232 data, err := MarshalIndent(test.Value, test.Prefix, test.Indent)
1234 t.Errorf("#%d: Error: %s", i, err)
1237 if got, want := string(data), test.ExpectXML; got != want {
1238 t.Errorf("#%d: MarshalIndent:\nGot:%s\nWant:\n%s", i, got, want)
1243 type limitedBytesWriter struct {
1245 remain int // until writes fail
1248 func (lw *limitedBytesWriter) Write(p []byte) (n int, err error) {
1251 return 0, errors.New("write limit hit")
1253 if len(p) > lw.remain {
1255 n, _ = lw.w.Write(p)
1257 return n, errors.New("write limit hit")
1259 n, err = lw.w.Write(p)
1264 func TestMarshalWriteErrors(t *testing.T) {
1265 var buf bytes.Buffer
1266 const writeCap = 1024
1267 w := &limitedBytesWriter{&buf, writeCap}
1268 enc := NewEncoder(w)
1272 for i = 1; i <= n; i++ {
1273 err = enc.Encode(&Passenger{
1274 Name: []string{"Alice", "Bob"},
1282 t.Error("expected an error")
1285 t.Errorf("expected to fail before the end")
1287 if buf.Len() != writeCap {
1288 t.Errorf("buf.Len() = %d; want %d", buf.Len(), writeCap)
1292 func TestMarshalWriteIOErrors(t *testing.T) {
1293 enc := NewEncoder(errWriter{})
1295 expectErr := "unwritable"
1296 err := enc.Encode(&Passenger{})
1297 if err == nil || err.Error() != expectErr {
1298 t.Errorf("EscapeTest = [error] %v, want %v", err, expectErr)
1302 func TestMarshalFlush(t *testing.T) {
1303 var buf bytes.Buffer
1304 enc := NewEncoder(&buf)
1305 if err := enc.EncodeToken(CharData("hello world")); err != nil {
1306 t.Fatalf("enc.EncodeToken: %v", err)
1309 t.Fatalf("enc.EncodeToken caused actual write: %q", buf.Bytes())
1311 if err := enc.Flush(); err != nil {
1312 t.Fatalf("enc.Flush: %v", err)
1314 if buf.String() != "hello world" {
1315 t.Fatalf("after enc.Flush, buf.String() = %q, want %q", buf.String(), "hello world")
1319 var encodeElementTests = []struct {
1325 desc: "simple string",
1327 start: StartElement{
1328 Name: Name{Local: "a"},
1330 expectXML: `<a>hello</a>`,
1332 desc: "string with added attributes",
1334 start: StartElement{
1335 Name: Name{Local: "a"},
1337 Name: Name{Local: "x"},
1340 Name: Name{Local: "foo"},
1344 expectXML: `<a x="y" foo="bar">hello</a>`,
1346 desc: "start element with default name space",
1348 Foo XMLNameWithNSTag
1350 Foo: XMLNameWithNSTag{
1354 start: StartElement{
1355 Name: Name{Space: "ns", Local: "a"},
1357 Name: Name{Local: "xmlns"},
1358 // "ns" is the name space defined in XMLNameWithNSTag
1362 expectXML: `<a xmlns="ns"><InXMLNameWithNSTag>hello</InXMLNameWithNSTag></a>`,
1364 desc: "start element in name space with different default name space",
1366 Foo XMLNameWithNSTag
1368 Foo: XMLNameWithNSTag{
1372 start: StartElement{
1373 Name: Name{Space: "ns2", Local: "a"},
1375 Name: Name{Local: "xmlns"},
1376 // "ns" is the name space defined in XMLNameWithNSTag
1380 expectXML: `<ns2:a xmlns:ns2="ns2" xmlns="ns"><InXMLNameWithNSTag>hello</InXMLNameWithNSTag></ns2:a>`,
1382 desc: "XMLMarshaler with start element with default name space",
1383 value: &MyMarshalerTest{},
1384 start: StartElement{
1385 Name: Name{Space: "ns2", Local: "a"},
1387 Name: Name{Local: "xmlns"},
1388 // "ns" is the name space defined in XMLNameWithNSTag
1392 expectXML: `<ns2:a xmlns:ns2="ns2" xmlns="ns">hello world</ns2:a>`,
1395 func TestEncodeElement(t *testing.T) {
1396 for idx, test := range encodeElementTests {
1397 var buf bytes.Buffer
1398 enc := NewEncoder(&buf)
1399 err := enc.EncodeElement(test.value, test.start)
1401 t.Fatalf("enc.EncodeElement: %v", err)
1405 t.Fatalf("enc.Flush: %v", err)
1407 if got, want := buf.String(), test.expectXML; got != want {
1408 t.Errorf("#%d(%s): EncodeElement(%#v, %#v):\nhave %#q\nwant %#q", idx, test.desc, test.value, test.start, got, want)
1413 func BenchmarkMarshal(b *testing.B) {
1415 for i := 0; i < b.N; i++ {
1420 func BenchmarkUnmarshal(b *testing.B) {
1422 xml := []byte(atomXml)
1423 for i := 0; i < b.N; i++ {
1424 Unmarshal(xml, &Feed{})
1428 // golang.org/issue/6556
1429 func TestStructPointerMarshal(t *testing.T) {
1431 XMLName string `xml:"a"`
1436 Value string `xml:"value"`
1440 a.B = append(a.B, &C{
1441 XMLName: Name{Local: "c"},
1445 b, err := Marshal(a)
1449 if x := string(b); x != "<a><c><value>x</value></c></a>" {
1453 err = Unmarshal(b, &v)
1459 var encodeTokenTests = []struct {
1465 desc: "start element with name space",
1467 StartElement{Name{"space", "local"}, nil},
1469 want: `<space:local xmlns:space="space">`,
1471 desc: "start element with no name",
1473 StartElement{Name{"space", ""}, nil},
1475 err: "xml: start tag with no name",
1477 desc: "end element with no name",
1479 EndElement{Name{"space", ""}},
1481 err: "xml: end tag with no name",
1489 desc: "char data with escaped chars",
1501 desc: "comment with invalid content",
1505 err: "xml: EncodeToken of Comment containing --> marker",
1507 desc: "proc instruction",
1509 ProcInst{"Target", []byte("Instruction")},
1511 want: `<?Target Instruction?>`,
1513 desc: "proc instruction with empty target",
1515 ProcInst{"", []byte("Instruction")},
1517 err: "xml: EncodeToken of ProcInst with invalid Target",
1519 desc: "proc instruction with bad content",
1521 ProcInst{"", []byte("Instruction?>")},
1523 err: "xml: EncodeToken of ProcInst with invalid Target",
1531 desc: "more complex directive",
1533 Directive("DOCTYPE doc [ <!ELEMENT doc '>'> <!-- com>ment --> ]"),
1535 want: `<!DOCTYPE doc [ <!ELEMENT doc '>'> <!-- com>ment --> ]>`,
1537 desc: "directive instruction with bad name",
1541 err: "xml: EncodeToken of Directive containing wrong < or > markers",
1543 desc: "end tag without start tag",
1545 EndElement{Name{"foo", "bar"}},
1547 err: "xml: end tag </bar> without start tag",
1549 desc: "mismatching end tag local name",
1551 StartElement{Name{"", "foo"}, nil},
1552 EndElement{Name{"", "bar"}},
1554 err: "xml: end tag </bar> does not match start tag <foo>",
1557 desc: "mismatching end tag namespace",
1559 StartElement{Name{"space", "foo"}, nil},
1560 EndElement{Name{"another", "foo"}},
1562 err: "xml: end tag </foo> in namespace another does not match start tag <foo> in namespace space",
1563 want: `<space:foo xmlns:space="space">`,
1565 desc: "start element with explicit namespace",
1567 StartElement{Name{"space", "local"}, []Attr{
1568 {Name{"xmlns", "x"}, "space"},
1569 {Name{"space", "foo"}, "value"},
1572 want: `<x:local xmlns:x="space" x:foo="value">`,
1574 desc: "start element with explicit namespace and colliding prefix",
1576 StartElement{Name{"space", "local"}, []Attr{
1577 {Name{"xmlns", "x"}, "space"},
1578 {Name{"space", "foo"}, "value"},
1579 {Name{"x", "bar"}, "other"},
1582 want: `<x:local xmlns:x_1="x" xmlns:x="space" x:foo="value" x_1:bar="other">`,
1584 desc: "start element using previously defined namespace",
1586 StartElement{Name{"", "local"}, []Attr{
1587 {Name{"xmlns", "x"}, "space"},
1589 StartElement{Name{"space", "foo"}, []Attr{
1590 {Name{"space", "x"}, "y"},
1593 want: `<local xmlns:x="space"><x:foo x:x="y">`,
1595 desc: "nested name space with same prefix",
1597 StartElement{Name{"", "foo"}, []Attr{
1598 {Name{"xmlns", "x"}, "space1"},
1600 StartElement{Name{"", "foo"}, []Attr{
1601 {Name{"xmlns", "x"}, "space2"},
1603 StartElement{Name{"", "foo"}, []Attr{
1604 {Name{"space1", "a"}, "space1 value"},
1605 {Name{"space2", "b"}, "space2 value"},
1607 EndElement{Name{"", "foo"}},
1608 EndElement{Name{"", "foo"}},
1609 StartElement{Name{"", "foo"}, []Attr{
1610 {Name{"space1", "a"}, "space1 value"},
1611 {Name{"space2", "b"}, "space2 value"},
1614 want: `<foo xmlns:x="space1"><foo xmlns:x="space2"><foo xmlns:space1="space1" space1:a="space1 value" x:b="space2 value"></foo></foo><foo xmlns:space2="space2" x:a="space1 value" space2:b="space2 value">`,
1616 desc: "start element defining several prefixes for the same name space",
1618 StartElement{Name{"space", "foo"}, []Attr{
1619 {Name{"xmlns", "a"}, "space"},
1620 {Name{"xmlns", "b"}, "space"},
1621 {Name{"space", "x"}, "value"},
1624 want: `<a:foo xmlns:a="space" a:x="value">`,
1626 desc: "nested element redefines name space",
1628 StartElement{Name{"", "foo"}, []Attr{
1629 {Name{"xmlns", "x"}, "space"},
1631 StartElement{Name{"space", "foo"}, []Attr{
1632 {Name{"xmlns", "y"}, "space"},
1633 {Name{"space", "a"}, "value"},
1636 want: `<foo xmlns:x="space"><x:foo x:a="value">`,
1638 desc: "nested element creates alias for default name space",
1640 StartElement{Name{"space", "foo"}, []Attr{
1641 {Name{"", "xmlns"}, "space"},
1643 StartElement{Name{"space", "foo"}, []Attr{
1644 {Name{"xmlns", "y"}, "space"},
1645 {Name{"space", "a"}, "value"},
1648 want: `<foo xmlns="space"><foo xmlns:y="space" y:a="value">`,
1650 desc: "nested element defines default name space with existing prefix",
1652 StartElement{Name{"", "foo"}, []Attr{
1653 {Name{"xmlns", "x"}, "space"},
1655 StartElement{Name{"space", "foo"}, []Attr{
1656 {Name{"", "xmlns"}, "space"},
1657 {Name{"space", "a"}, "value"},
1660 want: `<foo xmlns:x="space"><foo xmlns="space" x:a="value">`,
1662 desc: "nested element uses empty attribute name space when default ns defined",
1664 StartElement{Name{"space", "foo"}, []Attr{
1665 {Name{"", "xmlns"}, "space"},
1667 StartElement{Name{"space", "foo"}, []Attr{
1668 {Name{"", "attr"}, "value"},
1671 want: `<foo xmlns="space"><foo attr="value">`,
1673 desc: "redefine xmlns",
1675 StartElement{Name{"", "foo"}, []Attr{
1676 {Name{"foo", "xmlns"}, "space"},
1679 err: `xml: cannot redefine xmlns attribute prefix`,
1681 desc: "xmlns with explicit name space #1",
1683 StartElement{Name{"space", "foo"}, []Attr{
1684 {Name{"xml", "xmlns"}, "space"},
1687 want: `<foo xmlns="space">`,
1689 desc: "xmlns with explicit name space #2",
1691 StartElement{Name{"space", "foo"}, []Attr{
1692 {Name{xmlURL, "xmlns"}, "space"},
1695 want: `<foo xmlns="space">`,
1697 desc: "empty name space declaration is ignored",
1699 StartElement{Name{"", "foo"}, []Attr{
1700 {Name{"xmlns", "foo"}, ""},
1705 desc: "attribute with no name is ignored",
1707 StartElement{Name{"", "foo"}, []Attr{
1708 {Name{"", ""}, "value"},
1713 desc: "namespace URL with non-valid name",
1715 StartElement{Name{"/34", "foo"}, []Attr{
1716 {Name{"/34", "x"}, "value"},
1719 want: `<_:foo xmlns:_="/34" _:x="value">`,
1721 desc: "nested element resets default namespace to empty",
1723 StartElement{Name{"space", "foo"}, []Attr{
1724 {Name{"", "xmlns"}, "space"},
1726 StartElement{Name{"", "foo"}, []Attr{
1727 {Name{"", "xmlns"}, ""},
1728 {Name{"", "x"}, "value"},
1729 {Name{"space", "x"}, "value"},
1732 want: `<foo xmlns="space"><foo xmlns:space="space" xmlns="" x="value" space:x="value">`,
1734 desc: "nested element requires empty default name space",
1736 StartElement{Name{"space", "foo"}, []Attr{
1737 {Name{"", "xmlns"}, "space"},
1739 StartElement{Name{"", "foo"}, nil},
1741 want: `<foo xmlns="space"><foo xmlns="">`,
1743 desc: "attribute uses name space from xmlns",
1745 StartElement{Name{"some/space", "foo"}, []Attr{
1746 {Name{"", "attr"}, "value"},
1747 {Name{"some/space", "other"}, "other value"},
1750 want: `<space:foo xmlns:space="some/space" attr="value" space:other="other value">`,
1752 desc: "default name space should not be used by attributes",
1754 StartElement{Name{"space", "foo"}, []Attr{
1755 {Name{"", "xmlns"}, "space"},
1756 {Name{"xmlns", "bar"}, "space"},
1757 {Name{"space", "baz"}, "foo"},
1759 StartElement{Name{"space", "baz"}, nil},
1760 EndElement{Name{"space", "baz"}},
1761 EndElement{Name{"space", "foo"}},
1763 want: `<foo xmlns:bar="space" xmlns="space" bar:baz="foo"><baz></baz></foo>`,
1765 desc: "default name space not used by attributes, not explicitly defined",
1767 StartElement{Name{"space", "foo"}, []Attr{
1768 {Name{"", "xmlns"}, "space"},
1769 {Name{"space", "baz"}, "foo"},
1771 StartElement{Name{"space", "baz"}, nil},
1772 EndElement{Name{"space", "baz"}},
1773 EndElement{Name{"space", "foo"}},
1775 want: `<foo xmlns:space="space" xmlns="space" space:baz="foo"><baz></baz></foo>`,
1777 desc: "impossible xmlns declaration",
1779 StartElement{Name{"", "foo"}, []Attr{
1780 {Name{"", "xmlns"}, "space"},
1782 StartElement{Name{"space", "bar"}, []Attr{
1783 {Name{"space", "attr"}, "value"},
1786 want: `<foo><space:bar xmlns:space="space" space:attr="value">`,
1789 func TestEncodeToken(t *testing.T) {
1791 for i, tt := range encodeTokenTests {
1792 var buf bytes.Buffer
1793 enc := NewEncoder(&buf)
1795 for j, tok := range tt.toks {
1796 err = enc.EncodeToken(tok)
1797 if err != nil && j < len(tt.toks)-1 {
1798 t.Errorf("#%d %s token #%d: %v", i, tt.desc, j, err)
1802 errorf := func(f string, a ...interface{}) {
1803 t.Errorf("#%d %s token #%d:%s", i, tt.desc, len(tt.toks)-1, fmt.Sprintf(f, a...))
1806 case tt.err != "" && err == nil:
1807 errorf(" expected error; got none")
1809 case tt.err == "" && err != nil:
1810 errorf(" got error: %v", err)
1812 case tt.err != "" && err != nil && tt.err != err.Error():
1813 errorf(" error mismatch; got %v, want %v", err, tt.err)
1816 if err := enc.Flush(); err != nil {
1820 if got := buf.String(); got != tt.want {
1821 errorf("\ngot %v\nwant %v", got, tt.want)
1827 func TestProcInstEncodeToken(t *testing.T) {
1828 var buf bytes.Buffer
1829 enc := NewEncoder(&buf)
1831 if err := enc.EncodeToken(ProcInst{"xml", []byte("Instruction")}); err != nil {
1832 t.Fatalf("enc.EncodeToken: expected to be able to encode xml target ProcInst as first token, %s", err)
1835 if err := enc.EncodeToken(ProcInst{"Target", []byte("Instruction")}); err != nil {
1836 t.Fatalf("enc.EncodeToken: expected to be able to add non-xml target ProcInst")
1839 if err := enc.EncodeToken(ProcInst{"xml", []byte("Instruction")}); err == nil {
1840 t.Fatalf("enc.EncodeToken: expected to not be allowed to encode xml target ProcInst when not first token")
1844 func TestDecodeEncode(t *testing.T) {
1845 var in, out bytes.Buffer
1846 in.WriteString(`<?xml version="1.0" encoding="UTF-8"?>
1847 <?Target Instruction?>
1851 dec := NewDecoder(&in)
1852 enc := NewEncoder(&out)
1853 for tok, err := dec.Token(); err == nil; tok, err = dec.Token() {
1854 err = enc.EncodeToken(tok)
1856 t.Fatalf("enc.EncodeToken: Unable to encode token (%#v), %v", tok, err)
1861 // Issue 9796. Used to fail with GORACE="halt_on_error=1" -race.
1862 func TestRace9796(t *testing.T) {
1867 var wg sync.WaitGroup
1868 for i := 0; i < 2; i++ {
1878 func TestIsValidDirective(t *testing.T) {
1882 "<!DOCTYPE '<' '>' '>' <!--nothing-->>",
1883 "<!DOCTYPE doc [ <!ELEMENT doc ANY> <!ELEMENT doc ANY> ]>",
1884 "<!DOCTYPE doc [ <!ELEMENT doc \"ANY> '<' <!E\" LEMENT '>' doc ANY> ]>",
1885 "<!DOCTYPE doc <!-- just>>>> a < comment --> [ <!ITEM anything> ] >",
1893 "<!dummy <!-- > -->",
1895 "<!DOCTYPE doc '>'",
1896 "<!DOCTYPE doc <!--comment>",
1898 for _, s := range testOK {
1899 if !isValidDirective(Directive(s)) {
1900 t.Errorf("Directive %q is expected to be valid", s)
1903 for _, s := range testKO {
1904 if isValidDirective(Directive(s)) {
1905 t.Errorf("Directive %q is expected to be invalid", s)
1910 // Issue 11719. EncodeToken used to silently eat tokens with an invalid type.
1911 func TestSimpleUseOfEncodeToken(t *testing.T) {
1912 var buf bytes.Buffer
1913 enc := NewEncoder(&buf)
1914 if err := enc.EncodeToken(&StartElement{Name: Name{"", "object1"}}); err == nil {
1915 t.Errorf("enc.EncodeToken: pointer type should be rejected")
1917 if err := enc.EncodeToken(&EndElement{Name: Name{"", "object1"}}); err == nil {
1918 t.Errorf("enc.EncodeToken: pointer type should be rejected")
1920 if err := enc.EncodeToken(StartElement{Name: Name{"", "object2"}}); err != nil {
1921 t.Errorf("enc.EncodeToken: StartElement %s", err)
1923 if err := enc.EncodeToken(EndElement{Name: Name{"", "object2"}}); err != nil {
1924 t.Errorf("enc.EncodeToken: EndElement %s", err)
1926 if err := enc.EncodeToken(Universe{}); err == nil {
1927 t.Errorf("enc.EncodeToken: invalid type not caught")
1929 if err := enc.Flush(); err != nil {
1930 t.Errorf("enc.Flush: %s", err)
1933 t.Errorf("enc.EncodeToken: empty buffer")
1935 want := "<object2></object2>"
1936 if buf.String() != want {
1937 t.Errorf("enc.EncodeToken: expected %q; got %q", want, buf.String())