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