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