Empty interface; prefer specific types or generics for type safety
MarshalOnly: true, // Uses interface{}
1// Copyright 2011 The Go Authors. All rights reserved.2// Use of this source code is governed by a BSD-style3// license that can be found in the LICENSE file.45package xml67import (8 "bytes"9 "errors"10 "fmt"11 "io"12 "reflect"13 "strconv"14 "strings"15 "sync"16 "testing"17 "time"18)1920type DriveType int2122const (23 HyperDrive DriveType = iota24 ImprobabilityDrive25)2627type Passenger struct {28 Name []string `xml:"name"`29 Weight float32 `xml:"weight"`30}3132type Ship struct {33 XMLName struct{} `xml:"spaceship"`3435 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 string41}4243type NamedType string4445type 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}5152type Domain struct {53 XMLName struct{} `xml:"domain"`54 Country string `xml:",attr,omitempty"`55 Name []byte `xml:",chardata"`56 Comment []byte `xml:",comment"`57}5859type Book struct {60 XMLName struct{} `xml:"book"`61 Title string `xml:",chardata"`62}6364type Event struct {65 XMLName struct{} `xml:"event"`66 Year int `xml:",chardata"`67}6869type Movie struct {70 XMLName struct{} `xml:"movie"`71 Length uint `xml:",chardata"`72}7374type Pi struct {75 XMLName struct{} `xml:"pi"`76 Approximation float32 `xml:",chardata"`77}7879type Universe struct {80 XMLName struct{} `xml:"universe"`81 Visible float64 `xml:",chardata"`82}8384type Particle struct {85 XMLName struct{} `xml:"particle"`86 HasMass bool `xml:",chardata"`87}8889type Departure struct {90 XMLName struct{} `xml:"departure"`91 When time.Time `xml:",chardata"`92}9394type SecretAgent struct {95 XMLName struct{} `xml:"agent"`96 Handle string `xml:"handle,attr"`97 Identity string98 Obfuscate string `xml:",innerxml"`99}100101type NestedItems struct {102 XMLName struct{} `xml:"result"`103 Items []string `xml:">item"`104 Item1 []string `xml:"Items>item1"`105}106107type 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}113114type 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}121122type NilTest struct {123 A any `xml:"parent1>parent2>a"`124 B any `xml:"parent1>b"`125 C any `xml:"parent1>parent2>c"`126}127128type Service struct {129 XMLName struct{} `xml:"service"`130 Domain *Domain `xml:"host>domain"`131 Port *Port `xml:"host>port"`132 Extra1 any133 Extra2 any `xml:"host>extra2"`134}135136var nilStruct *Ship137138type EmbedA struct {139 EmbedC140 EmbedB EmbedB141 FieldA string142 embedD143}144145type EmbedB struct {146 FieldB string147 *EmbedC148}149150type EmbedC struct {151 FieldA1 string `xml:"FieldA>A1"`152 FieldA2 string `xml:"FieldA>A2"`153 FieldB string154 FieldC string155}156157type embedD struct {158 fieldD string159 FieldE string // Promoted and visible when embedD is embedded.160}161162type NameCasing struct {163 XMLName struct{} `xml:"casing"`164 Xy string165 XY string166 XyA string `xml:"Xy,attr"`167 XYA string `xml:"XY,attr"`168}169170type NamePrecedence struct {171 XMLName Name `xml:"Parent"`172 FromTag XMLNameWithoutTag `xml:"InTag"`173 FromNameVal XMLNameWithoutTag174 FromNameTag XMLNameWithTag175 InFieldName string176}177178type XMLNameWithTag struct {179 XMLName Name `xml:"InXMLNameTag"`180 Value string `xml:",chardata"`181}182183type XMLNameWithoutTag struct {184 XMLName Name185 Value string `xml:",chardata"`186}187188type NameInField struct {189 Foo Name `xml:"ns foo"`190}191192type 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}201202type 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}212213type 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}223224type 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}235236type AnyTest struct {237 XMLName struct{} `xml:"a"`238 Nested string `xml:"nested>value"`239 AnyField AnyHolder `xml:",any"`240}241242type AnyOmitTest struct {243 XMLName struct{} `xml:"a"`244 Nested string `xml:"nested>value"`245 AnyField *AnyHolder `xml:",any,omitempty"`246}247248type AnySliceTest struct {249 XMLName struct{} `xml:"a"`250 Nested string `xml:"nested>value"`251 AnyField []AnyHolder `xml:",any"`252}253254type AnyHolder struct {255 XMLName Name256 XML string `xml:",innerxml"`257}258259type RecurseA struct {260 A string261 B *RecurseB262}263264type RecurseB struct {265 A *RecurseA266 B string267}268269type PresenceTest struct {270 Exists *struct{}271}272273type IgnoreTest struct {274 PublicSecret string `xml:"-"`275}276277type MyBytes []byte278279type Data struct {280 Bytes []byte281 Attr []byte `xml:",attr"`282 Custom MyBytes283}284285type Plain struct {286 V any287}288289type MyInt int290291type EmbedInt struct {292 MyInt293}294295type Strings struct {296 X []string `xml:"A>B,omitempty"`297}298299type 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}306307type ChardataEmptyTest struct {308 XMLName Name `xml:"test"`309 Contents *string `xml:",chardata"`310}311312type PointerAnonFields struct {313 *MyInt314 *NamedType315}316317type MyMarshalerTest struct {318}319320var _ Marshaler = (*MyMarshalerTest)(nil)321322func (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 nil327}328329type MyMarshalerAttrTest struct {330}331332var _ MarshalerAttr = (*MyMarshalerAttrTest)(nil)333334func (m *MyMarshalerAttrTest) MarshalXMLAttr(name Name) (Attr, error) {335 return Attr{name, "hello world"}, nil336}337338func (m *MyMarshalerAttrTest) UnmarshalXMLAttr(attr Attr) error {339 return nil340}341342type MarshalerStruct struct {343 Foo MyMarshalerAttrTest `xml:",attr"`344}345346type InnerStruct struct {347 XMLName Name `xml:"testns outer"`348}349350type OuterStruct struct {351 InnerStruct352 IntAttr int `xml:"int,attr"`353}354355type OuterNamedStruct struct {356 InnerStruct357 XMLName Name `xml:"outerns test"`358 IntAttr int `xml:"int,attr"`359}360361type OuterNamedOrderedStruct struct {362 XMLName Name `xml:"outerns test"`363 InnerStruct364 IntAttr int `xml:"int,attr"`365}366367type OuterOuterStruct struct {368 OuterStruct369}370371type NestedAndChardata struct {372 AB []string `xml:"A>B"`373 Chardata string `xml:",chardata"`374}375376type NestedAndComment struct {377 AB []string `xml:"A>B"`378 Comment string `xml:",comment"`379}380381type CDataTest struct {382 Chardata string `xml:",cdata"`383}384385type NestedAndCData struct {386 AB []string `xml:"A>B"`387 CDATA string `xml:",cdata"`388}389390func ifaceptr(x any) any {391 return &x392}393394func stringptr(x string) *string {395 return &x396}397398type T1 struct{}399type T2 struct{}400401type IndirComment struct {402 T1 T1403 Comment *string `xml:",comment"`404 T2 T2405}406407type DirectComment struct {408 T1 T1409 Comment string `xml:",comment"`410 T2 T2411}412413type IfaceComment struct {414 T1 T1415 Comment any `xml:",comment"`416 T2 T2417}418419type IndirChardata struct {420 T1 T1421 Chardata *string `xml:",chardata"`422 T2 T2423}424425type DirectChardata struct {426 T1 T1427 Chardata string `xml:",chardata"`428 T2 T2429}430431type IfaceChardata struct {432 T1 T1433 Chardata any `xml:",chardata"`434 T2 T2435}436437type IndirCDATA struct {438 T1 T1439 CDATA *string `xml:",cdata"`440 T2 T2441}442443type DirectCDATA struct {444 T1 T1445 CDATA string `xml:",cdata"`446 T2 T2447}448449type IfaceCDATA struct {450 T1 T1451 CDATA any `xml:",cdata"`452 T2 T2453}454455type IndirInnerXML struct {456 T1 T1457 InnerXML *string `xml:",innerxml"`458 T2 T2459}460461type DirectInnerXML struct {462 T1 T1463 InnerXML string `xml:",innerxml"`464 T2 T2465}466467type IfaceInnerXML struct {468 T1 T1469 InnerXML any `xml:",innerxml"`470 T2 T2471}472473type IndirElement struct {474 T1 T1475 Element *string476 T2 T2477}478479type DirectElement struct {480 T1 T1481 Element string482 T2 T2483}484485type IfaceElement struct {486 T1 T1487 Element any488 T2 T2489}490491type IndirOmitEmpty struct {492 T1 T1493 OmitEmpty *string `xml:",omitempty"`494 T2 T2495}496497type DirectOmitEmpty struct {498 T1 T1499 OmitEmpty string `xml:",omitempty"`500 T2 T2501}502503type IfaceOmitEmpty struct {504 T1 T1505 OmitEmpty any `xml:",omitempty"`506 T2 T2507}508509type IndirAny struct {510 T1 T1511 Any *string `xml:",any"`512 T2 T2513}514515type DirectAny struct {516 T1 T1517 Any string `xml:",any"`518 T2 T2519}520521type IfaceAny struct {522 T1 T1523 Any any `xml:",any"`524 T2 T2525}526527type Generic[T any] struct {528 X T529}530531var (532 nameAttr = "Sarah"533 ageAttr = uint(12)534 contentsAttr = "lorem ipsum"535 empty = ""536)537538// Unless explicitly stated as such (or *Plain), all of the539// tests below are two-way tests. When introducing new tests,540// please try to make them two-way as well to ensure that541// marshaling and unmarshaling are as symmetrical as feasible.542var marshalTests = []struct {543 Value any544 ExpectXML string545 MarshalOnly bool546 MarshalError string547 UnmarshalOnly bool548 UnmarshalError string549}{550 // Test nil marshals to nothing551 {Value: nil, ExpectXML: ``, MarshalOnly: true},552 {Value: nilStruct, ExpectXML: ``, MarshalOnly: true},553554 // Test value types555 {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>`},577578 // Test time.579 {580 Value: &Plain{time.Unix(1e9, 123456789).UTC()},581 ExpectXML: `<Plain><V>2001-09-09T01:46:40.123456789Z</V></Plain>`,582 },583584 // 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 },593594 // 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 },605606 // 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 },611612 // Test innerxml613 {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 },631632 // Test structs633 {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 },699700 // Test a>b701 {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 Name824 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 },862863 // Test struct embedding864 {865 Value: &EmbedA{866 EmbedC: EmbedC{867 FieldA1: "", // Shadowed by A.A868 FieldA2: "", // Shadowed by A.A869 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.B878 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 },901902 // Embedded struct pointer field which is nil903 {904 Value: &EmbedB{},905 ExpectXML: `<EmbedB><FieldB></FieldB></EmbedB>`,906 },907908 // Other kinds of nil embedded fields909 {910 Value: &PointerAnonFields{},911 ExpectXML: `<PointerAnonFields></PointerAnonFields>`,912 },913914 // Test that name casing matters915 {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 },919920 // Test the order in which the XML element name is chosen921 {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 },952953 // 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 },963964 // 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 },970971 // Test attributes972 {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 },10551056 // pointer fields1057 {1058 Value: &PointerFieldsTest{Name: &nameAttr, Age: &ageAttr, Contents: &contentsAttr},1059 ExpectXML: `<dummy name="Sarah" age="12">lorem ipsum</dummy>`,1060 MarshalOnly: true,1061 },10621063 // empty chardata pointer field1064 {1065 Value: &ChardataEmptyTest{},1066 ExpectXML: `<test></test>`,1067 MarshalOnly: true,1068 },10691070 // omitempty on fields1071 {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 },10991100 // 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 },11481149 // 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 },11601161 // Test ignoring fields via "-" tag1162 {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 },11761177 // 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 },12401241 // 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/190631285 {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 CDATA1341 },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 CDATA1360 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 CDATA1380 },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 CDATA1393 },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 CDATA1412 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 CDATA1432 },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}16601661func TestMarshal(t *testing.T) {1662 for idx, test := range marshalTests {1663 if test.UnmarshalOnly {1664 continue1665 }16661667 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 return1673 }1674 if !strings.Contains(err.Error(), test.MarshalError) {1675 t.Errorf("marshal(%#v): %s, want %q", test.Value, err, test.MarshalError)1676 }1677 return1678 }1679 if test.MarshalError != "" {1680 t.Errorf("Marshal succeeded, want error %q", test.MarshalError)1681 return1682 }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}16931694type AttrParent struct {1695 X string `xml:"X>Y,attr"`1696}16971698type BadAttr struct {1699 Name map[string]string `xml:"name,attr"`1700}17011702var marshalErrorTests = []struct {1703 Value any1704 Err string1705 Kind reflect.Kind1706}{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}17391740var marshalIndentTests = []struct {1741 Value any1742 Prefix string1743 Indent string1744 ExpectXML string1745}{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}17571758func 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 continue1764 }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}17751776// Do invertibility testing on the various structures that we test1777func TestUnmarshal(t *testing.T) {1778 for i, test := range marshalTests {1779 if test.MarshalOnly {1780 continue1781 }1782 if _, ok := test.Value.(*Plain); ok {1783 continue1784 }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 in1790 // https://go-review.googlesource.com/#/c/5910/1791 continue1792 }17931794 vt := reflect.TypeOf(test.Value)1795 dest := reflect.New(vt.Elem()).Interface()1796 err := Unmarshal([]byte(test.ExpectXML), dest)17971798 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 }18061807 if err != nil {1808 if test.UnmarshalError == "" {1809 t.Errorf("unmarshal(%#v): %s", test.ExpectXML, err)1810 return1811 }1812 if !strings.Contains(err.Error(), test.UnmarshalError) {1813 t.Errorf("unmarshal(%#v): %s, want %q", test.ExpectXML, err, test.UnmarshalError)1814 }1815 return1816 }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}18231824func 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 continue1830 }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}18361837type limitedBytesWriter struct {1838 w io.Writer1839 remain int // until writes fail1840}18411842func (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 = 01851 return n, errors.New("write limit hit")1852 }1853 n, err = lw.w.Write(p)1854 lw.remain -= n1855 return n, err1856}18571858func TestMarshalWriteErrors(t *testing.T) {1859 var buf bytes.Buffer1860 const writeCap = 10241861 w := &limitedBytesWriter{&buf, writeCap}1862 enc := NewEncoder(w)1863 var err error1864 var i int1865 const n = 40001866 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 break1873 }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}18851886func TestMarshalWriteIOErrors(t *testing.T) {1887 enc := NewEncoder(errWriter{})18881889 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}18951896func TestMarshalFlush(t *testing.T) {1897 var buf strings.Builder1898 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}19121913func BenchmarkMarshal(b *testing.B) {1914 b.ReportAllocs()1915 b.RunParallel(func(pb *testing.PB) {1916 for pb.Next() {1917 Marshal(atomValue)1918 }1919 })1920}19211922func 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}19311932// golang.org/issue/65561933func TestStructPointerMarshal(t *testing.T) {1934 type A struct {1935 XMLName string `xml:"a"`1936 B []any1937 }1938 type C struct {1939 XMLName Name1940 Value string `xml:"value"`1941 }19421943 a := new(A)1944 a.B = append(a.B, &C{1945 XMLName: Name{Local: "c"},1946 Value: "x",1947 })19481949 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 A1957 err = Unmarshal(b, &v)1958 if err != nil {1959 t.Fatal(err)1960 }1961}19621963var encodeTokenTests = []struct {1964 desc string1965 toks []Token1966 want string1967 err string1968}{{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{
Same data, no extra tab — call code_get_file + code_get_findings over MCP from Claude/Cursor/Copilot.