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