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