OSDN Git Service

new repo
[bytom/vapor.git] / vendor / golang.org / x / net / webdav / internal / xml / marshal_test.go
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
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 // Unless explicitly stated as such (or *Plain), all of the
408 // tests below are two-way tests. When introducing new tests,
409 // please try to make them two-way as well to ensure that
410 // marshalling and unmarshalling are as symmetrical as feasible.
411 var marshalTests = []struct {
412         Value         interface{}
413         ExpectXML     string
414         MarshalOnly   bool
415         UnmarshalOnly bool
416 }{
417         // Test nil marshals to nothing
418         {Value: nil, ExpectXML: ``, MarshalOnly: true},
419         {Value: nilStruct, ExpectXML: ``, MarshalOnly: true},
420
421         // Test value types
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>&lt;/&gt;</V></Plain>`},
438         {Value: &Plain{[]byte("</>")}, ExpectXML: `<Plain><V>&lt;/&gt;</V></Plain>`},
439         {Value: &Plain{[3]byte{'<', '/', '>'}}, ExpectXML: `<Plain><V>&lt;/&gt;</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         // Test time.
446         {
447                 Value:     &Plain{time.Unix(1e9, 123456789).UTC()},
448                 ExpectXML: `<Plain><V>2001-09-09T01:46:40.123456789Z</V></Plain>`,
449         },
450
451         // A pointer to struct{} may be used to test for an element's presence.
452         {
453                 Value:     &PresenceTest{new(struct{})},
454                 ExpectXML: `<PresenceTest><Exists></Exists></PresenceTest>`,
455         },
456         {
457                 Value:     &PresenceTest{},
458                 ExpectXML: `<PresenceTest></PresenceTest>`,
459         },
460
461         // A pointer to struct{} may be used to test for an element's presence.
462         {
463                 Value:     &PresenceTest{new(struct{})},
464                 ExpectXML: `<PresenceTest><Exists></Exists></PresenceTest>`,
465         },
466         {
467                 Value:     &PresenceTest{},
468                 ExpectXML: `<PresenceTest></PresenceTest>`,
469         },
470
471         // A []byte field is only nil if the element was not found.
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         // Check that []byte works, including named []byte types.
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         // Test innerxml
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         // Test structs
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="&lt;unix&gt;"></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&amp;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 &amp; 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         // Test a>b
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, // Uses interface{}
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         // Test struct embedding
747         {
748                 Value: &EmbedA{
749                         EmbedC: EmbedC{
750                                 FieldA1: "", // Shadowed by A.A
751                                 FieldA2: "", // Shadowed by A.A
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:  "", // Shadowed by A.B.B
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         // Test that name casing matters
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         // Test the order in which the XML element name is chosen
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         // xml.Name works in a plain field as well.
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         // Marshaling zero xml.Name uses the tag or field name.
832         {
833                 Value:       &NameInField{},
834                 ExpectXML:   `<NameInField><foo xmlns="ns"></foo></NameInField>`,
835                 MarshalOnly: true,
836         },
837
838         // Test attributes
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         // pointer fields
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         // empty chardata pointer field
883         {
884                 Value:       &ChardataEmptyTest{},
885                 ExpectXML:   `<test></test>`,
886                 MarshalOnly: true,
887         },
888
889         // omitempty on fields
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         // Test ",any"
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         // Test recursive types.
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         // Test ignoring fields via "-" tag
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         // Test escaping.
995         {
996                 ExpectXML: `<a><nested><value>dquote: &#34;; squote: &#39;; ampersand: &amp;; less: &lt;; greater: &gt;;</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: &#xA;; cr: &#xD;; tab: &#x9;;</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         // Test omitempty with parent chain; see golang.org/issue/4168.
1023         {
1024                 ExpectXML: `<Strings><A></A></Strings>`,
1025                 Value:     &Strings{},
1026         },
1027         // Custom marshalers.
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                 // The xmlns attribute must be ignored because the <test>
1082                 // element is in the empty namespace, so it's not possible
1083                 // to set the default namespace to something non-empty.
1084                 ExpectXML:   `<test><Body>hello world</Body></test>`,
1085                 Value:       &NamedXMLNSFieldStructWithEmptyNamespace{Ns: "foo", Body: "hello world"},
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         // Reject parent chain with attr, never worked; see golang.org/issue/5033.
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 // Do invertibility testing on the various structures that we test
1202 func TestUnmarshal(t *testing.T) {
1203         for i, test := range marshalTests {
1204                 if test.MarshalOnly {
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 // until writes fail
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                         // "ns" is the name space defined in XMLNameWithNSTag
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                         // "ns" is the name space defined in XMLNameWithNSTag
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                         // "ns" is the name space defined in XMLNameWithNSTag
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 // golang.org/issue/6556
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: " &#x9;\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 // Issue 9796. Used to fail with GORACE="halt_on_error=1" -race.
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 // Issue 11719. EncodeToken used to silently eat tokens with an invalid type.
1911 func TestSimpleUseOfEncodeToken(t *testing.T) {
1912         var buf bytes.Buffer
1913         enc := NewEncoder(&buf)
1914         if err := enc.EncodeToken(&StartElement{Name: Name{"", "object1"}}); err == nil {
1915                 t.Errorf("enc.EncodeToken: pointer type should be rejected")
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 }