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