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 }
143
144 type EmbedB struct {
145 FieldB string
146 *EmbedC
147 }
148
149 type EmbedC struct {
150 FieldA1 string `xml:"FieldA>A1"`
151 FieldA2 string `xml:"FieldA>A2"`
152 FieldB string
153 FieldC string
154 }
155
156 type NameCasing struct {
157 XMLName struct{} `xml:"casing"`
158 Xy string
159 XY string
160 XyA string `xml:"Xy,attr"`
161 XYA string `xml:"XY,attr"`
162 }
163
164 type NamePrecedence struct {
165 XMLName Name `xml:"Parent"`
166 FromTag XMLNameWithoutTag `xml:"InTag"`
167 FromNameVal XMLNameWithoutTag
168 FromNameTag XMLNameWithTag
169 InFieldName string
170 }
171
172 type XMLNameWithTag struct {
173 XMLName Name `xml:"InXMLNameTag"`
174 Value string `xml:",chardata"`
175 }
176
177 type XMLNameWithNSTag struct {
178 XMLName Name `xml:"ns InXMLNameWithNSTag"`
179 Value string `xml:",chardata"`
180 }
181
182 type XMLNameWithoutTag struct {
183 XMLName Name
184 Value string `xml:",chardata"`
185 }
186
187 type NameInField struct {
188 Foo Name `xml:"ns foo"`
189 }
190
191 type AttrTest struct {
192 Int int `xml:",attr"`
193 Named int `xml:"int,attr"`
194 Float float64 `xml:",attr"`
195 Uint8 uint8 `xml:",attr"`
196 Bool bool `xml:",attr"`
197 Str string `xml:",attr"`
198 Bytes []byte `xml:",attr"`
199 }
200
201 type OmitAttrTest struct {
202 Int int `xml:",attr,omitempty"`
203 Named int `xml:"int,attr,omitempty"`
204 Float float64 `xml:",attr,omitempty"`
205 Uint8 uint8 `xml:",attr,omitempty"`
206 Bool bool `xml:",attr,omitempty"`
207 Str string `xml:",attr,omitempty"`
208 Bytes []byte `xml:",attr,omitempty"`
209 }
210
211 type OmitFieldTest struct {
212 Int int `xml:",omitempty"`
213 Named int `xml:"int,omitempty"`
214 Float float64 `xml:",omitempty"`
215 Uint8 uint8 `xml:",omitempty"`
216 Bool bool `xml:",omitempty"`
217 Str string `xml:",omitempty"`
218 Bytes []byte `xml:",omitempty"`
219 Ptr *PresenceTest `xml:",omitempty"`
220 }
221
222 type AnyTest struct {
223 XMLName struct{} `xml:"a"`
224 Nested string `xml:"nested>value"`
225 AnyField AnyHolder `xml:",any"`
226 }
227
228 type AnyOmitTest struct {
229 XMLName struct{} `xml:"a"`
230 Nested string `xml:"nested>value"`
231 AnyField *AnyHolder `xml:",any,omitempty"`
232 }
233
234 type AnySliceTest struct {
235 XMLName struct{} `xml:"a"`
236 Nested string `xml:"nested>value"`
237 AnyField []AnyHolder `xml:",any"`
238 }
239
240 type AnyHolder struct {
241 XMLName Name
242 XML string `xml:",innerxml"`
243 }
244
245 type RecurseA struct {
246 A string
247 B *RecurseB
248 }
249
250 type RecurseB struct {
251 A *RecurseA
252 B string
253 }
254
255 type PresenceTest struct {
256 Exists *struct{}
257 }
258
259 type IgnoreTest struct {
260 PublicSecret string `xml:"-"`
261 }
262
263 type MyBytes []byte
264
265 type Data struct {
266 Bytes []byte
267 Attr []byte `xml:",attr"`
268 Custom MyBytes
269 }
270
271 type Plain struct {
272 V interface{}
273 }
274
275 type MyInt int
276
277 type EmbedInt struct {
278 MyInt
279 }
280
281 type Strings struct {
282 X []string `xml:"A>B,omitempty"`
283 }
284
285 type PointerFieldsTest struct {
286 XMLName Name `xml:"dummy"`
287 Name *string `xml:"name,attr"`
288 Age *uint `xml:"age,attr"`
289 Empty *string `xml:"empty,attr"`
290 Contents *string `xml:",chardata"`
291 }
292
293 type ChardataEmptyTest struct {
294 XMLName Name `xml:"test"`
295 Contents *string `xml:",chardata"`
296 }
297
298 type MyMarshalerTest struct {
299 }
300
301 var _ Marshaler = (*MyMarshalerTest)(nil)
302
303 func (m *MyMarshalerTest) MarshalXML(e *Encoder, start StartElement) error {
304 e.EncodeToken(start)
305 e.EncodeToken(CharData([]byte("hello world")))
306 e.EncodeToken(EndElement{start.Name})
307 return nil
308 }
309
310 type MyMarshalerAttrTest struct{}
311
312 var _ MarshalerAttr = (*MyMarshalerAttrTest)(nil)
313
314 func (m *MyMarshalerAttrTest) MarshalXMLAttr(name Name) (Attr, error) {
315 return Attr{name, "hello world"}, nil
316 }
317
318 type MyMarshalerValueAttrTest struct{}
319
320 var _ MarshalerAttr = MyMarshalerValueAttrTest{}
321
322 func (m MyMarshalerValueAttrTest) MarshalXMLAttr(name Name) (Attr, error) {
323 return Attr{name, "hello world"}, nil
324 }
325
326 type MarshalerStruct struct {
327 Foo MyMarshalerAttrTest `xml:",attr"`
328 }
329
330 type MarshalerValueStruct struct {
331 Foo MyMarshalerValueAttrTest `xml:",attr"`
332 }
333
334 type InnerStruct struct {
335 XMLName Name `xml:"testns outer"`
336 }
337
338 type OuterStruct struct {
339 InnerStruct
340 IntAttr int `xml:"int,attr"`
341 }
342
343 type OuterNamedStruct struct {
344 InnerStruct
345 XMLName Name `xml:"outerns test"`
346 IntAttr int `xml:"int,attr"`
347 }
348
349 type OuterNamedOrderedStruct struct {
350 XMLName Name `xml:"outerns test"`
351 InnerStruct
352 IntAttr int `xml:"int,attr"`
353 }
354
355 type OuterOuterStruct struct {
356 OuterStruct
357 }
358
359 type NestedAndChardata struct {
360 AB []string `xml:"A>B"`
361 Chardata string `xml:",chardata"`
362 }
363
364 type NestedAndComment struct {
365 AB []string `xml:"A>B"`
366 Comment string `xml:",comment"`
367 }
368
369 type XMLNSFieldStruct struct {
370 Ns string `xml:"xmlns,attr"`
371 Body string
372 }
373
374 type NamedXMLNSFieldStruct struct {
375 XMLName struct{} `xml:"testns test"`
376 Ns string `xml:"xmlns,attr"`
377 Body string
378 }
379
380 type XMLNSFieldStructWithOmitEmpty struct {
381 Ns string `xml:"xmlns,attr,omitempty"`
382 Body string
383 }
384
385 type NamedXMLNSFieldStructWithEmptyNamespace struct {
386 XMLName struct{} `xml:"test"`
387 Ns string `xml:"xmlns,attr"`
388 Body string
389 }
390
391 type RecursiveXMLNSFieldStruct struct {
392 Ns string `xml:"xmlns,attr"`
393 Body *RecursiveXMLNSFieldStruct `xml:",omitempty"`
394 Text string `xml:",omitempty"`
395 }
396
397 func ifaceptr(x interface{}) interface{} {
398 return &x
399 }
400
401 var (
402 nameAttr = "Sarah"
403 ageAttr = uint(12)
404 contentsAttr = "lorem ipsum"
405 )
406
407
408
409
410
411 var marshalTests = []struct {
412 Value interface{}
413 ExpectXML string
414 MarshalOnly bool
415 UnmarshalOnly bool
416 }{
417
418 {Value: nil, ExpectXML: ``, MarshalOnly: true},
419 {Value: nilStruct, ExpectXML: ``, MarshalOnly: true},
420
421
422 {Value: &Plain{true}, ExpectXML: `<Plain><V>true</V></Plain>`},
423 {Value: &Plain{false}, ExpectXML: `<Plain><V>false</V></Plain>`},
424 {Value: &Plain{int(42)}, ExpectXML: `<Plain><V>42</V></Plain>`},
425 {Value: &Plain{int8(42)}, ExpectXML: `<Plain><V>42</V></Plain>`},
426 {Value: &Plain{int16(42)}, ExpectXML: `<Plain><V>42</V></Plain>`},
427 {Value: &Plain{int32(42)}, ExpectXML: `<Plain><V>42</V></Plain>`},
428 {Value: &Plain{uint(42)}, ExpectXML: `<Plain><V>42</V></Plain>`},
429 {Value: &Plain{uint8(42)}, ExpectXML: `<Plain><V>42</V></Plain>`},
430 {Value: &Plain{uint16(42)}, ExpectXML: `<Plain><V>42</V></Plain>`},
431 {Value: &Plain{uint32(42)}, ExpectXML: `<Plain><V>42</V></Plain>`},
432 {Value: &Plain{float32(1.25)}, ExpectXML: `<Plain><V>1.25</V></Plain>`},
433 {Value: &Plain{float64(1.25)}, ExpectXML: `<Plain><V>1.25</V></Plain>`},
434 {Value: &Plain{uintptr(0xFFDD)}, ExpectXML: `<Plain><V>65501</V></Plain>`},
435 {Value: &Plain{"gopher"}, ExpectXML: `<Plain><V>gopher</V></Plain>`},
436 {Value: &Plain{[]byte("gopher")}, ExpectXML: `<Plain><V>gopher</V></Plain>`},
437 {Value: &Plain{"</>"}, ExpectXML: `<Plain><V></></V></Plain>`},
438 {Value: &Plain{[]byte("</>")}, ExpectXML: `<Plain><V></></V></Plain>`},
439 {Value: &Plain{[3]byte{'<', '/', '>'}}, ExpectXML: `<Plain><V></></V></Plain>`},
440 {Value: &Plain{NamedType("potato")}, ExpectXML: `<Plain><V>potato</V></Plain>`},
441 {Value: &Plain{[]int{1, 2, 3}}, ExpectXML: `<Plain><V>1</V><V>2</V><V>3</V></Plain>`},
442 {Value: &Plain{[3]int{1, 2, 3}}, ExpectXML: `<Plain><V>1</V><V>2</V><V>3</V></Plain>`},
443 {Value: ifaceptr(true), MarshalOnly: true, ExpectXML: `<bool>true</bool>`},
444
445
446 {
447 Value: &Plain{time.Unix(1e9, 123456789).UTC()},
448 ExpectXML: `<Plain><V>2001-09-09T01:46:40.123456789Z</V></Plain>`,
449 },
450
451
452 {
453 Value: &PresenceTest{new(struct{})},
454 ExpectXML: `<PresenceTest><Exists></Exists></PresenceTest>`,
455 },
456 {
457 Value: &PresenceTest{},
458 ExpectXML: `<PresenceTest></PresenceTest>`,
459 },
460
461
462 {
463 Value: &PresenceTest{new(struct{})},
464 ExpectXML: `<PresenceTest><Exists></Exists></PresenceTest>`,
465 },
466 {
467 Value: &PresenceTest{},
468 ExpectXML: `<PresenceTest></PresenceTest>`,
469 },
470
471
472 {
473 Value: &Data{},
474 ExpectXML: `<Data></Data>`,
475 UnmarshalOnly: true,
476 },
477 {
478 Value: &Data{Bytes: []byte{}, Custom: MyBytes{}, Attr: []byte{}},
479 ExpectXML: `<Data Attr=""><Bytes></Bytes><Custom></Custom></Data>`,
480 UnmarshalOnly: true,
481 },
482
483
484 {
485 Value: &Data{Bytes: []byte("ab"), Custom: MyBytes("cd"), Attr: []byte{'v'}},
486 ExpectXML: `<Data Attr="v"><Bytes>ab</Bytes><Custom>cd</Custom></Data>`,
487 },
488
489
490 {
491 Value: &SecretAgent{
492 Handle: "007",
493 Identity: "James Bond",
494 Obfuscate: "<redacted/>",
495 },
496 ExpectXML: `<agent handle="007"><Identity>James Bond</Identity><redacted/></agent>`,
497 MarshalOnly: true,
498 },
499 {
500 Value: &SecretAgent{
501 Handle: "007",
502 Identity: "James Bond",
503 Obfuscate: "<Identity>James Bond</Identity><redacted/>",
504 },
505 ExpectXML: `<agent handle="007"><Identity>James Bond</Identity><redacted/></agent>`,
506 UnmarshalOnly: true,
507 },
508
509
510 {Value: &Port{Type: "ssl", Number: "443"}, ExpectXML: `<port type="ssl">443</port>`},
511 {Value: &Port{Number: "443"}, ExpectXML: `<port>443</port>`},
512 {Value: &Port{Type: "<unix>"}, ExpectXML: `<port type="<unix>"></port>`},
513 {Value: &Port{Number: "443", Comment: "https"}, ExpectXML: `<port><!--https-->443</port>`},
514 {Value: &Port{Number: "443", Comment: "add space-"}, ExpectXML: `<port><!--add space- -->443</port>`, MarshalOnly: true},
515 {Value: &Domain{Name: []byte("google.com&friends")}, ExpectXML: `<domain>google.com&friends</domain>`},
516 {Value: &Domain{Name: []byte("google.com"), Comment: []byte(" &friends ")}, ExpectXML: `<domain>google.com<!-- &friends --></domain>`},
517 {Value: &Book{Title: "Pride & Prejudice"}, ExpectXML: `<book>Pride & Prejudice</book>`},
518 {Value: &Event{Year: -3114}, ExpectXML: `<event>-3114</event>`},
519 {Value: &Movie{Length: 13440}, ExpectXML: `<movie>13440</movie>`},
520 {Value: &Pi{Approximation: 3.14159265}, ExpectXML: `<pi>3.1415927</pi>`},
521 {Value: &Universe{Visible: 9.3e13}, ExpectXML: `<universe>9.3e+13</universe>`},
522 {Value: &Particle{HasMass: true}, ExpectXML: `<particle>true</particle>`},
523 {Value: &Departure{When: ParseTime("2013-01-09T00:15:00-09:00")}, ExpectXML: `<departure>2013-01-09T00:15:00-09:00</departure>`},
524 {Value: atomValue, ExpectXML: atomXml},
525 {
526 Value: &Ship{
527 Name: "Heart of Gold",
528 Pilot: "Computer",
529 Age: 1,
530 Drive: ImprobabilityDrive,
531 Passenger: []*Passenger{
532 {
533 Name: []string{"Zaphod", "Beeblebrox"},
534 Weight: 7.25,
535 },
536 {
537 Name: []string{"Trisha", "McMillen"},
538 Weight: 5.5,
539 },
540 {
541 Name: []string{"Ford", "Prefect"},
542 Weight: 7,
543 },
544 {
545 Name: []string{"Arthur", "Dent"},
546 Weight: 6.75,
547 },
548 },
549 },
550 ExpectXML: `<spaceship name="Heart of Gold" pilot="Computer">` +
551 `<drive>` + strconv.Itoa(int(ImprobabilityDrive)) + `</drive>` +
552 `<age>1</age>` +
553 `<passenger>` +
554 `<name>Zaphod</name>` +
555 `<name>Beeblebrox</name>` +
556 `<weight>7.25</weight>` +
557 `</passenger>` +
558 `<passenger>` +
559 `<name>Trisha</name>` +
560 `<name>McMillen</name>` +
561 `<weight>5.5</weight>` +
562 `</passenger>` +
563 `<passenger>` +
564 `<name>Ford</name>` +
565 `<name>Prefect</name>` +
566 `<weight>7</weight>` +
567 `</passenger>` +
568 `<passenger>` +
569 `<name>Arthur</name>` +
570 `<name>Dent</name>` +
571 `<weight>6.75</weight>` +
572 `</passenger>` +
573 `</spaceship>`,
574 },
575
576
577 {
578 Value: &NestedItems{Items: nil, Item1: nil},
579 ExpectXML: `<result>` +
580 `<Items>` +
581 `</Items>` +
582 `</result>`,
583 },
584 {
585 Value: &NestedItems{Items: []string{}, Item1: []string{}},
586 ExpectXML: `<result>` +
587 `<Items>` +
588 `</Items>` +
589 `</result>`,
590 MarshalOnly: true,
591 },
592 {
593 Value: &NestedItems{Items: nil, Item1: []string{"A"}},
594 ExpectXML: `<result>` +
595 `<Items>` +
596 `<item1>A</item1>` +
597 `</Items>` +
598 `</result>`,
599 },
600 {
601 Value: &NestedItems{Items: []string{"A", "B"}, Item1: nil},
602 ExpectXML: `<result>` +
603 `<Items>` +
604 `<item>A</item>` +
605 `<item>B</item>` +
606 `</Items>` +
607 `</result>`,
608 },
609 {
610 Value: &NestedItems{Items: []string{"A", "B"}, Item1: []string{"C"}},
611 ExpectXML: `<result>` +
612 `<Items>` +
613 `<item>A</item>` +
614 `<item>B</item>` +
615 `<item1>C</item1>` +
616 `</Items>` +
617 `</result>`,
618 },
619 {
620 Value: &NestedOrder{Field1: "C", Field2: "B", Field3: "A"},
621 ExpectXML: `<result>` +
622 `<parent>` +
623 `<c>C</c>` +
624 `<b>B</b>` +
625 `<a>A</a>` +
626 `</parent>` +
627 `</result>`,
628 },
629 {
630 Value: &NilTest{A: "A", B: nil, C: "C"},
631 ExpectXML: `<NilTest>` +
632 `<parent1>` +
633 `<parent2><a>A</a></parent2>` +
634 `<parent2><c>C</c></parent2>` +
635 `</parent1>` +
636 `</NilTest>`,
637 MarshalOnly: true,
638 },
639 {
640 Value: &MixedNested{A: "A", B: "B", C: "C", D: "D"},
641 ExpectXML: `<result>` +
642 `<parent1><a>A</a></parent1>` +
643 `<b>B</b>` +
644 `<parent1>` +
645 `<parent2><c>C</c></parent2>` +
646 `<d>D</d>` +
647 `</parent1>` +
648 `</result>`,
649 },
650 {
651 Value: &Service{Port: &Port{Number: "80"}},
652 ExpectXML: `<service><host><port>80</port></host></service>`,
653 },
654 {
655 Value: &Service{},
656 ExpectXML: `<service></service>`,
657 },
658 {
659 Value: &Service{Port: &Port{Number: "80"}, Extra1: "A", Extra2: "B"},
660 ExpectXML: `<service>` +
661 `<host><port>80</port></host>` +
662 `<Extra1>A</Extra1>` +
663 `<host><extra2>B</extra2></host>` +
664 `</service>`,
665 MarshalOnly: true,
666 },
667 {
668 Value: &Service{Port: &Port{Number: "80"}, Extra2: "example"},
669 ExpectXML: `<service>` +
670 `<host><port>80</port></host>` +
671 `<host><extra2>example</extra2></host>` +
672 `</service>`,
673 MarshalOnly: true,
674 },
675 {
676 Value: &struct {
677 XMLName struct{} `xml:"space top"`
678 A string `xml:"x>a"`
679 B string `xml:"x>b"`
680 C string `xml:"space x>c"`
681 C1 string `xml:"space1 x>c"`
682 D1 string `xml:"space1 x>d"`
683 E1 string `xml:"x>e"`
684 }{
685 A: "a",
686 B: "b",
687 C: "c",
688 C1: "c1",
689 D1: "d1",
690 E1: "e1",
691 },
692 ExpectXML: `<top xmlns="space">` +
693 `<x><a>a</a><b>b</b><c>c</c></x>` +
694 `<x xmlns="space1">` +
695 `<c>c1</c>` +
696 `<d>d1</d>` +
697 `</x>` +
698 `<x>` +
699 `<e>e1</e>` +
700 `</x>` +
701 `</top>`,
702 },
703 {
704 Value: &struct {
705 XMLName Name
706 A string `xml:"x>a"`
707 B string `xml:"x>b"`
708 C string `xml:"space x>c"`
709 C1 string `xml:"space1 x>c"`
710 D1 string `xml:"space1 x>d"`
711 }{
712 XMLName: Name{
713 Space: "space0",
714 Local: "top",
715 },
716 A: "a",
717 B: "b",
718 C: "c",
719 C1: "c1",
720 D1: "d1",
721 },
722 ExpectXML: `<top xmlns="space0">` +
723 `<x><a>a</a><b>b</b></x>` +
724 `<x xmlns="space"><c>c</c></x>` +
725 `<x xmlns="space1">` +
726 `<c>c1</c>` +
727 `<d>d1</d>` +
728 `</x>` +
729 `</top>`,
730 },
731 {
732 Value: &struct {
733 XMLName struct{} `xml:"top"`
734 B string `xml:"space x>b"`
735 B1 string `xml:"space1 x>b"`
736 }{
737 B: "b",
738 B1: "b1",
739 },
740 ExpectXML: `<top>` +
741 `<x xmlns="space"><b>b</b></x>` +
742 `<x xmlns="space1"><b>b1</b></x>` +
743 `</top>`,
744 },
745
746
747 {
748 Value: &EmbedA{
749 EmbedC: EmbedC{
750 FieldA1: "",
751 FieldA2: "",
752 FieldB: "A.C.B",
753 FieldC: "A.C.C",
754 },
755 EmbedB: EmbedB{
756 FieldB: "A.B.B",
757 EmbedC: &EmbedC{
758 FieldA1: "A.B.C.A1",
759 FieldA2: "A.B.C.A2",
760 FieldB: "",
761 FieldC: "A.B.C.C",
762 },
763 },
764 FieldA: "A.A",
765 },
766 ExpectXML: `<EmbedA>` +
767 `<FieldB>A.C.B</FieldB>` +
768 `<FieldC>A.C.C</FieldC>` +
769 `<EmbedB>` +
770 `<FieldB>A.B.B</FieldB>` +
771 `<FieldA>` +
772 `<A1>A.B.C.A1</A1>` +
773 `<A2>A.B.C.A2</A2>` +
774 `</FieldA>` +
775 `<FieldC>A.B.C.C</FieldC>` +
776 `</EmbedB>` +
777 `<FieldA>A.A</FieldA>` +
778 `</EmbedA>`,
779 },
780
781
782 {
783 Value: &NameCasing{Xy: "mixed", XY: "upper", XyA: "mixedA", XYA: "upperA"},
784 ExpectXML: `<casing Xy="mixedA" XY="upperA"><Xy>mixed</Xy><XY>upper</XY></casing>`,
785 },
786
787
788 {
789 Value: &NamePrecedence{
790 FromTag: XMLNameWithoutTag{Value: "A"},
791 FromNameVal: XMLNameWithoutTag{XMLName: Name{Local: "InXMLName"}, Value: "B"},
792 FromNameTag: XMLNameWithTag{Value: "C"},
793 InFieldName: "D",
794 },
795 ExpectXML: `<Parent>` +
796 `<InTag>A</InTag>` +
797 `<InXMLName>B</InXMLName>` +
798 `<InXMLNameTag>C</InXMLNameTag>` +
799 `<InFieldName>D</InFieldName>` +
800 `</Parent>`,
801 MarshalOnly: true,
802 },
803 {
804 Value: &NamePrecedence{
805 XMLName: Name{Local: "Parent"},
806 FromTag: XMLNameWithoutTag{XMLName: Name{Local: "InTag"}, Value: "A"},
807 FromNameVal: XMLNameWithoutTag{XMLName: Name{Local: "FromNameVal"}, Value: "B"},
808 FromNameTag: XMLNameWithTag{XMLName: Name{Local: "InXMLNameTag"}, Value: "C"},
809 InFieldName: "D",
810 },
811 ExpectXML: `<Parent>` +
812 `<InTag>A</InTag>` +
813 `<FromNameVal>B</FromNameVal>` +
814 `<InXMLNameTag>C</InXMLNameTag>` +
815 `<InFieldName>D</InFieldName>` +
816 `</Parent>`,
817 UnmarshalOnly: true,
818 },
819
820
821 {
822 Value: &NameInField{Name{Space: "ns", Local: "foo"}},
823 ExpectXML: `<NameInField><foo xmlns="ns"></foo></NameInField>`,
824 },
825 {
826 Value: &NameInField{Name{Space: "ns", Local: "foo"}},
827 ExpectXML: `<NameInField><foo xmlns="ns"><ignore></ignore></foo></NameInField>`,
828 UnmarshalOnly: true,
829 },
830
831
832 {
833 Value: &NameInField{},
834 ExpectXML: `<NameInField><foo xmlns="ns"></foo></NameInField>`,
835 MarshalOnly: true,
836 },
837
838
839 {
840 Value: &AttrTest{
841 Int: 8,
842 Named: 9,
843 Float: 23.5,
844 Uint8: 255,
845 Bool: true,
846 Str: "str",
847 Bytes: []byte("byt"),
848 },
849 ExpectXML: `<AttrTest Int="8" int="9" Float="23.5" Uint8="255"` +
850 ` Bool="true" Str="str" Bytes="byt"></AttrTest>`,
851 },
852 {
853 Value: &AttrTest{Bytes: []byte{}},
854 ExpectXML: `<AttrTest Int="0" int="0" Float="0" Uint8="0"` +
855 ` Bool="false" Str="" Bytes=""></AttrTest>`,
856 },
857 {
858 Value: &OmitAttrTest{
859 Int: 8,
860 Named: 9,
861 Float: 23.5,
862 Uint8: 255,
863 Bool: true,
864 Str: "str",
865 Bytes: []byte("byt"),
866 },
867 ExpectXML: `<OmitAttrTest Int="8" int="9" Float="23.5" Uint8="255"` +
868 ` Bool="true" Str="str" Bytes="byt"></OmitAttrTest>`,
869 },
870 {
871 Value: &OmitAttrTest{},
872 ExpectXML: `<OmitAttrTest></OmitAttrTest>`,
873 },
874
875
876 {
877 Value: &PointerFieldsTest{Name: &nameAttr, Age: &ageAttr, Contents: &contentsAttr},
878 ExpectXML: `<dummy name="Sarah" age="12">lorem ipsum</dummy>`,
879 MarshalOnly: true,
880 },
881
882
883 {
884 Value: &ChardataEmptyTest{},
885 ExpectXML: `<test></test>`,
886 MarshalOnly: true,
887 },
888
889
890 {
891 Value: &OmitFieldTest{
892 Int: 8,
893 Named: 9,
894 Float: 23.5,
895 Uint8: 255,
896 Bool: true,
897 Str: "str",
898 Bytes: []byte("byt"),
899 Ptr: &PresenceTest{},
900 },
901 ExpectXML: `<OmitFieldTest>` +
902 `<Int>8</Int>` +
903 `<int>9</int>` +
904 `<Float>23.5</Float>` +
905 `<Uint8>255</Uint8>` +
906 `<Bool>true</Bool>` +
907 `<Str>str</Str>` +
908 `<Bytes>byt</Bytes>` +
909 `<Ptr></Ptr>` +
910 `</OmitFieldTest>`,
911 },
912 {
913 Value: &OmitFieldTest{},
914 ExpectXML: `<OmitFieldTest></OmitFieldTest>`,
915 },
916
917
918 {
919 ExpectXML: `<a><nested><value>known</value></nested><other><sub>unknown</sub></other></a>`,
920 Value: &AnyTest{
921 Nested: "known",
922 AnyField: AnyHolder{
923 XMLName: Name{Local: "other"},
924 XML: "<sub>unknown</sub>",
925 },
926 },
927 },
928 {
929 Value: &AnyTest{Nested: "known",
930 AnyField: AnyHolder{
931 XML: "<unknown/>",
932 XMLName: Name{Local: "AnyField"},
933 },
934 },
935 ExpectXML: `<a><nested><value>known</value></nested><AnyField><unknown/></AnyField></a>`,
936 },
937 {
938 ExpectXML: `<a><nested><value>b</value></nested></a>`,
939 Value: &AnyOmitTest{
940 Nested: "b",
941 },
942 },
943 {
944 ExpectXML: `<a><nested><value>b</value></nested><c><d>e</d></c><g xmlns="f"><h>i</h></g></a>`,
945 Value: &AnySliceTest{
946 Nested: "b",
947 AnyField: []AnyHolder{
948 {
949 XMLName: Name{Local: "c"},
950 XML: "<d>e</d>",
951 },
952 {
953 XMLName: Name{Space: "f", Local: "g"},
954 XML: "<h>i</h>",
955 },
956 },
957 },
958 },
959 {
960 ExpectXML: `<a><nested><value>b</value></nested></a>`,
961 Value: &AnySliceTest{
962 Nested: "b",
963 },
964 },
965
966
967 {
968 Value: &RecurseA{
969 A: "a1",
970 B: &RecurseB{
971 A: &RecurseA{"a2", nil},
972 B: "b1",
973 },
974 },
975 ExpectXML: `<RecurseA><A>a1</A><B><A><A>a2</A></A><B>b1</B></B></RecurseA>`,
976 },
977
978
979 {
980 ExpectXML: `<IgnoreTest></IgnoreTest>`,
981 Value: &IgnoreTest{},
982 },
983 {
984 ExpectXML: `<IgnoreTest></IgnoreTest>`,
985 Value: &IgnoreTest{PublicSecret: "can't tell"},
986 MarshalOnly: true,
987 },
988 {
989 ExpectXML: `<IgnoreTest><PublicSecret>ignore me</PublicSecret></IgnoreTest>`,
990 Value: &IgnoreTest{},
991 UnmarshalOnly: true,
992 },
993
994
995 {
996 ExpectXML: `<a><nested><value>dquote: "; squote: '; ampersand: &; less: <; greater: >;</value></nested><empty></empty></a>`,
997 Value: &AnyTest{
998 Nested: `dquote: "; squote: '; ampersand: &; less: <; greater: >;`,
999 AnyField: AnyHolder{XMLName: Name{Local: "empty"}},
1000 },
1001 },
1002 {
1003 ExpectXML: `<a><nested><value>newline: 
; cr: 
; tab: 	;</value></nested><AnyField></AnyField></a>`,
1004 Value: &AnyTest{
1005 Nested: "newline: \n; cr: \r; tab: \t;",
1006 AnyField: AnyHolder{XMLName: Name{Local: "AnyField"}},
1007 },
1008 },
1009 {
1010 ExpectXML: "<a><nested><value>1\r2\r\n3\n\r4\n5</value></nested></a>",
1011 Value: &AnyTest{
1012 Nested: "1\n2\n3\n\n4\n5",
1013 },
1014 UnmarshalOnly: true,
1015 },
1016 {
1017 ExpectXML: `<EmbedInt><MyInt>42</MyInt></EmbedInt>`,
1018 Value: &EmbedInt{
1019 MyInt: 42,
1020 },
1021 },
1022
1023 {
1024 ExpectXML: `<Strings><A></A></Strings>`,
1025 Value: &Strings{},
1026 },
1027
1028 {
1029 ExpectXML: `<MyMarshalerTest>hello world</MyMarshalerTest>`,
1030 Value: &MyMarshalerTest{},
1031 },
1032 {
1033 ExpectXML: `<MarshalerStruct Foo="hello world"></MarshalerStruct>`,
1034 Value: &MarshalerStruct{},
1035 },
1036 {
1037 ExpectXML: `<MarshalerValueStruct Foo="hello world"></MarshalerValueStruct>`,
1038 Value: &MarshalerValueStruct{},
1039 },
1040 {
1041 ExpectXML: `<outer xmlns="testns" int="10"></outer>`,
1042 Value: &OuterStruct{IntAttr: 10},
1043 },
1044 {
1045 ExpectXML: `<test xmlns="outerns" int="10"></test>`,
1046 Value: &OuterNamedStruct{XMLName: Name{Space: "outerns", Local: "test"}, IntAttr: 10},
1047 },
1048 {
1049 ExpectXML: `<test xmlns="outerns" int="10"></test>`,
1050 Value: &OuterNamedOrderedStruct{XMLName: Name{Space: "outerns", Local: "test"}, IntAttr: 10},
1051 },
1052 {
1053 ExpectXML: `<outer xmlns="testns" int="10"></outer>`,
1054 Value: &OuterOuterStruct{OuterStruct{IntAttr: 10}},
1055 },
1056 {
1057 ExpectXML: `<NestedAndChardata><A><B></B><B></B></A>test</NestedAndChardata>`,
1058 Value: &NestedAndChardata{AB: make([]string, 2), Chardata: "test"},
1059 },
1060 {
1061 ExpectXML: `<NestedAndComment><A><B></B><B></B></A><!--test--></NestedAndComment>`,
1062 Value: &NestedAndComment{AB: make([]string, 2), Comment: "test"},
1063 },
1064 {
1065 ExpectXML: `<XMLNSFieldStruct xmlns="http://example.com/ns"><Body>hello world</Body></XMLNSFieldStruct>`,
1066 Value: &XMLNSFieldStruct{Ns: "http://example.com/ns", Body: "hello world"},
1067 },
1068 {
1069 ExpectXML: `<testns:test xmlns:testns="testns" xmlns="http://example.com/ns"><Body>hello world</Body></testns:test>`,
1070 Value: &NamedXMLNSFieldStruct{Ns: "http://example.com/ns", Body: "hello world"},
1071 },
1072 {
1073 ExpectXML: `<testns:test xmlns:testns="testns"><Body>hello world</Body></testns:test>`,
1074 Value: &NamedXMLNSFieldStruct{Ns: "", Body: "hello world"},
1075 },
1076 {
1077 ExpectXML: `<XMLNSFieldStructWithOmitEmpty><Body>hello world</Body></XMLNSFieldStructWithOmitEmpty>`,
1078 Value: &XMLNSFieldStructWithOmitEmpty{Body: "hello world"},
1079 },
1080 {
1081
1082
1083
1084 ExpectXML: `<test><Body>hello world</Body></test>`,
1085 Value: &NamedXMLNSFieldStructWithEmptyNamespace{Ns: "foo", Body: "hello world"},
1086 MarshalOnly: true,
1087 },
1088 {
1089 ExpectXML: `<RecursiveXMLNSFieldStruct xmlns="foo"><Body xmlns=""><Text>hello world</Text></Body></RecursiveXMLNSFieldStruct>`,
1090 Value: &RecursiveXMLNSFieldStruct{
1091 Ns: "foo",
1092 Body: &RecursiveXMLNSFieldStruct{
1093 Text: "hello world",
1094 },
1095 },
1096 },
1097 }
1098
1099 func TestMarshal(t *testing.T) {
1100 for idx, test := range marshalTests {
1101 if test.UnmarshalOnly {
1102 continue
1103 }
1104 data, err := Marshal(test.Value)
1105 if err != nil {
1106 t.Errorf("#%d: marshal(%#v): %s", idx, test.Value, err)
1107 continue
1108 }
1109 if got, want := string(data), test.ExpectXML; got != want {
1110 if strings.Contains(want, "\n") {
1111 t.Errorf("#%d: marshal(%#v):\nHAVE:\n%s\nWANT:\n%s", idx, test.Value, got, want)
1112 } else {
1113 t.Errorf("#%d: marshal(%#v):\nhave %#q\nwant %#q", idx, test.Value, got, want)
1114 }
1115 }
1116 }
1117 }
1118
1119 type AttrParent struct {
1120 X string `xml:"X>Y,attr"`
1121 }
1122
1123 type BadAttr struct {
1124 Name []string `xml:"name,attr"`
1125 }
1126
1127 var marshalErrorTests = []struct {
1128 Value interface{}
1129 Err string
1130 Kind reflect.Kind
1131 }{
1132 {
1133 Value: make(chan bool),
1134 Err: "xml: unsupported type: chan bool",
1135 Kind: reflect.Chan,
1136 },
1137 {
1138 Value: map[string]string{
1139 "question": "What do you get when you multiply six by nine?",
1140 "answer": "42",
1141 },
1142 Err: "xml: unsupported type: map[string]string",
1143 Kind: reflect.Map,
1144 },
1145 {
1146 Value: map[*Ship]bool{nil: false},
1147 Err: "xml: unsupported type: map[*xml.Ship]bool",
1148 Kind: reflect.Map,
1149 },
1150 {
1151 Value: &Domain{Comment: []byte("f--bar")},
1152 Err: `xml: comments must not contain "--"`,
1153 },
1154
1155 {
1156 Value: &AttrParent{},
1157 Err: `xml: X>Y chain not valid with attr flag`,
1158 },
1159 {
1160 Value: BadAttr{[]string{"X", "Y"}},
1161 Err: `xml: unsupported type: []string`,
1162 },
1163 }
1164
1165 var marshalIndentTests = []struct {
1166 Value interface{}
1167 Prefix string
1168 Indent string
1169 ExpectXML string
1170 }{
1171 {
1172 Value: &SecretAgent{
1173 Handle: "007",
1174 Identity: "James Bond",
1175 Obfuscate: "<redacted/>",
1176 },
1177 Prefix: "",
1178 Indent: "\t",
1179 ExpectXML: fmt.Sprintf("<agent handle=\"007\">\n\t<Identity>James Bond</Identity><redacted/>\n</agent>"),
1180 },
1181 }
1182
1183 func TestMarshalErrors(t *testing.T) {
1184 for idx, test := range marshalErrorTests {
1185 data, err := Marshal(test.Value)
1186 if err == nil {
1187 t.Errorf("#%d: marshal(%#v) = [success] %q, want error %v", idx, test.Value, data, test.Err)
1188 continue
1189 }
1190 if err.Error() != test.Err {
1191 t.Errorf("#%d: marshal(%#v) = [error] %v, want %v", idx, test.Value, err, test.Err)
1192 }
1193 if test.Kind != reflect.Invalid {
1194 if kind := err.(*UnsupportedTypeError).Type.Kind(); kind != test.Kind {
1195 t.Errorf("#%d: marshal(%#v) = [error kind] %s, want %s", idx, test.Value, kind, test.Kind)
1196 }
1197 }
1198 }
1199 }
1200
1201
1202 func TestUnmarshal(t *testing.T) {
1203 for i, test := range marshalTests {
1204 if test.MarshalOnly {
1205 continue
1206 }
1207 if _, ok := test.Value.(*Plain); ok {
1208 continue
1209 }
1210 vt := reflect.TypeOf(test.Value)
1211 dest := reflect.New(vt.Elem()).Interface()
1212 err := Unmarshal([]byte(test.ExpectXML), dest)
1213
1214 switch fix := dest.(type) {
1215 case *Feed:
1216 fix.Author.InnerXML = ""
1217 for i := range fix.Entry {
1218 fix.Entry[i].Author.InnerXML = ""
1219 }
1220 }
1221
1222 if err != nil {
1223 t.Errorf("#%d: unexpected error: %#v", i, err)
1224 } else if got, want := dest, test.Value; !reflect.DeepEqual(got, want) {
1225 t.Errorf("#%d: unmarshal(%q):\nhave %#v\nwant %#v", i, test.ExpectXML, got, want)
1226 }
1227 }
1228 }
1229
1230 func TestMarshalIndent(t *testing.T) {
1231 for i, test := range marshalIndentTests {
1232 data, err := MarshalIndent(test.Value, test.Prefix, test.Indent)
1233 if err != nil {
1234 t.Errorf("#%d: Error: %s", i, err)
1235 continue
1236 }
1237 if got, want := string(data), test.ExpectXML; got != want {
1238 t.Errorf("#%d: MarshalIndent:\nGot:%s\nWant:\n%s", i, got, want)
1239 }
1240 }
1241 }
1242
1243 type limitedBytesWriter struct {
1244 w io.Writer
1245 remain int
1246 }
1247
1248 func (lw *limitedBytesWriter) Write(p []byte) (n int, err error) {
1249 if lw.remain <= 0 {
1250 println("error")
1251 return 0, errors.New("write limit hit")
1252 }
1253 if len(p) > lw.remain {
1254 p = p[:lw.remain]
1255 n, _ = lw.w.Write(p)
1256 lw.remain = 0
1257 return n, errors.New("write limit hit")
1258 }
1259 n, err = lw.w.Write(p)
1260 lw.remain -= n
1261 return n, err
1262 }
1263
1264 func TestMarshalWriteErrors(t *testing.T) {
1265 var buf bytes.Buffer
1266 const writeCap = 1024
1267 w := &limitedBytesWriter{&buf, writeCap}
1268 enc := NewEncoder(w)
1269 var err error
1270 var i int
1271 const n = 4000
1272 for i = 1; i <= n; i++ {
1273 err = enc.Encode(&Passenger{
1274 Name: []string{"Alice", "Bob"},
1275 Weight: 5,
1276 })
1277 if err != nil {
1278 break
1279 }
1280 }
1281 if err == nil {
1282 t.Error("expected an error")
1283 }
1284 if i == n {
1285 t.Errorf("expected to fail before the end")
1286 }
1287 if buf.Len() != writeCap {
1288 t.Errorf("buf.Len() = %d; want %d", buf.Len(), writeCap)
1289 }
1290 }
1291
1292 func TestMarshalWriteIOErrors(t *testing.T) {
1293 enc := NewEncoder(errWriter{})
1294
1295 expectErr := "unwritable"
1296 err := enc.Encode(&Passenger{})
1297 if err == nil || err.Error() != expectErr {
1298 t.Errorf("EscapeTest = [error] %v, want %v", err, expectErr)
1299 }
1300 }
1301
1302 func TestMarshalFlush(t *testing.T) {
1303 var buf bytes.Buffer
1304 enc := NewEncoder(&buf)
1305 if err := enc.EncodeToken(CharData("hello world")); err != nil {
1306 t.Fatalf("enc.EncodeToken: %v", err)
1307 }
1308 if buf.Len() > 0 {
1309 t.Fatalf("enc.EncodeToken caused actual write: %q", buf.Bytes())
1310 }
1311 if err := enc.Flush(); err != nil {
1312 t.Fatalf("enc.Flush: %v", err)
1313 }
1314 if buf.String() != "hello world" {
1315 t.Fatalf("after enc.Flush, buf.String() = %q, want %q", buf.String(), "hello world")
1316 }
1317 }
1318
1319 var encodeElementTests = []struct {
1320 desc string
1321 value interface{}
1322 start StartElement
1323 expectXML string
1324 }{{
1325 desc: "simple string",
1326 value: "hello",
1327 start: StartElement{
1328 Name: Name{Local: "a"},
1329 },
1330 expectXML: `<a>hello</a>`,
1331 }, {
1332 desc: "string with added attributes",
1333 value: "hello",
1334 start: StartElement{
1335 Name: Name{Local: "a"},
1336 Attr: []Attr{{
1337 Name: Name{Local: "x"},
1338 Value: "y",
1339 }, {
1340 Name: Name{Local: "foo"},
1341 Value: "bar",
1342 }},
1343 },
1344 expectXML: `<a x="y" foo="bar">hello</a>`,
1345 }, {
1346 desc: "start element with default name space",
1347 value: struct {
1348 Foo XMLNameWithNSTag
1349 }{
1350 Foo: XMLNameWithNSTag{
1351 Value: "hello",
1352 },
1353 },
1354 start: StartElement{
1355 Name: Name{Space: "ns", Local: "a"},
1356 Attr: []Attr{{
1357 Name: Name{Local: "xmlns"},
1358
1359 Value: "ns",
1360 }},
1361 },
1362 expectXML: `<a xmlns="ns"><InXMLNameWithNSTag>hello</InXMLNameWithNSTag></a>`,
1363 }, {
1364 desc: "start element in name space with different default name space",
1365 value: struct {
1366 Foo XMLNameWithNSTag
1367 }{
1368 Foo: XMLNameWithNSTag{
1369 Value: "hello",
1370 },
1371 },
1372 start: StartElement{
1373 Name: Name{Space: "ns2", Local: "a"},
1374 Attr: []Attr{{
1375 Name: Name{Local: "xmlns"},
1376
1377 Value: "ns",
1378 }},
1379 },
1380 expectXML: `<ns2:a xmlns:ns2="ns2" xmlns="ns"><InXMLNameWithNSTag>hello</InXMLNameWithNSTag></ns2:a>`,
1381 }, {
1382 desc: "XMLMarshaler with start element with default name space",
1383 value: &MyMarshalerTest{},
1384 start: StartElement{
1385 Name: Name{Space: "ns2", Local: "a"},
1386 Attr: []Attr{{
1387 Name: Name{Local: "xmlns"},
1388
1389 Value: "ns",
1390 }},
1391 },
1392 expectXML: `<ns2:a xmlns:ns2="ns2" xmlns="ns">hello world</ns2:a>`,
1393 }}
1394
1395 func TestEncodeElement(t *testing.T) {
1396 for idx, test := range encodeElementTests {
1397 var buf bytes.Buffer
1398 enc := NewEncoder(&buf)
1399 err := enc.EncodeElement(test.value, test.start)
1400 if err != nil {
1401 t.Fatalf("enc.EncodeElement: %v", err)
1402 }
1403 err = enc.Flush()
1404 if err != nil {
1405 t.Fatalf("enc.Flush: %v", err)
1406 }
1407 if got, want := buf.String(), test.expectXML; got != want {
1408 t.Errorf("#%d(%s): EncodeElement(%#v, %#v):\nhave %#q\nwant %#q", idx, test.desc, test.value, test.start, got, want)
1409 }
1410 }
1411 }
1412
1413 func BenchmarkMarshal(b *testing.B) {
1414 b.ReportAllocs()
1415 for i := 0; i < b.N; i++ {
1416 Marshal(atomValue)
1417 }
1418 }
1419
1420 func BenchmarkUnmarshal(b *testing.B) {
1421 b.ReportAllocs()
1422 xml := []byte(atomXml)
1423 for i := 0; i < b.N; i++ {
1424 Unmarshal(xml, &Feed{})
1425 }
1426 }
1427
1428
1429 func TestStructPointerMarshal(t *testing.T) {
1430 type A struct {
1431 XMLName string `xml:"a"`
1432 B []interface{}
1433 }
1434 type C struct {
1435 XMLName Name
1436 Value string `xml:"value"`
1437 }
1438
1439 a := new(A)
1440 a.B = append(a.B, &C{
1441 XMLName: Name{Local: "c"},
1442 Value: "x",
1443 })
1444
1445 b, err := Marshal(a)
1446 if err != nil {
1447 t.Fatal(err)
1448 }
1449 if x := string(b); x != "<a><c><value>x</value></c></a>" {
1450 t.Fatal(x)
1451 }
1452 var v A
1453 err = Unmarshal(b, &v)
1454 if err != nil {
1455 t.Fatal(err)
1456 }
1457 }
1458
1459 var encodeTokenTests = []struct {
1460 desc string
1461 toks []Token
1462 want string
1463 err string
1464 }{{
1465 desc: "start element with name space",
1466 toks: []Token{
1467 StartElement{Name{"space", "local"}, nil},
1468 },
1469 want: `<space:local xmlns:space="space">`,
1470 }, {
1471 desc: "start element with no name",
1472 toks: []Token{
1473 StartElement{Name{"space", ""}, nil},
1474 },
1475 err: "xml: start tag with no name",
1476 }, {
1477 desc: "end element with no name",
1478 toks: []Token{
1479 EndElement{Name{"space", ""}},
1480 },
1481 err: "xml: end tag with no name",
1482 }, {
1483 desc: "char data",
1484 toks: []Token{
1485 CharData("foo"),
1486 },
1487 want: `foo`,
1488 }, {
1489 desc: "char data with escaped chars",
1490 toks: []Token{
1491 CharData(" \t\n"),
1492 },
1493 want: " 	\n",
1494 }, {
1495 desc: "comment",
1496 toks: []Token{
1497 Comment("foo"),
1498 },
1499 want: `<!--foo-->`,
1500 }, {
1501 desc: "comment with invalid content",
1502 toks: []Token{
1503 Comment("foo-->"),
1504 },
1505 err: "xml: EncodeToken of Comment containing --> marker",
1506 }, {
1507 desc: "proc instruction",
1508 toks: []Token{
1509 ProcInst{"Target", []byte("Instruction")},
1510 },
1511 want: `<?Target Instruction?>`,
1512 }, {
1513 desc: "proc instruction with empty target",
1514 toks: []Token{
1515 ProcInst{"", []byte("Instruction")},
1516 },
1517 err: "xml: EncodeToken of ProcInst with invalid Target",
1518 }, {
1519 desc: "proc instruction with bad content",
1520 toks: []Token{
1521 ProcInst{"", []byte("Instruction?>")},
1522 },
1523 err: "xml: EncodeToken of ProcInst with invalid Target",
1524 }, {
1525 desc: "directive",
1526 toks: []Token{
1527 Directive("foo"),
1528 },
1529 want: `<!foo>`,
1530 }, {
1531 desc: "more complex directive",
1532 toks: []Token{
1533 Directive("DOCTYPE doc [ <!ELEMENT doc '>'> <!-- com>ment --> ]"),
1534 },
1535 want: `<!DOCTYPE doc [ <!ELEMENT doc '>'> <!-- com>ment --> ]>`,
1536 }, {
1537 desc: "directive instruction with bad name",
1538 toks: []Token{
1539 Directive("foo>"),
1540 },
1541 err: "xml: EncodeToken of Directive containing wrong < or > markers",
1542 }, {
1543 desc: "end tag without start tag",
1544 toks: []Token{
1545 EndElement{Name{"foo", "bar"}},
1546 },
1547 err: "xml: end tag </bar> without start tag",
1548 }, {
1549 desc: "mismatching end tag local name",
1550 toks: []Token{
1551 StartElement{Name{"", "foo"}, nil},
1552 EndElement{Name{"", "bar"}},
1553 },
1554 err: "xml: end tag </bar> does not match start tag <foo>",
1555 want: `<foo>`,
1556 }, {
1557 desc: "mismatching end tag namespace",
1558 toks: []Token{
1559 StartElement{Name{"space", "foo"}, nil},
1560 EndElement{Name{"another", "foo"}},
1561 },
1562 err: "xml: end tag </foo> in namespace another does not match start tag <foo> in namespace space",
1563 want: `<space:foo xmlns:space="space">`,
1564 }, {
1565 desc: "start element with explicit namespace",
1566 toks: []Token{
1567 StartElement{Name{"space", "local"}, []Attr{
1568 {Name{"xmlns", "x"}, "space"},
1569 {Name{"space", "foo"}, "value"},
1570 }},
1571 },
1572 want: `<x:local xmlns:x="space" x:foo="value">`,
1573 }, {
1574 desc: "start element with explicit namespace and colliding prefix",
1575 toks: []Token{
1576 StartElement{Name{"space", "local"}, []Attr{
1577 {Name{"xmlns", "x"}, "space"},
1578 {Name{"space", "foo"}, "value"},
1579 {Name{"x", "bar"}, "other"},
1580 }},
1581 },
1582 want: `<x:local xmlns:x_1="x" xmlns:x="space" x:foo="value" x_1:bar="other">`,
1583 }, {
1584 desc: "start element using previously defined namespace",
1585 toks: []Token{
1586 StartElement{Name{"", "local"}, []Attr{
1587 {Name{"xmlns", "x"}, "space"},
1588 }},
1589 StartElement{Name{"space", "foo"}, []Attr{
1590 {Name{"space", "x"}, "y"},
1591 }},
1592 },
1593 want: `<local xmlns:x="space"><x:foo x:x="y">`,
1594 }, {
1595 desc: "nested name space with same prefix",
1596 toks: []Token{
1597 StartElement{Name{"", "foo"}, []Attr{
1598 {Name{"xmlns", "x"}, "space1"},
1599 }},
1600 StartElement{Name{"", "foo"}, []Attr{
1601 {Name{"xmlns", "x"}, "space2"},
1602 }},
1603 StartElement{Name{"", "foo"}, []Attr{
1604 {Name{"space1", "a"}, "space1 value"},
1605 {Name{"space2", "b"}, "space2 value"},
1606 }},
1607 EndElement{Name{"", "foo"}},
1608 EndElement{Name{"", "foo"}},
1609 StartElement{Name{"", "foo"}, []Attr{
1610 {Name{"space1", "a"}, "space1 value"},
1611 {Name{"space2", "b"}, "space2 value"},
1612 }},
1613 },
1614 want: `<foo xmlns:x="space1"><foo xmlns:x="space2"><foo xmlns:space1="space1" space1:a="space1 value" x:b="space2 value"></foo></foo><foo xmlns:space2="space2" x:a="space1 value" space2:b="space2 value">`,
1615 }, {
1616 desc: "start element defining several prefixes for the same name space",
1617 toks: []Token{
1618 StartElement{Name{"space", "foo"}, []Attr{
1619 {Name{"xmlns", "a"}, "space"},
1620 {Name{"xmlns", "b"}, "space"},
1621 {Name{"space", "x"}, "value"},
1622 }},
1623 },
1624 want: `<a:foo xmlns:a="space" a:x="value">`,
1625 }, {
1626 desc: "nested element redefines name space",
1627 toks: []Token{
1628 StartElement{Name{"", "foo"}, []Attr{
1629 {Name{"xmlns", "x"}, "space"},
1630 }},
1631 StartElement{Name{"space", "foo"}, []Attr{
1632 {Name{"xmlns", "y"}, "space"},
1633 {Name{"space", "a"}, "value"},
1634 }},
1635 },
1636 want: `<foo xmlns:x="space"><x:foo x:a="value">`,
1637 }, {
1638 desc: "nested element creates alias for default name space",
1639 toks: []Token{
1640 StartElement{Name{"space", "foo"}, []Attr{
1641 {Name{"", "xmlns"}, "space"},
1642 }},
1643 StartElement{Name{"space", "foo"}, []Attr{
1644 {Name{"xmlns", "y"}, "space"},
1645 {Name{"space", "a"}, "value"},
1646 }},
1647 },
1648 want: `<foo xmlns="space"><foo xmlns:y="space" y:a="value">`,
1649 }, {
1650 desc: "nested element defines default name space with existing prefix",
1651 toks: []Token{
1652 StartElement{Name{"", "foo"}, []Attr{
1653 {Name{"xmlns", "x"}, "space"},
1654 }},
1655 StartElement{Name{"space", "foo"}, []Attr{
1656 {Name{"", "xmlns"}, "space"},
1657 {Name{"space", "a"}, "value"},
1658 }},
1659 },
1660 want: `<foo xmlns:x="space"><foo xmlns="space" x:a="value">`,
1661 }, {
1662 desc: "nested element uses empty attribute name space when default ns defined",
1663 toks: []Token{
1664 StartElement{Name{"space", "foo"}, []Attr{
1665 {Name{"", "xmlns"}, "space"},
1666 }},
1667 StartElement{Name{"space", "foo"}, []Attr{
1668 {Name{"", "attr"}, "value"},
1669 }},
1670 },
1671 want: `<foo xmlns="space"><foo attr="value">`,
1672 }, {
1673 desc: "redefine xmlns",
1674 toks: []Token{
1675 StartElement{Name{"", "foo"}, []Attr{
1676 {Name{"foo", "xmlns"}, "space"},
1677 }},
1678 },
1679 err: `xml: cannot redefine xmlns attribute prefix`,
1680 }, {
1681 desc: "xmlns with explicit name space #1",
1682 toks: []Token{
1683 StartElement{Name{"space", "foo"}, []Attr{
1684 {Name{"xml", "xmlns"}, "space"},
1685 }},
1686 },
1687 want: `<foo xmlns="space">`,
1688 }, {
1689 desc: "xmlns with explicit name space #2",
1690 toks: []Token{
1691 StartElement{Name{"space", "foo"}, []Attr{
1692 {Name{xmlURL, "xmlns"}, "space"},
1693 }},
1694 },
1695 want: `<foo xmlns="space">`,
1696 }, {
1697 desc: "empty name space declaration is ignored",
1698 toks: []Token{
1699 StartElement{Name{"", "foo"}, []Attr{
1700 {Name{"xmlns", "foo"}, ""},
1701 }},
1702 },
1703 want: `<foo>`,
1704 }, {
1705 desc: "attribute with no name is ignored",
1706 toks: []Token{
1707 StartElement{Name{"", "foo"}, []Attr{
1708 {Name{"", ""}, "value"},
1709 }},
1710 },
1711 want: `<foo>`,
1712 }, {
1713 desc: "namespace URL with non-valid name",
1714 toks: []Token{
1715 StartElement{Name{"/34", "foo"}, []Attr{
1716 {Name{"/34", "x"}, "value"},
1717 }},
1718 },
1719 want: `<_:foo xmlns:_="/34" _:x="value">`,
1720 }, {
1721 desc: "nested element resets default namespace to empty",
1722 toks: []Token{
1723 StartElement{Name{"space", "foo"}, []Attr{
1724 {Name{"", "xmlns"}, "space"},
1725 }},
1726 StartElement{Name{"", "foo"}, []Attr{
1727 {Name{"", "xmlns"}, ""},
1728 {Name{"", "x"}, "value"},
1729 {Name{"space", "x"}, "value"},
1730 }},
1731 },
1732 want: `<foo xmlns="space"><foo xmlns:space="space" xmlns="" x="value" space:x="value">`,
1733 }, {
1734 desc: "nested element requires empty default name space",
1735 toks: []Token{
1736 StartElement{Name{"space", "foo"}, []Attr{
1737 {Name{"", "xmlns"}, "space"},
1738 }},
1739 StartElement{Name{"", "foo"}, nil},
1740 },
1741 want: `<foo xmlns="space"><foo xmlns="">`,
1742 }, {
1743 desc: "attribute uses name space from xmlns",
1744 toks: []Token{
1745 StartElement{Name{"some/space", "foo"}, []Attr{
1746 {Name{"", "attr"}, "value"},
1747 {Name{"some/space", "other"}, "other value"},
1748 }},
1749 },
1750 want: `<space:foo xmlns:space="some/space" attr="value" space:other="other value">`,
1751 }, {
1752 desc: "default name space should not be used by attributes",
1753 toks: []Token{
1754 StartElement{Name{"space", "foo"}, []Attr{
1755 {Name{"", "xmlns"}, "space"},
1756 {Name{"xmlns", "bar"}, "space"},
1757 {Name{"space", "baz"}, "foo"},
1758 }},
1759 StartElement{Name{"space", "baz"}, nil},
1760 EndElement{Name{"space", "baz"}},
1761 EndElement{Name{"space", "foo"}},
1762 },
1763 want: `<foo xmlns:bar="space" xmlns="space" bar:baz="foo"><baz></baz></foo>`,
1764 }, {
1765 desc: "default name space not used by attributes, not explicitly defined",
1766 toks: []Token{
1767 StartElement{Name{"space", "foo"}, []Attr{
1768 {Name{"", "xmlns"}, "space"},
1769 {Name{"space", "baz"}, "foo"},
1770 }},
1771 StartElement{Name{"space", "baz"}, nil},
1772 EndElement{Name{"space", "baz"}},
1773 EndElement{Name{"space", "foo"}},
1774 },
1775 want: `<foo xmlns:space="space" xmlns="space" space:baz="foo"><baz></baz></foo>`,
1776 }, {
1777 desc: "impossible xmlns declaration",
1778 toks: []Token{
1779 StartElement{Name{"", "foo"}, []Attr{
1780 {Name{"", "xmlns"}, "space"},
1781 }},
1782 StartElement{Name{"space", "bar"}, []Attr{
1783 {Name{"space", "attr"}, "value"},
1784 }},
1785 },
1786 want: `<foo><space:bar xmlns:space="space" space:attr="value">`,
1787 }}
1788
1789 func TestEncodeToken(t *testing.T) {
1790 loop:
1791 for i, tt := range encodeTokenTests {
1792 var buf bytes.Buffer
1793 enc := NewEncoder(&buf)
1794 var err error
1795 for j, tok := range tt.toks {
1796 err = enc.EncodeToken(tok)
1797 if err != nil && j < len(tt.toks)-1 {
1798 t.Errorf("#%d %s token #%d: %v", i, tt.desc, j, err)
1799 continue loop
1800 }
1801 }
1802 errorf := func(f string, a ...interface{}) {
1803 t.Errorf("#%d %s token #%d:%s", i, tt.desc, len(tt.toks)-1, fmt.Sprintf(f, a...))
1804 }
1805 switch {
1806 case tt.err != "" && err == nil:
1807 errorf(" expected error; got none")
1808 continue
1809 case tt.err == "" && err != nil:
1810 errorf(" got error: %v", err)
1811 continue
1812 case tt.err != "" && err != nil && tt.err != err.Error():
1813 errorf(" error mismatch; got %v, want %v", err, tt.err)
1814 continue
1815 }
1816 if err := enc.Flush(); err != nil {
1817 errorf(" %v", err)
1818 continue
1819 }
1820 if got := buf.String(); got != tt.want {
1821 errorf("\ngot %v\nwant %v", got, tt.want)
1822 continue
1823 }
1824 }
1825 }
1826
1827 func TestProcInstEncodeToken(t *testing.T) {
1828 var buf bytes.Buffer
1829 enc := NewEncoder(&buf)
1830
1831 if err := enc.EncodeToken(ProcInst{"xml", []byte("Instruction")}); err != nil {
1832 t.Fatalf("enc.EncodeToken: expected to be able to encode xml target ProcInst as first token, %s", err)
1833 }
1834
1835 if err := enc.EncodeToken(ProcInst{"Target", []byte("Instruction")}); err != nil {
1836 t.Fatalf("enc.EncodeToken: expected to be able to add non-xml target ProcInst")
1837 }
1838
1839 if err := enc.EncodeToken(ProcInst{"xml", []byte("Instruction")}); err == nil {
1840 t.Fatalf("enc.EncodeToken: expected to not be allowed to encode xml target ProcInst when not first token")
1841 }
1842 }
1843
1844 func TestDecodeEncode(t *testing.T) {
1845 var in, out bytes.Buffer
1846 in.WriteString(`<?xml version="1.0" encoding="UTF-8"?>
1847 <?Target Instruction?>
1848 <root>
1849 </root>
1850 `)
1851 dec := NewDecoder(&in)
1852 enc := NewEncoder(&out)
1853 for tok, err := dec.Token(); err == nil; tok, err = dec.Token() {
1854 err = enc.EncodeToken(tok)
1855 if err != nil {
1856 t.Fatalf("enc.EncodeToken: Unable to encode token (%#v), %v", tok, err)
1857 }
1858 }
1859 }
1860
1861
1862 func TestRace9796(t *testing.T) {
1863 type A struct{}
1864 type B struct {
1865 C []A `xml:"X>Y"`
1866 }
1867 var wg sync.WaitGroup
1868 for i := 0; i < 2; i++ {
1869 wg.Add(1)
1870 go func() {
1871 Marshal(B{[]A{{}}})
1872 wg.Done()
1873 }()
1874 }
1875 wg.Wait()
1876 }
1877
1878 func TestIsValidDirective(t *testing.T) {
1879 testOK := []string{
1880 "<>",
1881 "< < > >",
1882 "<!DOCTYPE '<' '>' '>' <!--nothing-->>",
1883 "<!DOCTYPE doc [ <!ELEMENT doc ANY> <!ELEMENT doc ANY> ]>",
1884 "<!DOCTYPE doc [ <!ELEMENT doc \"ANY> '<' <!E\" LEMENT '>' doc ANY> ]>",
1885 "<!DOCTYPE doc <!-- just>>>> a < comment --> [ <!ITEM anything> ] >",
1886 }
1887 testKO := []string{
1888 "<",
1889 ">",
1890 "<!--",
1891 "-->",
1892 "< > > < < >",
1893 "<!dummy <!-- > -->",
1894 "<!DOCTYPE doc '>",
1895 "<!DOCTYPE doc '>'",
1896 "<!DOCTYPE doc <!--comment>",
1897 }
1898 for _, s := range testOK {
1899 if !isValidDirective(Directive(s)) {
1900 t.Errorf("Directive %q is expected to be valid", s)
1901 }
1902 }
1903 for _, s := range testKO {
1904 if isValidDirective(Directive(s)) {
1905 t.Errorf("Directive %q is expected to be invalid", s)
1906 }
1907 }
1908 }
1909
1910
1911 func TestSimpleUseOfEncodeToken(t *testing.T) {
1912 var buf bytes.Buffer
1913 enc := NewEncoder(&buf)
1914 if err := enc.EncodeToken(&StartElement{Name: Name{"", "object1"}}); err == nil {
1915 t.Errorf("enc.EncodeToken: pointer type should be rejected")
1916 }
1917 if err := enc.EncodeToken(&EndElement{Name: Name{"", "object1"}}); err == nil {
1918 t.Errorf("enc.EncodeToken: pointer type should be rejected")
1919 }
1920 if err := enc.EncodeToken(StartElement{Name: Name{"", "object2"}}); err != nil {
1921 t.Errorf("enc.EncodeToken: StartElement %s", err)
1922 }
1923 if err := enc.EncodeToken(EndElement{Name: Name{"", "object2"}}); err != nil {
1924 t.Errorf("enc.EncodeToken: EndElement %s", err)
1925 }
1926 if err := enc.EncodeToken(Universe{}); err == nil {
1927 t.Errorf("enc.EncodeToken: invalid type not caught")
1928 }
1929 if err := enc.Flush(); err != nil {
1930 t.Errorf("enc.Flush: %s", err)
1931 }
1932 if buf.Len() == 0 {
1933 t.Errorf("enc.EncodeToken: empty buffer")
1934 }
1935 want := "<object2></object2>"
1936 if buf.String() != want {
1937 t.Errorf("enc.EncodeToken: expected %q; got %q", want, buf.String())
1938 }
1939 }
1940
View as plain text