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