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