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