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