...
Run Format

Source file src/encoding/xml/marshal_test.go

     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		"testing"
    16		"time"
    17	)
    18	
    19	type DriveType int
    20	
    21	const (
    22		HyperDrive DriveType = iota
    23		ImprobabilityDrive
    24	)
    25	
    26	type Passenger struct {
    27		Name   []string `xml:"name"`
    28		Weight float32  `xml:"weight"`
    29	}
    30	
    31	type Ship struct {
    32		XMLName struct{} `xml:"spaceship"`
    33	
    34		Name      string       `xml:"name,attr"`
    35		Pilot     string       `xml:"pilot,attr"`
    36		Drive     DriveType    `xml:"drive"`
    37		Age       uint         `xml:"age"`
    38		Passenger []*Passenger `xml:"passenger"`
    39		secret    string
    40	}
    41	
    42	type NamedType string
    43	
    44	type Port struct {
    45		XMLName struct{} `xml:"port"`
    46		Type    string   `xml:"type,attr,omitempty"`
    47		Comment string   `xml:",comment"`
    48		Number  string   `xml:",chardata"`
    49	}
    50	
    51	type Domain struct {
    52		XMLName struct{} `xml:"domain"`
    53		Country string   `xml:",attr,omitempty"`
    54		Name    []byte   `xml:",chardata"`
    55		Comment []byte   `xml:",comment"`
    56	}
    57	
    58	type Book struct {
    59		XMLName struct{} `xml:"book"`
    60		Title   string   `xml:",chardata"`
    61	}
    62	
    63	type Event struct {
    64		XMLName struct{} `xml:"event"`
    65		Year    int      `xml:",chardata"`
    66	}
    67	
    68	type Movie struct {
    69		XMLName struct{} `xml:"movie"`
    70		Length  uint     `xml:",chardata"`
    71	}
    72	
    73	type Pi struct {
    74		XMLName       struct{} `xml:"pi"`
    75		Approximation float32  `xml:",chardata"`
    76	}
    77	
    78	type Universe struct {
    79		XMLName struct{} `xml:"universe"`
    80		Visible float64  `xml:",chardata"`
    81	}
    82	
    83	type Particle struct {
    84		XMLName struct{} `xml:"particle"`
    85		HasMass bool     `xml:",chardata"`
    86	}
    87	
    88	type Departure struct {
    89		XMLName struct{}  `xml:"departure"`
    90		When    time.Time `xml:",chardata"`
    91	}
    92	
    93	type SecretAgent struct {
    94		XMLName   struct{} `xml:"agent"`
    95		Handle    string   `xml:"handle,attr"`
    96		Identity  string
    97		Obfuscate string `xml:",innerxml"`
    98	}
    99	
   100	type NestedItems struct {
   101		XMLName struct{} `xml:"result"`
   102		Items   []string `xml:">item"`
   103		Item1   []string `xml:"Items>item1"`
   104	}
   105	
   106	type NestedOrder struct {
   107		XMLName struct{} `xml:"result"`
   108		Field1  string   `xml:"parent>c"`
   109		Field2  string   `xml:"parent>b"`
   110		Field3  string   `xml:"parent>a"`
   111	}
   112	
   113	type MixedNested struct {
   114		XMLName struct{} `xml:"result"`
   115		A       string   `xml:"parent1>a"`
   116		B       string   `xml:"b"`
   117		C       string   `xml:"parent1>parent2>c"`
   118		D       string   `xml:"parent1>d"`
   119	}
   120	
   121	type NilTest struct {
   122		A interface{} `xml:"parent1>parent2>a"`
   123		B interface{} `xml:"parent1>b"`
   124		C interface{} `xml:"parent1>parent2>c"`
   125	}
   126	
   127	type Service struct {
   128		XMLName struct{} `xml:"service"`
   129		Domain  *Domain  `xml:"host>domain"`
   130		Port    *Port    `xml:"host>port"`
   131		Extra1  interface{}
   132		Extra2  interface{} `xml:"host>extra2"`
   133	}
   134	
   135	var nilStruct *Ship
   136	
   137	type EmbedA struct {
   138		EmbedC
   139		EmbedB EmbedB
   140		FieldA string
   141	}
   142	
   143	type EmbedB struct {
   144		FieldB string
   145		*EmbedC
   146	}
   147	
   148	type EmbedC struct {
   149		FieldA1 string `xml:"FieldA>A1"`
   150		FieldA2 string `xml:"FieldA>A2"`
   151		FieldB  string
   152		FieldC  string
   153	}
   154	
   155	type NameCasing struct {
   156		XMLName struct{} `xml:"casing"`
   157		Xy      string
   158		XY      string
   159		XyA     string `xml:"Xy,attr"`
   160		XYA     string `xml:"XY,attr"`
   161	}
   162	
   163	type NamePrecedence struct {
   164		XMLName     Name              `xml:"Parent"`
   165		FromTag     XMLNameWithoutTag `xml:"InTag"`
   166		FromNameVal XMLNameWithoutTag
   167		FromNameTag XMLNameWithTag
   168		InFieldName string
   169	}
   170	
   171	type XMLNameWithTag struct {
   172		XMLName Name   `xml:"InXMLNameTag"`
   173		Value   string `xml:",chardata"`
   174	}
   175	
   176	type XMLNameWithoutTag struct {
   177		XMLName Name
   178		Value   string `xml:",chardata"`
   179	}
   180	
   181	type NameInField struct {
   182		Foo Name `xml:"ns foo"`
   183	}
   184	
   185	type AttrTest struct {
   186		Int   int     `xml:",attr"`
   187		Named int     `xml:"int,attr"`
   188		Float float64 `xml:",attr"`
   189		Uint8 uint8   `xml:",attr"`
   190		Bool  bool    `xml:",attr"`
   191		Str   string  `xml:",attr"`
   192		Bytes []byte  `xml:",attr"`
   193	}
   194	
   195	type OmitAttrTest struct {
   196		Int   int     `xml:",attr,omitempty"`
   197		Named int     `xml:"int,attr,omitempty"`
   198		Float float64 `xml:",attr,omitempty"`
   199		Uint8 uint8   `xml:",attr,omitempty"`
   200		Bool  bool    `xml:",attr,omitempty"`
   201		Str   string  `xml:",attr,omitempty"`
   202		Bytes []byte  `xml:",attr,omitempty"`
   203	}
   204	
   205	type OmitFieldTest struct {
   206		Int   int           `xml:",omitempty"`
   207		Named int           `xml:"int,omitempty"`
   208		Float float64       `xml:",omitempty"`
   209		Uint8 uint8         `xml:",omitempty"`
   210		Bool  bool          `xml:",omitempty"`
   211		Str   string        `xml:",omitempty"`
   212		Bytes []byte        `xml:",omitempty"`
   213		Ptr   *PresenceTest `xml:",omitempty"`
   214	}
   215	
   216	type AnyTest struct {
   217		XMLName  struct{}  `xml:"a"`
   218		Nested   string    `xml:"nested>value"`
   219		AnyField AnyHolder `xml:",any"`
   220	}
   221	
   222	type AnyOmitTest struct {
   223		XMLName  struct{}   `xml:"a"`
   224		Nested   string     `xml:"nested>value"`
   225		AnyField *AnyHolder `xml:",any,omitempty"`
   226	}
   227	
   228	type AnySliceTest struct {
   229		XMLName  struct{}    `xml:"a"`
   230		Nested   string      `xml:"nested>value"`
   231		AnyField []AnyHolder `xml:",any"`
   232	}
   233	
   234	type AnyHolder struct {
   235		XMLName Name
   236		XML     string `xml:",innerxml"`
   237	}
   238	
   239	type RecurseA struct {
   240		A string
   241		B *RecurseB
   242	}
   243	
   244	type RecurseB struct {
   245		A *RecurseA
   246		B string
   247	}
   248	
   249	type PresenceTest struct {
   250		Exists *struct{}
   251	}
   252	
   253	type IgnoreTest struct {
   254		PublicSecret string `xml:"-"`
   255	}
   256	
   257	type MyBytes []byte
   258	
   259	type Data struct {
   260		Bytes  []byte
   261		Attr   []byte `xml:",attr"`
   262		Custom MyBytes
   263	}
   264	
   265	type Plain struct {
   266		V interface{}
   267	}
   268	
   269	type MyInt int
   270	
   271	type EmbedInt struct {
   272		MyInt
   273	}
   274	
   275	type Strings struct {
   276		X []string `xml:"A>B,omitempty"`
   277	}
   278	
   279	type PointerFieldsTest struct {
   280		XMLName  Name    `xml:"dummy"`
   281		Name     *string `xml:"name,attr"`
   282		Age      *uint   `xml:"age,attr"`
   283		Empty    *string `xml:"empty,attr"`
   284		Contents *string `xml:",chardata"`
   285	}
   286	
   287	type ChardataEmptyTest struct {
   288		XMLName  Name    `xml:"test"`
   289		Contents *string `xml:",chardata"`
   290	}
   291	
   292	type MyMarshalerTest struct {
   293	}
   294	
   295	var _ Marshaler = (*MyMarshalerTest)(nil)
   296	
   297	func (m *MyMarshalerTest) MarshalXML(e *Encoder, start StartElement) error {
   298		e.EncodeToken(start)
   299		e.EncodeToken(CharData([]byte("hello world")))
   300		e.EncodeToken(EndElement{start.Name})
   301		return nil
   302	}
   303	
   304	type MyMarshalerAttrTest struct {
   305	}
   306	
   307	var _ MarshalerAttr = (*MyMarshalerAttrTest)(nil)
   308	
   309	func (m *MyMarshalerAttrTest) MarshalXMLAttr(name Name) (Attr, error) {
   310		return Attr{name, "hello world"}, nil
   311	}
   312	
   313	type MarshalerStruct struct {
   314		Foo MyMarshalerAttrTest `xml:",attr"`
   315	}
   316	
   317	type InnerStruct struct {
   318		XMLName Name `xml:"testns outer"`
   319	}
   320	
   321	type OuterStruct struct {
   322		InnerStruct
   323		IntAttr int `xml:"int,attr"`
   324	}
   325	
   326	type OuterNamedStruct struct {
   327		InnerStruct
   328		XMLName Name `xml:"outerns test"`
   329		IntAttr int  `xml:"int,attr"`
   330	}
   331	
   332	type OuterNamedOrderedStruct struct {
   333		XMLName Name `xml:"outerns test"`
   334		InnerStruct
   335		IntAttr int `xml:"int,attr"`
   336	}
   337	
   338	type OuterOuterStruct struct {
   339		OuterStruct
   340	}
   341	
   342	func ifaceptr(x interface{}) interface{} {
   343		return &x
   344	}
   345	
   346	var (
   347		nameAttr     = "Sarah"
   348		ageAttr      = uint(12)
   349		contentsAttr = "lorem ipsum"
   350	)
   351	
   352	// Unless explicitly stated as such (or *Plain), all of the
   353	// tests below are two-way tests. When introducing new tests,
   354	// please try to make them two-way as well to ensure that
   355	// marshalling and unmarshalling are as symmetrical as feasible.
   356	var marshalTests = []struct {
   357		Value         interface{}
   358		ExpectXML     string
   359		MarshalOnly   bool
   360		UnmarshalOnly bool
   361	}{
   362		// Test nil marshals to nothing
   363		{Value: nil, ExpectXML: ``, MarshalOnly: true},
   364		{Value: nilStruct, ExpectXML: ``, MarshalOnly: true},
   365	
   366		// Test value types
   367		{Value: &Plain{true}, ExpectXML: `<Plain><V>true</V></Plain>`},
   368		{Value: &Plain{false}, ExpectXML: `<Plain><V>false</V></Plain>`},
   369		{Value: &Plain{int(42)}, ExpectXML: `<Plain><V>42</V></Plain>`},
   370		{Value: &Plain{int8(42)}, ExpectXML: `<Plain><V>42</V></Plain>`},
   371		{Value: &Plain{int16(42)}, ExpectXML: `<Plain><V>42</V></Plain>`},
   372		{Value: &Plain{int32(42)}, ExpectXML: `<Plain><V>42</V></Plain>`},
   373		{Value: &Plain{uint(42)}, ExpectXML: `<Plain><V>42</V></Plain>`},
   374		{Value: &Plain{uint8(42)}, ExpectXML: `<Plain><V>42</V></Plain>`},
   375		{Value: &Plain{uint16(42)}, ExpectXML: `<Plain><V>42</V></Plain>`},
   376		{Value: &Plain{uint32(42)}, ExpectXML: `<Plain><V>42</V></Plain>`},
   377		{Value: &Plain{float32(1.25)}, ExpectXML: `<Plain><V>1.25</V></Plain>`},
   378		{Value: &Plain{float64(1.25)}, ExpectXML: `<Plain><V>1.25</V></Plain>`},
   379		{Value: &Plain{uintptr(0xFFDD)}, ExpectXML: `<Plain><V>65501</V></Plain>`},
   380		{Value: &Plain{"gopher"}, ExpectXML: `<Plain><V>gopher</V></Plain>`},
   381		{Value: &Plain{[]byte("gopher")}, ExpectXML: `<Plain><V>gopher</V></Plain>`},
   382		{Value: &Plain{"</>"}, ExpectXML: `<Plain><V>&lt;/&gt;</V></Plain>`},
   383		{Value: &Plain{[]byte("</>")}, ExpectXML: `<Plain><V>&lt;/&gt;</V></Plain>`},
   384		{Value: &Plain{[3]byte{'<', '/', '>'}}, ExpectXML: `<Plain><V>&lt;/&gt;</V></Plain>`},
   385		{Value: &Plain{NamedType("potato")}, ExpectXML: `<Plain><V>potato</V></Plain>`},
   386		{Value: &Plain{[]int{1, 2, 3}}, ExpectXML: `<Plain><V>1</V><V>2</V><V>3</V></Plain>`},
   387		{Value: &Plain{[3]int{1, 2, 3}}, ExpectXML: `<Plain><V>1</V><V>2</V><V>3</V></Plain>`},
   388		{Value: ifaceptr(true), MarshalOnly: true, ExpectXML: `<bool>true</bool>`},
   389	
   390		// Test time.
   391		{
   392			Value:     &Plain{time.Unix(1e9, 123456789).UTC()},
   393			ExpectXML: `<Plain><V>2001-09-09T01:46:40.123456789Z</V></Plain>`,
   394		},
   395	
   396		// A pointer to struct{} may be used to test for an element's presence.
   397		{
   398			Value:     &PresenceTest{new(struct{})},
   399			ExpectXML: `<PresenceTest><Exists></Exists></PresenceTest>`,
   400		},
   401		{
   402			Value:     &PresenceTest{},
   403			ExpectXML: `<PresenceTest></PresenceTest>`,
   404		},
   405	
   406		// A pointer to struct{} may be used to test for an element's presence.
   407		{
   408			Value:     &PresenceTest{new(struct{})},
   409			ExpectXML: `<PresenceTest><Exists></Exists></PresenceTest>`,
   410		},
   411		{
   412			Value:     &PresenceTest{},
   413			ExpectXML: `<PresenceTest></PresenceTest>`,
   414		},
   415	
   416		// A []byte field is only nil if the element was not found.
   417		{
   418			Value:         &Data{},
   419			ExpectXML:     `<Data></Data>`,
   420			UnmarshalOnly: true,
   421		},
   422		{
   423			Value:         &Data{Bytes: []byte{}, Custom: MyBytes{}, Attr: []byte{}},
   424			ExpectXML:     `<Data Attr=""><Bytes></Bytes><Custom></Custom></Data>`,
   425			UnmarshalOnly: true,
   426		},
   427	
   428		// Check that []byte works, including named []byte types.
   429		{
   430			Value:     &Data{Bytes: []byte("ab"), Custom: MyBytes("cd"), Attr: []byte{'v'}},
   431			ExpectXML: `<Data Attr="v"><Bytes>ab</Bytes><Custom>cd</Custom></Data>`,
   432		},
   433	
   434		// Test innerxml
   435		{
   436			Value: &SecretAgent{
   437				Handle:    "007",
   438				Identity:  "James Bond",
   439				Obfuscate: "<redacted/>",
   440			},
   441			ExpectXML:   `<agent handle="007"><Identity>James Bond</Identity><redacted/></agent>`,
   442			MarshalOnly: true,
   443		},
   444		{
   445			Value: &SecretAgent{
   446				Handle:    "007",
   447				Identity:  "James Bond",
   448				Obfuscate: "<Identity>James Bond</Identity><redacted/>",
   449			},
   450			ExpectXML:     `<agent handle="007"><Identity>James Bond</Identity><redacted/></agent>`,
   451			UnmarshalOnly: true,
   452		},
   453	
   454		// Test structs
   455		{Value: &Port{Type: "ssl", Number: "443"}, ExpectXML: `<port type="ssl">443</port>`},
   456		{Value: &Port{Number: "443"}, ExpectXML: `<port>443</port>`},
   457		{Value: &Port{Type: "<unix>"}, ExpectXML: `<port type="&lt;unix&gt;"></port>`},
   458		{Value: &Port{Number: "443", Comment: "https"}, ExpectXML: `<port><!--https-->443</port>`},
   459		{Value: &Port{Number: "443", Comment: "add space-"}, ExpectXML: `<port><!--add space- -->443</port>`, MarshalOnly: true},
   460		{Value: &Domain{Name: []byte("google.com&friends")}, ExpectXML: `<domain>google.com&amp;friends</domain>`},
   461		{Value: &Domain{Name: []byte("google.com"), Comment: []byte(" &friends ")}, ExpectXML: `<domain>google.com<!-- &friends --></domain>`},
   462		{Value: &Book{Title: "Pride & Prejudice"}, ExpectXML: `<book>Pride &amp; Prejudice</book>`},
   463		{Value: &Event{Year: -3114}, ExpectXML: `<event>-3114</event>`},
   464		{Value: &Movie{Length: 13440}, ExpectXML: `<movie>13440</movie>`},
   465		{Value: &Pi{Approximation: 3.14159265}, ExpectXML: `<pi>3.1415927</pi>`},
   466		{Value: &Universe{Visible: 9.3e13}, ExpectXML: `<universe>9.3e+13</universe>`},
   467		{Value: &Particle{HasMass: true}, ExpectXML: `<particle>true</particle>`},
   468		{Value: &Departure{When: ParseTime("2013-01-09T00:15:00-09:00")}, ExpectXML: `<departure>2013-01-09T00:15:00-09:00</departure>`},
   469		{Value: atomValue, ExpectXML: atomXml},
   470		{
   471			Value: &Ship{
   472				Name:  "Heart of Gold",
   473				Pilot: "Computer",
   474				Age:   1,
   475				Drive: ImprobabilityDrive,
   476				Passenger: []*Passenger{
   477					{
   478						Name:   []string{"Zaphod", "Beeblebrox"},
   479						Weight: 7.25,
   480					},
   481					{
   482						Name:   []string{"Trisha", "McMillen"},
   483						Weight: 5.5,
   484					},
   485					{
   486						Name:   []string{"Ford", "Prefect"},
   487						Weight: 7,
   488					},
   489					{
   490						Name:   []string{"Arthur", "Dent"},
   491						Weight: 6.75,
   492					},
   493				},
   494			},
   495			ExpectXML: `<spaceship name="Heart of Gold" pilot="Computer">` +
   496				`<drive>` + strconv.Itoa(int(ImprobabilityDrive)) + `</drive>` +
   497				`<age>1</age>` +
   498				`<passenger>` +
   499				`<name>Zaphod</name>` +
   500				`<name>Beeblebrox</name>` +
   501				`<weight>7.25</weight>` +
   502				`</passenger>` +
   503				`<passenger>` +
   504				`<name>Trisha</name>` +
   505				`<name>McMillen</name>` +
   506				`<weight>5.5</weight>` +
   507				`</passenger>` +
   508				`<passenger>` +
   509				`<name>Ford</name>` +
   510				`<name>Prefect</name>` +
   511				`<weight>7</weight>` +
   512				`</passenger>` +
   513				`<passenger>` +
   514				`<name>Arthur</name>` +
   515				`<name>Dent</name>` +
   516				`<weight>6.75</weight>` +
   517				`</passenger>` +
   518				`</spaceship>`,
   519		},
   520	
   521		// Test a>b
   522		{
   523			Value: &NestedItems{Items: nil, Item1: nil},
   524			ExpectXML: `<result>` +
   525				`<Items>` +
   526				`</Items>` +
   527				`</result>`,
   528		},
   529		{
   530			Value: &NestedItems{Items: []string{}, Item1: []string{}},
   531			ExpectXML: `<result>` +
   532				`<Items>` +
   533				`</Items>` +
   534				`</result>`,
   535			MarshalOnly: true,
   536		},
   537		{
   538			Value: &NestedItems{Items: nil, Item1: []string{"A"}},
   539			ExpectXML: `<result>` +
   540				`<Items>` +
   541				`<item1>A</item1>` +
   542				`</Items>` +
   543				`</result>`,
   544		},
   545		{
   546			Value: &NestedItems{Items: []string{"A", "B"}, Item1: nil},
   547			ExpectXML: `<result>` +
   548				`<Items>` +
   549				`<item>A</item>` +
   550				`<item>B</item>` +
   551				`</Items>` +
   552				`</result>`,
   553		},
   554		{
   555			Value: &NestedItems{Items: []string{"A", "B"}, Item1: []string{"C"}},
   556			ExpectXML: `<result>` +
   557				`<Items>` +
   558				`<item>A</item>` +
   559				`<item>B</item>` +
   560				`<item1>C</item1>` +
   561				`</Items>` +
   562				`</result>`,
   563		},
   564		{
   565			Value: &NestedOrder{Field1: "C", Field2: "B", Field3: "A"},
   566			ExpectXML: `<result>` +
   567				`<parent>` +
   568				`<c>C</c>` +
   569				`<b>B</b>` +
   570				`<a>A</a>` +
   571				`</parent>` +
   572				`</result>`,
   573		},
   574		{
   575			Value: &NilTest{A: "A", B: nil, C: "C"},
   576			ExpectXML: `<NilTest>` +
   577				`<parent1>` +
   578				`<parent2><a>A</a></parent2>` +
   579				`<parent2><c>C</c></parent2>` +
   580				`</parent1>` +
   581				`</NilTest>`,
   582			MarshalOnly: true, // Uses interface{}
   583		},
   584		{
   585			Value: &MixedNested{A: "A", B: "B", C: "C", D: "D"},
   586			ExpectXML: `<result>` +
   587				`<parent1><a>A</a></parent1>` +
   588				`<b>B</b>` +
   589				`<parent1>` +
   590				`<parent2><c>C</c></parent2>` +
   591				`<d>D</d>` +
   592				`</parent1>` +
   593				`</result>`,
   594		},
   595		{
   596			Value:     &Service{Port: &Port{Number: "80"}},
   597			ExpectXML: `<service><host><port>80</port></host></service>`,
   598		},
   599		{
   600			Value:     &Service{},
   601			ExpectXML: `<service></service>`,
   602		},
   603		{
   604			Value: &Service{Port: &Port{Number: "80"}, Extra1: "A", Extra2: "B"},
   605			ExpectXML: `<service>` +
   606				`<host><port>80</port></host>` +
   607				`<Extra1>A</Extra1>` +
   608				`<host><extra2>B</extra2></host>` +
   609				`</service>`,
   610			MarshalOnly: true,
   611		},
   612		{
   613			Value: &Service{Port: &Port{Number: "80"}, Extra2: "example"},
   614			ExpectXML: `<service>` +
   615				`<host><port>80</port></host>` +
   616				`<host><extra2>example</extra2></host>` +
   617				`</service>`,
   618			MarshalOnly: true,
   619		},
   620	
   621		// Test struct embedding
   622		{
   623			Value: &EmbedA{
   624				EmbedC: EmbedC{
   625					FieldA1: "", // Shadowed by A.A
   626					FieldA2: "", // Shadowed by A.A
   627					FieldB:  "A.C.B",
   628					FieldC:  "A.C.C",
   629				},
   630				EmbedB: EmbedB{
   631					FieldB: "A.B.B",
   632					EmbedC: &EmbedC{
   633						FieldA1: "A.B.C.A1",
   634						FieldA2: "A.B.C.A2",
   635						FieldB:  "", // Shadowed by A.B.B
   636						FieldC:  "A.B.C.C",
   637					},
   638				},
   639				FieldA: "A.A",
   640			},
   641			ExpectXML: `<EmbedA>` +
   642				`<FieldB>A.C.B</FieldB>` +
   643				`<FieldC>A.C.C</FieldC>` +
   644				`<EmbedB>` +
   645				`<FieldB>A.B.B</FieldB>` +
   646				`<FieldA>` +
   647				`<A1>A.B.C.A1</A1>` +
   648				`<A2>A.B.C.A2</A2>` +
   649				`</FieldA>` +
   650				`<FieldC>A.B.C.C</FieldC>` +
   651				`</EmbedB>` +
   652				`<FieldA>A.A</FieldA>` +
   653				`</EmbedA>`,
   654		},
   655	
   656		// Test that name casing matters
   657		{
   658			Value:     &NameCasing{Xy: "mixed", XY: "upper", XyA: "mixedA", XYA: "upperA"},
   659			ExpectXML: `<casing Xy="mixedA" XY="upperA"><Xy>mixed</Xy><XY>upper</XY></casing>`,
   660		},
   661	
   662		// Test the order in which the XML element name is chosen
   663		{
   664			Value: &NamePrecedence{
   665				FromTag:     XMLNameWithoutTag{Value: "A"},
   666				FromNameVal: XMLNameWithoutTag{XMLName: Name{Local: "InXMLName"}, Value: "B"},
   667				FromNameTag: XMLNameWithTag{Value: "C"},
   668				InFieldName: "D",
   669			},
   670			ExpectXML: `<Parent>` +
   671				`<InTag>A</InTag>` +
   672				`<InXMLName>B</InXMLName>` +
   673				`<InXMLNameTag>C</InXMLNameTag>` +
   674				`<InFieldName>D</InFieldName>` +
   675				`</Parent>`,
   676			MarshalOnly: true,
   677		},
   678		{
   679			Value: &NamePrecedence{
   680				XMLName:     Name{Local: "Parent"},
   681				FromTag:     XMLNameWithoutTag{XMLName: Name{Local: "InTag"}, Value: "A"},
   682				FromNameVal: XMLNameWithoutTag{XMLName: Name{Local: "FromNameVal"}, Value: "B"},
   683				FromNameTag: XMLNameWithTag{XMLName: Name{Local: "InXMLNameTag"}, Value: "C"},
   684				InFieldName: "D",
   685			},
   686			ExpectXML: `<Parent>` +
   687				`<InTag>A</InTag>` +
   688				`<FromNameVal>B</FromNameVal>` +
   689				`<InXMLNameTag>C</InXMLNameTag>` +
   690				`<InFieldName>D</InFieldName>` +
   691				`</Parent>`,
   692			UnmarshalOnly: true,
   693		},
   694	
   695		// xml.Name works in a plain field as well.
   696		{
   697			Value:     &NameInField{Name{Space: "ns", Local: "foo"}},
   698			ExpectXML: `<NameInField><foo xmlns="ns"></foo></NameInField>`,
   699		},
   700		{
   701			Value:         &NameInField{Name{Space: "ns", Local: "foo"}},
   702			ExpectXML:     `<NameInField><foo xmlns="ns"><ignore></ignore></foo></NameInField>`,
   703			UnmarshalOnly: true,
   704		},
   705	
   706		// Marshaling zero xml.Name uses the tag or field name.
   707		{
   708			Value:       &NameInField{},
   709			ExpectXML:   `<NameInField><foo xmlns="ns"></foo></NameInField>`,
   710			MarshalOnly: true,
   711		},
   712	
   713		// Test attributes
   714		{
   715			Value: &AttrTest{
   716				Int:   8,
   717				Named: 9,
   718				Float: 23.5,
   719				Uint8: 255,
   720				Bool:  true,
   721				Str:   "str",
   722				Bytes: []byte("byt"),
   723			},
   724			ExpectXML: `<AttrTest Int="8" int="9" Float="23.5" Uint8="255"` +
   725				` Bool="true" Str="str" Bytes="byt"></AttrTest>`,
   726		},
   727		{
   728			Value: &AttrTest{Bytes: []byte{}},
   729			ExpectXML: `<AttrTest Int="0" int="0" Float="0" Uint8="0"` +
   730				` Bool="false" Str="" Bytes=""></AttrTest>`,
   731		},
   732		{
   733			Value: &OmitAttrTest{
   734				Int:   8,
   735				Named: 9,
   736				Float: 23.5,
   737				Uint8: 255,
   738				Bool:  true,
   739				Str:   "str",
   740				Bytes: []byte("byt"),
   741			},
   742			ExpectXML: `<OmitAttrTest Int="8" int="9" Float="23.5" Uint8="255"` +
   743				` Bool="true" Str="str" Bytes="byt"></OmitAttrTest>`,
   744		},
   745		{
   746			Value:     &OmitAttrTest{},
   747			ExpectXML: `<OmitAttrTest></OmitAttrTest>`,
   748		},
   749	
   750		// pointer fields
   751		{
   752			Value:       &PointerFieldsTest{Name: &nameAttr, Age: &ageAttr, Contents: &contentsAttr},
   753			ExpectXML:   `<dummy name="Sarah" age="12">lorem ipsum</dummy>`,
   754			MarshalOnly: true,
   755		},
   756	
   757		// empty chardata pointer field
   758		{
   759			Value:       &ChardataEmptyTest{},
   760			ExpectXML:   `<test></test>`,
   761			MarshalOnly: true,
   762		},
   763	
   764		// omitempty on fields
   765		{
   766			Value: &OmitFieldTest{
   767				Int:   8,
   768				Named: 9,
   769				Float: 23.5,
   770				Uint8: 255,
   771				Bool:  true,
   772				Str:   "str",
   773				Bytes: []byte("byt"),
   774				Ptr:   &PresenceTest{},
   775			},
   776			ExpectXML: `<OmitFieldTest>` +
   777				`<Int>8</Int>` +
   778				`<int>9</int>` +
   779				`<Float>23.5</Float>` +
   780				`<Uint8>255</Uint8>` +
   781				`<Bool>true</Bool>` +
   782				`<Str>str</Str>` +
   783				`<Bytes>byt</Bytes>` +
   784				`<Ptr></Ptr>` +
   785				`</OmitFieldTest>`,
   786		},
   787		{
   788			Value:     &OmitFieldTest{},
   789			ExpectXML: `<OmitFieldTest></OmitFieldTest>`,
   790		},
   791	
   792		// Test ",any"
   793		{
   794			ExpectXML: `<a><nested><value>known</value></nested><other><sub>unknown</sub></other></a>`,
   795			Value: &AnyTest{
   796				Nested: "known",
   797				AnyField: AnyHolder{
   798					XMLName: Name{Local: "other"},
   799					XML:     "<sub>unknown</sub>",
   800				},
   801			},
   802		},
   803		{
   804			Value: &AnyTest{Nested: "known",
   805				AnyField: AnyHolder{
   806					XML:     "<unknown/>",
   807					XMLName: Name{Local: "AnyField"},
   808				},
   809			},
   810			ExpectXML: `<a><nested><value>known</value></nested><AnyField><unknown/></AnyField></a>`,
   811		},
   812		{
   813			ExpectXML: `<a><nested><value>b</value></nested></a>`,
   814			Value: &AnyOmitTest{
   815				Nested: "b",
   816			},
   817		},
   818		{
   819			ExpectXML: `<a><nested><value>b</value></nested><c><d>e</d></c><g xmlns="f"><h>i</h></g></a>`,
   820			Value: &AnySliceTest{
   821				Nested: "b",
   822				AnyField: []AnyHolder{
   823					{
   824						XMLName: Name{Local: "c"},
   825						XML:     "<d>e</d>",
   826					},
   827					{
   828						XMLName: Name{Space: "f", Local: "g"},
   829						XML:     "<h>i</h>",
   830					},
   831				},
   832			},
   833		},
   834		{
   835			ExpectXML: `<a><nested><value>b</value></nested></a>`,
   836			Value: &AnySliceTest{
   837				Nested: "b",
   838			},
   839		},
   840	
   841		// Test recursive types.
   842		{
   843			Value: &RecurseA{
   844				A: "a1",
   845				B: &RecurseB{
   846					A: &RecurseA{"a2", nil},
   847					B: "b1",
   848				},
   849			},
   850			ExpectXML: `<RecurseA><A>a1</A><B><A><A>a2</A></A><B>b1</B></B></RecurseA>`,
   851		},
   852	
   853		// Test ignoring fields via "-" tag
   854		{
   855			ExpectXML: `<IgnoreTest></IgnoreTest>`,
   856			Value:     &IgnoreTest{},
   857		},
   858		{
   859			ExpectXML:   `<IgnoreTest></IgnoreTest>`,
   860			Value:       &IgnoreTest{PublicSecret: "can't tell"},
   861			MarshalOnly: true,
   862		},
   863		{
   864			ExpectXML:     `<IgnoreTest><PublicSecret>ignore me</PublicSecret></IgnoreTest>`,
   865			Value:         &IgnoreTest{},
   866			UnmarshalOnly: true,
   867		},
   868	
   869		// Test escaping.
   870		{
   871			ExpectXML: `<a><nested><value>dquote: &#34;; squote: &#39;; ampersand: &amp;; less: &lt;; greater: &gt;;</value></nested><empty></empty></a>`,
   872			Value: &AnyTest{
   873				Nested:   `dquote: "; squote: '; ampersand: &; less: <; greater: >;`,
   874				AnyField: AnyHolder{XMLName: Name{Local: "empty"}},
   875			},
   876		},
   877		{
   878			ExpectXML: `<a><nested><value>newline: &#xA;; cr: &#xD;; tab: &#x9;;</value></nested><AnyField></AnyField></a>`,
   879			Value: &AnyTest{
   880				Nested:   "newline: \n; cr: \r; tab: \t;",
   881				AnyField: AnyHolder{XMLName: Name{Local: "AnyField"}},
   882			},
   883		},
   884		{
   885			ExpectXML: "<a><nested><value>1\r2\r\n3\n\r4\n5</value></nested></a>",
   886			Value: &AnyTest{
   887				Nested: "1\n2\n3\n\n4\n5",
   888			},
   889			UnmarshalOnly: true,
   890		},
   891		{
   892			ExpectXML: `<EmbedInt><MyInt>42</MyInt></EmbedInt>`,
   893			Value: &EmbedInt{
   894				MyInt: 42,
   895			},
   896		},
   897		// Test omitempty with parent chain; see golang.org/issue/4168.
   898		{
   899			ExpectXML: `<Strings><A></A></Strings>`,
   900			Value:     &Strings{},
   901		},
   902		// Custom marshalers.
   903		{
   904			ExpectXML: `<MyMarshalerTest>hello world</MyMarshalerTest>`,
   905			Value:     &MyMarshalerTest{},
   906		},
   907		{
   908			ExpectXML: `<MarshalerStruct Foo="hello world"></MarshalerStruct>`,
   909			Value:     &MarshalerStruct{},
   910		},
   911		{
   912			ExpectXML: `<outer xmlns="testns" int="10"></outer>`,
   913			Value:     &OuterStruct{IntAttr: 10},
   914		},
   915		{
   916			ExpectXML: `<test xmlns="outerns" int="10"></test>`,
   917			Value:     &OuterNamedStruct{XMLName: Name{Space: "outerns", Local: "test"}, IntAttr: 10},
   918		},
   919		{
   920			ExpectXML: `<test xmlns="outerns" int="10"></test>`,
   921			Value:     &OuterNamedOrderedStruct{XMLName: Name{Space: "outerns", Local: "test"}, IntAttr: 10},
   922		},
   923		{
   924			ExpectXML: `<outer xmlns="testns" int="10"></outer>`,
   925			Value:     &OuterOuterStruct{OuterStruct{IntAttr: 10}},
   926		},
   927	}
   928	
   929	func TestMarshal(t *testing.T) {
   930		for idx, test := range marshalTests {
   931			if test.UnmarshalOnly {
   932				continue
   933			}
   934			data, err := Marshal(test.Value)
   935			if err != nil {
   936				t.Errorf("#%d: Error: %s", idx, err)
   937				continue
   938			}
   939			if got, want := string(data), test.ExpectXML; got != want {
   940				if strings.Contains(want, "\n") {
   941					t.Errorf("#%d: marshal(%#v):\nHAVE:\n%s\nWANT:\n%s", idx, test.Value, got, want)
   942				} else {
   943					t.Errorf("#%d: marshal(%#v):\nhave %#q\nwant %#q", idx, test.Value, got, want)
   944				}
   945			}
   946		}
   947	}
   948	
   949	type AttrParent struct {
   950		X string `xml:"X>Y,attr"`
   951	}
   952	
   953	type BadAttr struct {
   954		Name []string `xml:"name,attr"`
   955	}
   956	
   957	var marshalErrorTests = []struct {
   958		Value interface{}
   959		Err   string
   960		Kind  reflect.Kind
   961	}{
   962		{
   963			Value: make(chan bool),
   964			Err:   "xml: unsupported type: chan bool",
   965			Kind:  reflect.Chan,
   966		},
   967		{
   968			Value: map[string]string{
   969				"question": "What do you get when you multiply six by nine?",
   970				"answer":   "42",
   971			},
   972			Err:  "xml: unsupported type: map[string]string",
   973			Kind: reflect.Map,
   974		},
   975		{
   976			Value: map[*Ship]bool{nil: false},
   977			Err:   "xml: unsupported type: map[*xml.Ship]bool",
   978			Kind:  reflect.Map,
   979		},
   980		{
   981			Value: &Domain{Comment: []byte("f--bar")},
   982			Err:   `xml: comments must not contain "--"`,
   983		},
   984		// Reject parent chain with attr, never worked; see golang.org/issue/5033.
   985		{
   986			Value: &AttrParent{},
   987			Err:   `xml: X>Y chain not valid with attr flag`,
   988		},
   989		{
   990			Value: BadAttr{[]string{"X", "Y"}},
   991			Err:   `xml: unsupported type: []string`,
   992		},
   993	}
   994	
   995	var marshalIndentTests = []struct {
   996		Value     interface{}
   997		Prefix    string
   998		Indent    string
   999		ExpectXML string
  1000	}{
  1001		{
  1002			Value: &SecretAgent{
  1003				Handle:    "007",
  1004				Identity:  "James Bond",
  1005				Obfuscate: "<redacted/>",
  1006			},
  1007			Prefix:    "",
  1008			Indent:    "\t",
  1009			ExpectXML: fmt.Sprintf("<agent handle=\"007\">\n\t<Identity>James Bond</Identity><redacted/>\n</agent>"),
  1010		},
  1011	}
  1012	
  1013	func TestMarshalErrors(t *testing.T) {
  1014		for idx, test := range marshalErrorTests {
  1015			data, err := Marshal(test.Value)
  1016			if err == nil {
  1017				t.Errorf("#%d: marshal(%#v) = [success] %q, want error %v", idx, test.Value, data, test.Err)
  1018				continue
  1019			}
  1020			if err.Error() != test.Err {
  1021				t.Errorf("#%d: marshal(%#v) = [error] %v, want %v", idx, test.Value, err, test.Err)
  1022			}
  1023			if test.Kind != reflect.Invalid {
  1024				if kind := err.(*UnsupportedTypeError).Type.Kind(); kind != test.Kind {
  1025					t.Errorf("#%d: marshal(%#v) = [error kind] %s, want %s", idx, test.Value, kind, test.Kind)
  1026				}
  1027			}
  1028		}
  1029	}
  1030	
  1031	// Do invertibility testing on the various structures that we test
  1032	func TestUnmarshal(t *testing.T) {
  1033		for i, test := range marshalTests {
  1034			if test.MarshalOnly {
  1035				continue
  1036			}
  1037			if _, ok := test.Value.(*Plain); ok {
  1038				continue
  1039			}
  1040	
  1041			vt := reflect.TypeOf(test.Value)
  1042			dest := reflect.New(vt.Elem()).Interface()
  1043			err := Unmarshal([]byte(test.ExpectXML), dest)
  1044	
  1045			switch fix := dest.(type) {
  1046			case *Feed:
  1047				fix.Author.InnerXML = ""
  1048				for i := range fix.Entry {
  1049					fix.Entry[i].Author.InnerXML = ""
  1050				}
  1051			}
  1052	
  1053			if err != nil {
  1054				t.Errorf("#%d: unexpected error: %#v", i, err)
  1055			} else if got, want := dest, test.Value; !reflect.DeepEqual(got, want) {
  1056				t.Errorf("#%d: unmarshal(%q):\nhave %#v\nwant %#v", i, test.ExpectXML, got, want)
  1057			}
  1058		}
  1059	}
  1060	
  1061	func TestMarshalIndent(t *testing.T) {
  1062		for i, test := range marshalIndentTests {
  1063			data, err := MarshalIndent(test.Value, test.Prefix, test.Indent)
  1064			if err != nil {
  1065				t.Errorf("#%d: Error: %s", i, err)
  1066				continue
  1067			}
  1068			if got, want := string(data), test.ExpectXML; got != want {
  1069				t.Errorf("#%d: MarshalIndent:\nGot:%s\nWant:\n%s", i, got, want)
  1070			}
  1071		}
  1072	}
  1073	
  1074	type limitedBytesWriter struct {
  1075		w      io.Writer
  1076		remain int // until writes fail
  1077	}
  1078	
  1079	func (lw *limitedBytesWriter) Write(p []byte) (n int, err error) {
  1080		if lw.remain <= 0 {
  1081			println("error")
  1082			return 0, errors.New("write limit hit")
  1083		}
  1084		if len(p) > lw.remain {
  1085			p = p[:lw.remain]
  1086			n, _ = lw.w.Write(p)
  1087			lw.remain = 0
  1088			return n, errors.New("write limit hit")
  1089		}
  1090		n, err = lw.w.Write(p)
  1091		lw.remain -= n
  1092		return n, err
  1093	}
  1094	
  1095	func TestMarshalWriteErrors(t *testing.T) {
  1096		var buf bytes.Buffer
  1097		const writeCap = 1024
  1098		w := &limitedBytesWriter{&buf, writeCap}
  1099		enc := NewEncoder(w)
  1100		var err error
  1101		var i int
  1102		const n = 4000
  1103		for i = 1; i <= n; i++ {
  1104			err = enc.Encode(&Passenger{
  1105				Name:   []string{"Alice", "Bob"},
  1106				Weight: 5,
  1107			})
  1108			if err != nil {
  1109				break
  1110			}
  1111		}
  1112		if err == nil {
  1113			t.Error("expected an error")
  1114		}
  1115		if i == n {
  1116			t.Errorf("expected to fail before the end")
  1117		}
  1118		if buf.Len() != writeCap {
  1119			t.Errorf("buf.Len() = %d; want %d", buf.Len(), writeCap)
  1120		}
  1121	}
  1122	
  1123	func TestMarshalWriteIOErrors(t *testing.T) {
  1124		enc := NewEncoder(errWriter{})
  1125	
  1126		expectErr := "unwritable"
  1127		err := enc.Encode(&Passenger{})
  1128		if err == nil || err.Error() != expectErr {
  1129			t.Errorf("EscapeTest = [error] %v, want %v", err, expectErr)
  1130		}
  1131	}
  1132	
  1133	func TestMarshalFlush(t *testing.T) {
  1134		var buf bytes.Buffer
  1135		enc := NewEncoder(&buf)
  1136		if err := enc.EncodeToken(CharData("hello world")); err != nil {
  1137			t.Fatalf("enc.EncodeToken: %v", err)
  1138		}
  1139		if buf.Len() > 0 {
  1140			t.Fatalf("enc.EncodeToken caused actual write: %q", buf.Bytes())
  1141		}
  1142		if err := enc.Flush(); err != nil {
  1143			t.Fatalf("enc.Flush: %v", err)
  1144		}
  1145		if buf.String() != "hello world" {
  1146			t.Fatalf("after enc.Flush, buf.String() = %q, want %q", buf.String(), "hello world")
  1147		}
  1148	}
  1149	
  1150	func BenchmarkMarshal(b *testing.B) {
  1151		for i := 0; i < b.N; i++ {
  1152			Marshal(atomValue)
  1153		}
  1154	}
  1155	
  1156	func BenchmarkUnmarshal(b *testing.B) {
  1157		xml := []byte(atomXml)
  1158		for i := 0; i < b.N; i++ {
  1159			Unmarshal(xml, &Feed{})
  1160		}
  1161	}
  1162	
  1163	// golang.org/issue/6556
  1164	func TestStructPointerMarshal(t *testing.T) {
  1165		type A struct {
  1166			XMLName string `xml:"a"`
  1167			B       []interface{}
  1168		}
  1169		type C struct {
  1170			XMLName Name
  1171			Value   string `xml:"value"`
  1172		}
  1173	
  1174		a := new(A)
  1175		a.B = append(a.B, &C{
  1176			XMLName: Name{Local: "c"},
  1177			Value:   "x",
  1178		})
  1179	
  1180		b, err := Marshal(a)
  1181		if err != nil {
  1182			t.Fatal(err)
  1183		}
  1184		if x := string(b); x != "<a><c><value>x</value></c></a>" {
  1185			t.Fatal(x)
  1186		}
  1187		var v A
  1188		err = Unmarshal(b, &v)
  1189		if err != nil {
  1190			t.Fatal(err)
  1191		}
  1192	}
  1193	
  1194	var encodeTokenTests = []struct {
  1195		tok  Token
  1196		want string
  1197		ok   bool
  1198	}{
  1199		{StartElement{Name{"space", "local"}, nil}, "<local xmlns=\"space\">", true},
  1200		{StartElement{Name{"space", ""}, nil}, "", false},
  1201		{EndElement{Name{"space", ""}}, "", false},
  1202		{CharData("foo"), "foo", true},
  1203		{Comment("foo"), "<!--foo-->", true},
  1204		{Comment("foo-->"), "", false},
  1205		{ProcInst{"Target", []byte("Instruction")}, "<?Target Instruction?>", true},
  1206		{ProcInst{"", []byte("Instruction")}, "", false},
  1207		{ProcInst{"Target", []byte("Instruction?>")}, "", false},
  1208		{Directive("foo"), "<!foo>", true},
  1209		{Directive("foo>"), "", false},
  1210	}
  1211	
  1212	func TestEncodeToken(t *testing.T) {
  1213		for _, tt := range encodeTokenTests {
  1214			var buf bytes.Buffer
  1215			enc := NewEncoder(&buf)
  1216			err := enc.EncodeToken(tt.tok)
  1217			switch {
  1218			case !tt.ok && err == nil:
  1219				t.Errorf("enc.EncodeToken(%#v): expected error; got none", tt.tok)
  1220			case tt.ok && err != nil:
  1221				t.Fatalf("enc.EncodeToken: %v", err)
  1222			case !tt.ok && err != nil:
  1223				// expected error, got one
  1224			}
  1225			if err := enc.Flush(); err != nil {
  1226				t.Fatalf("enc.EncodeToken: %v", err)
  1227			}
  1228			if got := buf.String(); got != tt.want {
  1229				t.Errorf("enc.EncodeToken = %s; want: %s", got, tt.want)
  1230			}
  1231		}
  1232	}
  1233	
  1234	func TestProcInstEncodeToken(t *testing.T) {
  1235		var buf bytes.Buffer
  1236		enc := NewEncoder(&buf)
  1237	
  1238		if err := enc.EncodeToken(ProcInst{"xml", []byte("Instruction")}); err != nil {
  1239			t.Fatalf("enc.EncodeToken: expected to be able to encode xml target ProcInst as first token, %s", err)
  1240		}
  1241	
  1242		if err := enc.EncodeToken(ProcInst{"Target", []byte("Instruction")}); err != nil {
  1243			t.Fatalf("enc.EncodeToken: expected to be able to add non-xml target ProcInst")
  1244		}
  1245	
  1246		if err := enc.EncodeToken(ProcInst{"xml", []byte("Instruction")}); err == nil {
  1247			t.Fatalf("enc.EncodeToken: expected to not be allowed to encode xml target ProcInst when not first token")
  1248		}
  1249	}
  1250	
  1251	func TestDecodeEncode(t *testing.T) {
  1252		var in, out bytes.Buffer
  1253		in.WriteString(`<?xml version="1.0" encoding="UTF-8"?>
  1254	<?Target Instruction?>
  1255	<root>
  1256	</root>	
  1257	`)
  1258		dec := NewDecoder(&in)
  1259		enc := NewEncoder(&out)
  1260		for tok, err := dec.Token(); err == nil; tok, err = dec.Token() {
  1261			err = enc.EncodeToken(tok)
  1262			if err != nil {
  1263				t.Fatalf("enc.EncodeToken: Unable to encode token (%#v), %v", tok, err)
  1264			}
  1265		}
  1266	}
  1267	

View as plain text