...
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		"sync"
    16		"testing"
    17		"time"
    18	)
    19	
    20	type DriveType int
    21	
    22	const (
    23		HyperDrive DriveType = iota
    24		ImprobabilityDrive
    25	)
    26	
    27	type Passenger struct {
    28		Name   []string `xml:"name"`
    29		Weight float32  `xml:"weight"`
    30	}
    31	
    32	type Ship struct {
    33		XMLName struct{} `xml:"spaceship"`
    34	
    35		Name      string       `xml:"name,attr"`
    36		Pilot     string       `xml:"pilot,attr"`
    37		Drive     DriveType    `xml:"drive"`
    38		Age       uint         `xml:"age"`
    39		Passenger []*Passenger `xml:"passenger"`
    40		secret    string
    41	}
    42	
    43	type NamedType string
    44	
    45	type Port struct {
    46		XMLName struct{} `xml:"port"`
    47		Type    string   `xml:"type,attr,omitempty"`
    48		Comment string   `xml:",comment"`
    49		Number  string   `xml:",chardata"`
    50	}
    51	
    52	type Domain struct {
    53		XMLName struct{} `xml:"domain"`
    54		Country string   `xml:",attr,omitempty"`
    55		Name    []byte   `xml:",chardata"`
    56		Comment []byte   `xml:",comment"`
    57	}
    58	
    59	type Book struct {
    60		XMLName struct{} `xml:"book"`
    61		Title   string   `xml:",chardata"`
    62	}
    63	
    64	type Event struct {
    65		XMLName struct{} `xml:"event"`
    66		Year    int      `xml:",chardata"`
    67	}
    68	
    69	type Movie struct {
    70		XMLName struct{} `xml:"movie"`
    71		Length  uint     `xml:",chardata"`
    72	}
    73	
    74	type Pi struct {
    75		XMLName       struct{} `xml:"pi"`
    76		Approximation float32  `xml:",chardata"`
    77	}
    78	
    79	type Universe struct {
    80		XMLName struct{} `xml:"universe"`
    81		Visible float64  `xml:",chardata"`
    82	}
    83	
    84	type Particle struct {
    85		XMLName struct{} `xml:"particle"`
    86		HasMass bool     `xml:",chardata"`
    87	}
    88	
    89	type Departure struct {
    90		XMLName struct{}  `xml:"departure"`
    91		When    time.Time `xml:",chardata"`
    92	}
    93	
    94	type SecretAgent struct {
    95		XMLName   struct{} `xml:"agent"`
    96		Handle    string   `xml:"handle,attr"`
    97		Identity  string
    98		Obfuscate string `xml:",innerxml"`
    99	}
   100	
   101	type NestedItems struct {
   102		XMLName struct{} `xml:"result"`
   103		Items   []string `xml:">item"`
   104		Item1   []string `xml:"Items>item1"`
   105	}
   106	
   107	type NestedOrder struct {
   108		XMLName struct{} `xml:"result"`
   109		Field1  string   `xml:"parent>c"`
   110		Field2  string   `xml:"parent>b"`
   111		Field3  string   `xml:"parent>a"`
   112	}
   113	
   114	type MixedNested struct {
   115		XMLName struct{} `xml:"result"`
   116		A       string   `xml:"parent1>a"`
   117		B       string   `xml:"b"`
   118		C       string   `xml:"parent1>parent2>c"`
   119		D       string   `xml:"parent1>d"`
   120	}
   121	
   122	type NilTest struct {
   123		A interface{} `xml:"parent1>parent2>a"`
   124		B interface{} `xml:"parent1>b"`
   125		C interface{} `xml:"parent1>parent2>c"`
   126	}
   127	
   128	type Service struct {
   129		XMLName struct{} `xml:"service"`
   130		Domain  *Domain  `xml:"host>domain"`
   131		Port    *Port    `xml:"host>port"`
   132		Extra1  interface{}
   133		Extra2  interface{} `xml:"host>extra2"`
   134	}
   135	
   136	var nilStruct *Ship
   137	
   138	type EmbedA struct {
   139		EmbedC
   140		EmbedB EmbedB
   141		FieldA string
   142		embedD
   143	}
   144	
   145	type EmbedB struct {
   146		FieldB string
   147		*EmbedC
   148	}
   149	
   150	type EmbedC struct {
   151		FieldA1 string `xml:"FieldA>A1"`
   152		FieldA2 string `xml:"FieldA>A2"`
   153		FieldB  string
   154		FieldC  string
   155	}
   156	
   157	type embedD struct {
   158		fieldD string
   159		FieldE string // Promoted and visible when embedD is embedded.
   160	}
   161	
   162	type NameCasing struct {
   163		XMLName struct{} `xml:"casing"`
   164		Xy      string
   165		XY      string
   166		XyA     string `xml:"Xy,attr"`
   167		XYA     string `xml:"XY,attr"`
   168	}
   169	
   170	type NamePrecedence struct {
   171		XMLName     Name              `xml:"Parent"`
   172		FromTag     XMLNameWithoutTag `xml:"InTag"`
   173		FromNameVal XMLNameWithoutTag
   174		FromNameTag XMLNameWithTag
   175		InFieldName string
   176	}
   177	
   178	type XMLNameWithTag struct {
   179		XMLName Name   `xml:"InXMLNameTag"`
   180		Value   string `xml:",chardata"`
   181	}
   182	
   183	type XMLNameWithoutTag struct {
   184		XMLName Name
   185		Value   string `xml:",chardata"`
   186	}
   187	
   188	type NameInField struct {
   189		Foo Name `xml:"ns foo"`
   190	}
   191	
   192	type AttrTest struct {
   193		Int   int     `xml:",attr"`
   194		Named int     `xml:"int,attr"`
   195		Float float64 `xml:",attr"`
   196		Uint8 uint8   `xml:",attr"`
   197		Bool  bool    `xml:",attr"`
   198		Str   string  `xml:",attr"`
   199		Bytes []byte  `xml:",attr"`
   200	}
   201	
   202	type OmitAttrTest struct {
   203		Int   int     `xml:",attr,omitempty"`
   204		Named int     `xml:"int,attr,omitempty"`
   205		Float float64 `xml:",attr,omitempty"`
   206		Uint8 uint8   `xml:",attr,omitempty"`
   207		Bool  bool    `xml:",attr,omitempty"`
   208		Str   string  `xml:",attr,omitempty"`
   209		Bytes []byte  `xml:",attr,omitempty"`
   210	}
   211	
   212	type OmitFieldTest struct {
   213		Int   int           `xml:",omitempty"`
   214		Named int           `xml:"int,omitempty"`
   215		Float float64       `xml:",omitempty"`
   216		Uint8 uint8         `xml:",omitempty"`
   217		Bool  bool          `xml:",omitempty"`
   218		Str   string        `xml:",omitempty"`
   219		Bytes []byte        `xml:",omitempty"`
   220		Ptr   *PresenceTest `xml:",omitempty"`
   221	}
   222	
   223	type AnyTest struct {
   224		XMLName  struct{}  `xml:"a"`
   225		Nested   string    `xml:"nested>value"`
   226		AnyField AnyHolder `xml:",any"`
   227	}
   228	
   229	type AnyOmitTest struct {
   230		XMLName  struct{}   `xml:"a"`
   231		Nested   string     `xml:"nested>value"`
   232		AnyField *AnyHolder `xml:",any,omitempty"`
   233	}
   234	
   235	type AnySliceTest struct {
   236		XMLName  struct{}    `xml:"a"`
   237		Nested   string      `xml:"nested>value"`
   238		AnyField []AnyHolder `xml:",any"`
   239	}
   240	
   241	type AnyHolder struct {
   242		XMLName Name
   243		XML     string `xml:",innerxml"`
   244	}
   245	
   246	type RecurseA struct {
   247		A string
   248		B *RecurseB
   249	}
   250	
   251	type RecurseB struct {
   252		A *RecurseA
   253		B string
   254	}
   255	
   256	type PresenceTest struct {
   257		Exists *struct{}
   258	}
   259	
   260	type IgnoreTest struct {
   261		PublicSecret string `xml:"-"`
   262	}
   263	
   264	type MyBytes []byte
   265	
   266	type Data struct {
   267		Bytes  []byte
   268		Attr   []byte `xml:",attr"`
   269		Custom MyBytes
   270	}
   271	
   272	type Plain struct {
   273		V interface{}
   274	}
   275	
   276	type MyInt int
   277	
   278	type EmbedInt struct {
   279		MyInt
   280	}
   281	
   282	type Strings struct {
   283		X []string `xml:"A>B,omitempty"`
   284	}
   285	
   286	type PointerFieldsTest struct {
   287		XMLName  Name    `xml:"dummy"`
   288		Name     *string `xml:"name,attr"`
   289		Age      *uint   `xml:"age,attr"`
   290		Empty    *string `xml:"empty,attr"`
   291		Contents *string `xml:",chardata"`
   292	}
   293	
   294	type ChardataEmptyTest struct {
   295		XMLName  Name    `xml:"test"`
   296		Contents *string `xml:",chardata"`
   297	}
   298	
   299	type MyMarshalerTest struct {
   300	}
   301	
   302	var _ Marshaler = (*MyMarshalerTest)(nil)
   303	
   304	func (m *MyMarshalerTest) MarshalXML(e *Encoder, start StartElement) error {
   305		e.EncodeToken(start)
   306		e.EncodeToken(CharData([]byte("hello world")))
   307		e.EncodeToken(EndElement{start.Name})
   308		return nil
   309	}
   310	
   311	type MyMarshalerAttrTest struct {
   312	}
   313	
   314	var _ MarshalerAttr = (*MyMarshalerAttrTest)(nil)
   315	
   316	func (m *MyMarshalerAttrTest) MarshalXMLAttr(name Name) (Attr, error) {
   317		return Attr{name, "hello world"}, nil
   318	}
   319	
   320	type MarshalerStruct struct {
   321		Foo MyMarshalerAttrTest `xml:",attr"`
   322	}
   323	
   324	type InnerStruct struct {
   325		XMLName Name `xml:"testns outer"`
   326	}
   327	
   328	type OuterStruct struct {
   329		InnerStruct
   330		IntAttr int `xml:"int,attr"`
   331	}
   332	
   333	type OuterNamedStruct struct {
   334		InnerStruct
   335		XMLName Name `xml:"outerns test"`
   336		IntAttr int  `xml:"int,attr"`
   337	}
   338	
   339	type OuterNamedOrderedStruct struct {
   340		XMLName Name `xml:"outerns test"`
   341		InnerStruct
   342		IntAttr int `xml:"int,attr"`
   343	}
   344	
   345	type OuterOuterStruct struct {
   346		OuterStruct
   347	}
   348	
   349	type NestedAndChardata struct {
   350		AB       []string `xml:"A>B"`
   351		Chardata string   `xml:",chardata"`
   352	}
   353	
   354	type NestedAndComment struct {
   355		AB      []string `xml:"A>B"`
   356		Comment string   `xml:",comment"`
   357	}
   358	
   359	type CDataTest struct {
   360		Chardata string `xml:",cdata"`
   361	}
   362	
   363	type NestedAndCData struct {
   364		AB    []string `xml:"A>B"`
   365		CDATA string   `xml:",cdata"`
   366	}
   367	
   368	func ifaceptr(x interface{}) interface{} {
   369		return &x
   370	}
   371	
   372	var (
   373		nameAttr     = "Sarah"
   374		ageAttr      = uint(12)
   375		contentsAttr = "lorem ipsum"
   376	)
   377	
   378	// Unless explicitly stated as such (or *Plain), all of the
   379	// tests below are two-way tests. When introducing new tests,
   380	// please try to make them two-way as well to ensure that
   381	// marshalling and unmarshalling are as symmetrical as feasible.
   382	var marshalTests = []struct {
   383		Value         interface{}
   384		ExpectXML     string
   385		MarshalOnly   bool
   386		UnmarshalOnly bool
   387	}{
   388		// Test nil marshals to nothing
   389		{Value: nil, ExpectXML: ``, MarshalOnly: true},
   390		{Value: nilStruct, ExpectXML: ``, MarshalOnly: true},
   391	
   392		// Test value types
   393		{Value: &Plain{true}, ExpectXML: `<Plain><V>true</V></Plain>`},
   394		{Value: &Plain{false}, ExpectXML: `<Plain><V>false</V></Plain>`},
   395		{Value: &Plain{int(42)}, ExpectXML: `<Plain><V>42</V></Plain>`},
   396		{Value: &Plain{int8(42)}, ExpectXML: `<Plain><V>42</V></Plain>`},
   397		{Value: &Plain{int16(42)}, ExpectXML: `<Plain><V>42</V></Plain>`},
   398		{Value: &Plain{int32(42)}, ExpectXML: `<Plain><V>42</V></Plain>`},
   399		{Value: &Plain{uint(42)}, ExpectXML: `<Plain><V>42</V></Plain>`},
   400		{Value: &Plain{uint8(42)}, ExpectXML: `<Plain><V>42</V></Plain>`},
   401		{Value: &Plain{uint16(42)}, ExpectXML: `<Plain><V>42</V></Plain>`},
   402		{Value: &Plain{uint32(42)}, ExpectXML: `<Plain><V>42</V></Plain>`},
   403		{Value: &Plain{float32(1.25)}, ExpectXML: `<Plain><V>1.25</V></Plain>`},
   404		{Value: &Plain{float64(1.25)}, ExpectXML: `<Plain><V>1.25</V></Plain>`},
   405		{Value: &Plain{uintptr(0xFFDD)}, ExpectXML: `<Plain><V>65501</V></Plain>`},
   406		{Value: &Plain{"gopher"}, ExpectXML: `<Plain><V>gopher</V></Plain>`},
   407		{Value: &Plain{[]byte("gopher")}, ExpectXML: `<Plain><V>gopher</V></Plain>`},
   408		{Value: &Plain{"</>"}, ExpectXML: `<Plain><V>&lt;/&gt;</V></Plain>`},
   409		{Value: &Plain{[]byte("</>")}, ExpectXML: `<Plain><V>&lt;/&gt;</V></Plain>`},
   410		{Value: &Plain{[3]byte{'<', '/', '>'}}, ExpectXML: `<Plain><V>&lt;/&gt;</V></Plain>`},
   411		{Value: &Plain{NamedType("potato")}, ExpectXML: `<Plain><V>potato</V></Plain>`},
   412		{Value: &Plain{[]int{1, 2, 3}}, ExpectXML: `<Plain><V>1</V><V>2</V><V>3</V></Plain>`},
   413		{Value: &Plain{[3]int{1, 2, 3}}, ExpectXML: `<Plain><V>1</V><V>2</V><V>3</V></Plain>`},
   414		{Value: ifaceptr(true), MarshalOnly: true, ExpectXML: `<bool>true</bool>`},
   415	
   416		// Test time.
   417		{
   418			Value:     &Plain{time.Unix(1e9, 123456789).UTC()},
   419			ExpectXML: `<Plain><V>2001-09-09T01:46:40.123456789Z</V></Plain>`,
   420		},
   421	
   422		// A pointer to struct{} may be used to test for an element's presence.
   423		{
   424			Value:     &PresenceTest{new(struct{})},
   425			ExpectXML: `<PresenceTest><Exists></Exists></PresenceTest>`,
   426		},
   427		{
   428			Value:     &PresenceTest{},
   429			ExpectXML: `<PresenceTest></PresenceTest>`,
   430		},
   431	
   432		// A pointer to struct{} may be used to test for an element's presence.
   433		{
   434			Value:     &PresenceTest{new(struct{})},
   435			ExpectXML: `<PresenceTest><Exists></Exists></PresenceTest>`,
   436		},
   437		{
   438			Value:     &PresenceTest{},
   439			ExpectXML: `<PresenceTest></PresenceTest>`,
   440		},
   441	
   442		// A []byte field is only nil if the element was not found.
   443		{
   444			Value:         &Data{},
   445			ExpectXML:     `<Data></Data>`,
   446			UnmarshalOnly: true,
   447		},
   448		{
   449			Value:         &Data{Bytes: []byte{}, Custom: MyBytes{}, Attr: []byte{}},
   450			ExpectXML:     `<Data Attr=""><Bytes></Bytes><Custom></Custom></Data>`,
   451			UnmarshalOnly: true,
   452		},
   453	
   454		// Check that []byte works, including named []byte types.
   455		{
   456			Value:     &Data{Bytes: []byte("ab"), Custom: MyBytes("cd"), Attr: []byte{'v'}},
   457			ExpectXML: `<Data Attr="v"><Bytes>ab</Bytes><Custom>cd</Custom></Data>`,
   458		},
   459	
   460		// Test innerxml
   461		{
   462			Value: &SecretAgent{
   463				Handle:    "007",
   464				Identity:  "James Bond",
   465				Obfuscate: "<redacted/>",
   466			},
   467			ExpectXML:   `<agent handle="007"><Identity>James Bond</Identity><redacted/></agent>`,
   468			MarshalOnly: true,
   469		},
   470		{
   471			Value: &SecretAgent{
   472				Handle:    "007",
   473				Identity:  "James Bond",
   474				Obfuscate: "<Identity>James Bond</Identity><redacted/>",
   475			},
   476			ExpectXML:     `<agent handle="007"><Identity>James Bond</Identity><redacted/></agent>`,
   477			UnmarshalOnly: true,
   478		},
   479	
   480		// Test structs
   481		{Value: &Port{Type: "ssl", Number: "443"}, ExpectXML: `<port type="ssl">443</port>`},
   482		{Value: &Port{Number: "443"}, ExpectXML: `<port>443</port>`},
   483		{Value: &Port{Type: "<unix>"}, ExpectXML: `<port type="&lt;unix&gt;"></port>`},
   484		{Value: &Port{Number: "443", Comment: "https"}, ExpectXML: `<port><!--https-->443</port>`},
   485		{Value: &Port{Number: "443", Comment: "add space-"}, ExpectXML: `<port><!--add space- -->443</port>`, MarshalOnly: true},
   486		{Value: &Domain{Name: []byte("google.com&friends")}, ExpectXML: `<domain>google.com&amp;friends</domain>`},
   487		{Value: &Domain{Name: []byte("google.com"), Comment: []byte(" &friends ")}, ExpectXML: `<domain>google.com<!-- &friends --></domain>`},
   488		{Value: &Book{Title: "Pride & Prejudice"}, ExpectXML: `<book>Pride &amp; Prejudice</book>`},
   489		{Value: &Event{Year: -3114}, ExpectXML: `<event>-3114</event>`},
   490		{Value: &Movie{Length: 13440}, ExpectXML: `<movie>13440</movie>`},
   491		{Value: &Pi{Approximation: 3.14159265}, ExpectXML: `<pi>3.1415927</pi>`},
   492		{Value: &Universe{Visible: 9.3e13}, ExpectXML: `<universe>9.3e+13</universe>`},
   493		{Value: &Particle{HasMass: true}, ExpectXML: `<particle>true</particle>`},
   494		{Value: &Departure{When: ParseTime("2013-01-09T00:15:00-09:00")}, ExpectXML: `<departure>2013-01-09T00:15:00-09:00</departure>`},
   495		{Value: atomValue, ExpectXML: atomXml},
   496		{
   497			Value: &Ship{
   498				Name:  "Heart of Gold",
   499				Pilot: "Computer",
   500				Age:   1,
   501				Drive: ImprobabilityDrive,
   502				Passenger: []*Passenger{
   503					{
   504						Name:   []string{"Zaphod", "Beeblebrox"},
   505						Weight: 7.25,
   506					},
   507					{
   508						Name:   []string{"Trisha", "McMillen"},
   509						Weight: 5.5,
   510					},
   511					{
   512						Name:   []string{"Ford", "Prefect"},
   513						Weight: 7,
   514					},
   515					{
   516						Name:   []string{"Arthur", "Dent"},
   517						Weight: 6.75,
   518					},
   519				},
   520			},
   521			ExpectXML: `<spaceship name="Heart of Gold" pilot="Computer">` +
   522				`<drive>` + strconv.Itoa(int(ImprobabilityDrive)) + `</drive>` +
   523				`<age>1</age>` +
   524				`<passenger>` +
   525				`<name>Zaphod</name>` +
   526				`<name>Beeblebrox</name>` +
   527				`<weight>7.25</weight>` +
   528				`</passenger>` +
   529				`<passenger>` +
   530				`<name>Trisha</name>` +
   531				`<name>McMillen</name>` +
   532				`<weight>5.5</weight>` +
   533				`</passenger>` +
   534				`<passenger>` +
   535				`<name>Ford</name>` +
   536				`<name>Prefect</name>` +
   537				`<weight>7</weight>` +
   538				`</passenger>` +
   539				`<passenger>` +
   540				`<name>Arthur</name>` +
   541				`<name>Dent</name>` +
   542				`<weight>6.75</weight>` +
   543				`</passenger>` +
   544				`</spaceship>`,
   545		},
   546	
   547		// Test a>b
   548		{
   549			Value: &NestedItems{Items: nil, Item1: nil},
   550			ExpectXML: `<result>` +
   551				`<Items>` +
   552				`</Items>` +
   553				`</result>`,
   554		},
   555		{
   556			Value: &NestedItems{Items: []string{}, Item1: []string{}},
   557			ExpectXML: `<result>` +
   558				`<Items>` +
   559				`</Items>` +
   560				`</result>`,
   561			MarshalOnly: true,
   562		},
   563		{
   564			Value: &NestedItems{Items: nil, Item1: []string{"A"}},
   565			ExpectXML: `<result>` +
   566				`<Items>` +
   567				`<item1>A</item1>` +
   568				`</Items>` +
   569				`</result>`,
   570		},
   571		{
   572			Value: &NestedItems{Items: []string{"A", "B"}, Item1: nil},
   573			ExpectXML: `<result>` +
   574				`<Items>` +
   575				`<item>A</item>` +
   576				`<item>B</item>` +
   577				`</Items>` +
   578				`</result>`,
   579		},
   580		{
   581			Value: &NestedItems{Items: []string{"A", "B"}, Item1: []string{"C"}},
   582			ExpectXML: `<result>` +
   583				`<Items>` +
   584				`<item>A</item>` +
   585				`<item>B</item>` +
   586				`<item1>C</item1>` +
   587				`</Items>` +
   588				`</result>`,
   589		},
   590		{
   591			Value: &NestedOrder{Field1: "C", Field2: "B", Field3: "A"},
   592			ExpectXML: `<result>` +
   593				`<parent>` +
   594				`<c>C</c>` +
   595				`<b>B</b>` +
   596				`<a>A</a>` +
   597				`</parent>` +
   598				`</result>`,
   599		},
   600		{
   601			Value: &NilTest{A: "A", B: nil, C: "C"},
   602			ExpectXML: `<NilTest>` +
   603				`<parent1>` +
   604				`<parent2><a>A</a></parent2>` +
   605				`<parent2><c>C</c></parent2>` +
   606				`</parent1>` +
   607				`</NilTest>`,
   608			MarshalOnly: true, // Uses interface{}
   609		},
   610		{
   611			Value: &MixedNested{A: "A", B: "B", C: "C", D: "D"},
   612			ExpectXML: `<result>` +
   613				`<parent1><a>A</a></parent1>` +
   614				`<b>B</b>` +
   615				`<parent1>` +
   616				`<parent2><c>C</c></parent2>` +
   617				`<d>D</d>` +
   618				`</parent1>` +
   619				`</result>`,
   620		},
   621		{
   622			Value:     &Service{Port: &Port{Number: "80"}},
   623			ExpectXML: `<service><host><port>80</port></host></service>`,
   624		},
   625		{
   626			Value:     &Service{},
   627			ExpectXML: `<service></service>`,
   628		},
   629		{
   630			Value: &Service{Port: &Port{Number: "80"}, Extra1: "A", Extra2: "B"},
   631			ExpectXML: `<service>` +
   632				`<host><port>80</port></host>` +
   633				`<Extra1>A</Extra1>` +
   634				`<host><extra2>B</extra2></host>` +
   635				`</service>`,
   636			MarshalOnly: true,
   637		},
   638		{
   639			Value: &Service{Port: &Port{Number: "80"}, Extra2: "example"},
   640			ExpectXML: `<service>` +
   641				`<host><port>80</port></host>` +
   642				`<host><extra2>example</extra2></host>` +
   643				`</service>`,
   644			MarshalOnly: true,
   645		},
   646		{
   647			Value: &struct {
   648				XMLName struct{} `xml:"space top"`
   649				A       string   `xml:"x>a"`
   650				B       string   `xml:"x>b"`
   651				C       string   `xml:"space x>c"`
   652				C1      string   `xml:"space1 x>c"`
   653				D1      string   `xml:"space1 x>d"`
   654			}{
   655				A:  "a",
   656				B:  "b",
   657				C:  "c",
   658				C1: "c1",
   659				D1: "d1",
   660			},
   661			ExpectXML: `<top xmlns="space">` +
   662				`<x><a>a</a><b>b</b><c xmlns="space">c</c>` +
   663				`<c xmlns="space1">c1</c>` +
   664				`<d xmlns="space1">d1</d>` +
   665				`</x>` +
   666				`</top>`,
   667		},
   668		{
   669			Value: &struct {
   670				XMLName Name
   671				A       string `xml:"x>a"`
   672				B       string `xml:"x>b"`
   673				C       string `xml:"space x>c"`
   674				C1      string `xml:"space1 x>c"`
   675				D1      string `xml:"space1 x>d"`
   676			}{
   677				XMLName: Name{
   678					Space: "space0",
   679					Local: "top",
   680				},
   681				A:  "a",
   682				B:  "b",
   683				C:  "c",
   684				C1: "c1",
   685				D1: "d1",
   686			},
   687			ExpectXML: `<top xmlns="space0">` +
   688				`<x><a>a</a><b>b</b>` +
   689				`<c xmlns="space">c</c>` +
   690				`<c xmlns="space1">c1</c>` +
   691				`<d xmlns="space1">d1</d>` +
   692				`</x>` +
   693				`</top>`,
   694		},
   695		{
   696			Value: &struct {
   697				XMLName struct{} `xml:"top"`
   698				B       string   `xml:"space x>b"`
   699				B1      string   `xml:"space1 x>b"`
   700			}{
   701				B:  "b",
   702				B1: "b1",
   703			},
   704			ExpectXML: `<top>` +
   705				`<x><b xmlns="space">b</b>` +
   706				`<b xmlns="space1">b1</b></x>` +
   707				`</top>`,
   708		},
   709	
   710		// Test struct embedding
   711		{
   712			Value: &EmbedA{
   713				EmbedC: EmbedC{
   714					FieldA1: "", // Shadowed by A.A
   715					FieldA2: "", // Shadowed by A.A
   716					FieldB:  "A.C.B",
   717					FieldC:  "A.C.C",
   718				},
   719				EmbedB: EmbedB{
   720					FieldB: "A.B.B",
   721					EmbedC: &EmbedC{
   722						FieldA1: "A.B.C.A1",
   723						FieldA2: "A.B.C.A2",
   724						FieldB:  "", // Shadowed by A.B.B
   725						FieldC:  "A.B.C.C",
   726					},
   727				},
   728				FieldA: "A.A",
   729				embedD: embedD{
   730					FieldE: "A.D.E",
   731				},
   732			},
   733			ExpectXML: `<EmbedA>` +
   734				`<FieldB>A.C.B</FieldB>` +
   735				`<FieldC>A.C.C</FieldC>` +
   736				`<EmbedB>` +
   737				`<FieldB>A.B.B</FieldB>` +
   738				`<FieldA>` +
   739				`<A1>A.B.C.A1</A1>` +
   740				`<A2>A.B.C.A2</A2>` +
   741				`</FieldA>` +
   742				`<FieldC>A.B.C.C</FieldC>` +
   743				`</EmbedB>` +
   744				`<FieldA>A.A</FieldA>` +
   745				`<FieldE>A.D.E</FieldE>` +
   746				`</EmbedA>`,
   747		},
   748	
   749		// Test that name casing matters
   750		{
   751			Value:     &NameCasing{Xy: "mixed", XY: "upper", XyA: "mixedA", XYA: "upperA"},
   752			ExpectXML: `<casing Xy="mixedA" XY="upperA"><Xy>mixed</Xy><XY>upper</XY></casing>`,
   753		},
   754	
   755		// Test the order in which the XML element name is chosen
   756		{
   757			Value: &NamePrecedence{
   758				FromTag:     XMLNameWithoutTag{Value: "A"},
   759				FromNameVal: XMLNameWithoutTag{XMLName: Name{Local: "InXMLName"}, Value: "B"},
   760				FromNameTag: XMLNameWithTag{Value: "C"},
   761				InFieldName: "D",
   762			},
   763			ExpectXML: `<Parent>` +
   764				`<InTag>A</InTag>` +
   765				`<InXMLName>B</InXMLName>` +
   766				`<InXMLNameTag>C</InXMLNameTag>` +
   767				`<InFieldName>D</InFieldName>` +
   768				`</Parent>`,
   769			MarshalOnly: true,
   770		},
   771		{
   772			Value: &NamePrecedence{
   773				XMLName:     Name{Local: "Parent"},
   774				FromTag:     XMLNameWithoutTag{XMLName: Name{Local: "InTag"}, Value: "A"},
   775				FromNameVal: XMLNameWithoutTag{XMLName: Name{Local: "FromNameVal"}, Value: "B"},
   776				FromNameTag: XMLNameWithTag{XMLName: Name{Local: "InXMLNameTag"}, Value: "C"},
   777				InFieldName: "D",
   778			},
   779			ExpectXML: `<Parent>` +
   780				`<InTag>A</InTag>` +
   781				`<FromNameVal>B</FromNameVal>` +
   782				`<InXMLNameTag>C</InXMLNameTag>` +
   783				`<InFieldName>D</InFieldName>` +
   784				`</Parent>`,
   785			UnmarshalOnly: true,
   786		},
   787	
   788		// xml.Name works in a plain field as well.
   789		{
   790			Value:     &NameInField{Name{Space: "ns", Local: "foo"}},
   791			ExpectXML: `<NameInField><foo xmlns="ns"></foo></NameInField>`,
   792		},
   793		{
   794			Value:         &NameInField{Name{Space: "ns", Local: "foo"}},
   795			ExpectXML:     `<NameInField><foo xmlns="ns"><ignore></ignore></foo></NameInField>`,
   796			UnmarshalOnly: true,
   797		},
   798	
   799		// Marshaling zero xml.Name uses the tag or field name.
   800		{
   801			Value:       &NameInField{},
   802			ExpectXML:   `<NameInField><foo xmlns="ns"></foo></NameInField>`,
   803			MarshalOnly: true,
   804		},
   805	
   806		// Test attributes
   807		{
   808			Value: &AttrTest{
   809				Int:   8,
   810				Named: 9,
   811				Float: 23.5,
   812				Uint8: 255,
   813				Bool:  true,
   814				Str:   "str",
   815				Bytes: []byte("byt"),
   816			},
   817			ExpectXML: `<AttrTest Int="8" int="9" Float="23.5" Uint8="255"` +
   818				` Bool="true" Str="str" Bytes="byt"></AttrTest>`,
   819		},
   820		{
   821			Value: &AttrTest{Bytes: []byte{}},
   822			ExpectXML: `<AttrTest Int="0" int="0" Float="0" Uint8="0"` +
   823				` Bool="false" Str="" Bytes=""></AttrTest>`,
   824		},
   825		{
   826			Value: &OmitAttrTest{
   827				Int:   8,
   828				Named: 9,
   829				Float: 23.5,
   830				Uint8: 255,
   831				Bool:  true,
   832				Str:   "str",
   833				Bytes: []byte("byt"),
   834			},
   835			ExpectXML: `<OmitAttrTest Int="8" int="9" Float="23.5" Uint8="255"` +
   836				` Bool="true" Str="str" Bytes="byt"></OmitAttrTest>`,
   837		},
   838		{
   839			Value:     &OmitAttrTest{},
   840			ExpectXML: `<OmitAttrTest></OmitAttrTest>`,
   841		},
   842	
   843		// pointer fields
   844		{
   845			Value:       &PointerFieldsTest{Name: &nameAttr, Age: &ageAttr, Contents: &contentsAttr},
   846			ExpectXML:   `<dummy name="Sarah" age="12">lorem ipsum</dummy>`,
   847			MarshalOnly: true,
   848		},
   849	
   850		// empty chardata pointer field
   851		{
   852			Value:       &ChardataEmptyTest{},
   853			ExpectXML:   `<test></test>`,
   854			MarshalOnly: true,
   855		},
   856	
   857		// omitempty on fields
   858		{
   859			Value: &OmitFieldTest{
   860				Int:   8,
   861				Named: 9,
   862				Float: 23.5,
   863				Uint8: 255,
   864				Bool:  true,
   865				Str:   "str",
   866				Bytes: []byte("byt"),
   867				Ptr:   &PresenceTest{},
   868			},
   869			ExpectXML: `<OmitFieldTest>` +
   870				`<Int>8</Int>` +
   871				`<int>9</int>` +
   872				`<Float>23.5</Float>` +
   873				`<Uint8>255</Uint8>` +
   874				`<Bool>true</Bool>` +
   875				`<Str>str</Str>` +
   876				`<Bytes>byt</Bytes>` +
   877				`<Ptr></Ptr>` +
   878				`</OmitFieldTest>`,
   879		},
   880		{
   881			Value:     &OmitFieldTest{},
   882			ExpectXML: `<OmitFieldTest></OmitFieldTest>`,
   883		},
   884	
   885		// Test ",any"
   886		{
   887			ExpectXML: `<a><nested><value>known</value></nested><other><sub>unknown</sub></other></a>`,
   888			Value: &AnyTest{
   889				Nested: "known",
   890				AnyField: AnyHolder{
   891					XMLName: Name{Local: "other"},
   892					XML:     "<sub>unknown</sub>",
   893				},
   894			},
   895		},
   896		{
   897			Value: &AnyTest{Nested: "known",
   898				AnyField: AnyHolder{
   899					XML:     "<unknown/>",
   900					XMLName: Name{Local: "AnyField"},
   901				},
   902			},
   903			ExpectXML: `<a><nested><value>known</value></nested><AnyField><unknown/></AnyField></a>`,
   904		},
   905		{
   906			ExpectXML: `<a><nested><value>b</value></nested></a>`,
   907			Value: &AnyOmitTest{
   908				Nested: "b",
   909			},
   910		},
   911		{
   912			ExpectXML: `<a><nested><value>b</value></nested><c><d>e</d></c><g xmlns="f"><h>i</h></g></a>`,
   913			Value: &AnySliceTest{
   914				Nested: "b",
   915				AnyField: []AnyHolder{
   916					{
   917						XMLName: Name{Local: "c"},
   918						XML:     "<d>e</d>",
   919					},
   920					{
   921						XMLName: Name{Space: "f", Local: "g"},
   922						XML:     "<h>i</h>",
   923					},
   924				},
   925			},
   926		},
   927		{
   928			ExpectXML: `<a><nested><value>b</value></nested></a>`,
   929			Value: &AnySliceTest{
   930				Nested: "b",
   931			},
   932		},
   933	
   934		// Test recursive types.
   935		{
   936			Value: &RecurseA{
   937				A: "a1",
   938				B: &RecurseB{
   939					A: &RecurseA{"a2", nil},
   940					B: "b1",
   941				},
   942			},
   943			ExpectXML: `<RecurseA><A>a1</A><B><A><A>a2</A></A><B>b1</B></B></RecurseA>`,
   944		},
   945	
   946		// Test ignoring fields via "-" tag
   947		{
   948			ExpectXML: `<IgnoreTest></IgnoreTest>`,
   949			Value:     &IgnoreTest{},
   950		},
   951		{
   952			ExpectXML:   `<IgnoreTest></IgnoreTest>`,
   953			Value:       &IgnoreTest{PublicSecret: "can't tell"},
   954			MarshalOnly: true,
   955		},
   956		{
   957			ExpectXML:     `<IgnoreTest><PublicSecret>ignore me</PublicSecret></IgnoreTest>`,
   958			Value:         &IgnoreTest{},
   959			UnmarshalOnly: true,
   960		},
   961	
   962		// Test escaping.
   963		{
   964			ExpectXML: `<a><nested><value>dquote: &#34;; squote: &#39;; ampersand: &amp;; less: &lt;; greater: &gt;;</value></nested><empty></empty></a>`,
   965			Value: &AnyTest{
   966				Nested:   `dquote: "; squote: '; ampersand: &; less: <; greater: >;`,
   967				AnyField: AnyHolder{XMLName: Name{Local: "empty"}},
   968			},
   969		},
   970		{
   971			ExpectXML: `<a><nested><value>newline: &#xA;; cr: &#xD;; tab: &#x9;;</value></nested><AnyField></AnyField></a>`,
   972			Value: &AnyTest{
   973				Nested:   "newline: \n; cr: \r; tab: \t;",
   974				AnyField: AnyHolder{XMLName: Name{Local: "AnyField"}},
   975			},
   976		},
   977		{
   978			ExpectXML: "<a><nested><value>1\r2\r\n3\n\r4\n5</value></nested></a>",
   979			Value: &AnyTest{
   980				Nested: "1\n2\n3\n\n4\n5",
   981			},
   982			UnmarshalOnly: true,
   983		},
   984		{
   985			ExpectXML: `<EmbedInt><MyInt>42</MyInt></EmbedInt>`,
   986			Value: &EmbedInt{
   987				MyInt: 42,
   988			},
   989		},
   990		// Test outputting CDATA-wrapped text.
   991		{
   992			ExpectXML: `<CDataTest></CDataTest>`,
   993			Value:     &CDataTest{},
   994		},
   995		{
   996			ExpectXML: `<CDataTest><![CDATA[http://example.com/tests/1?foo=1&bar=baz]]></CDataTest>`,
   997			Value: &CDataTest{
   998				Chardata: "http://example.com/tests/1?foo=1&bar=baz",
   999			},
  1000		},
  1001		{
  1002			ExpectXML: `<CDataTest><![CDATA[Literal <![CDATA[Nested]]]]><![CDATA[>!]]></CDataTest>`,
  1003			Value: &CDataTest{
  1004				Chardata: "Literal <![CDATA[Nested]]>!",
  1005			},
  1006		},
  1007		{
  1008			ExpectXML: `<CDataTest><![CDATA[<![CDATA[Nested]]]]><![CDATA[> Literal!]]></CDataTest>`,
  1009			Value: &CDataTest{
  1010				Chardata: "<![CDATA[Nested]]> Literal!",
  1011			},
  1012		},
  1013		{
  1014			ExpectXML: `<CDataTest><![CDATA[<![CDATA[Nested]]]]><![CDATA[> Literal! <![CDATA[Nested]]]]><![CDATA[> Literal!]]></CDataTest>`,
  1015			Value: &CDataTest{
  1016				Chardata: "<![CDATA[Nested]]> Literal! <![CDATA[Nested]]> Literal!",
  1017			},
  1018		},
  1019		{
  1020			ExpectXML: `<CDataTest><![CDATA[<![CDATA[<![CDATA[Nested]]]]><![CDATA[>]]]]><![CDATA[>]]></CDataTest>`,
  1021			Value: &CDataTest{
  1022				Chardata: "<![CDATA[<![CDATA[Nested]]>]]>",
  1023			},
  1024		},
  1025	
  1026		// Test omitempty with parent chain; see golang.org/issue/4168.
  1027		{
  1028			ExpectXML: `<Strings><A></A></Strings>`,
  1029			Value:     &Strings{},
  1030		},
  1031		// Custom marshalers.
  1032		{
  1033			ExpectXML: `<MyMarshalerTest>hello world</MyMarshalerTest>`,
  1034			Value:     &MyMarshalerTest{},
  1035		},
  1036		{
  1037			ExpectXML: `<MarshalerStruct Foo="hello world"></MarshalerStruct>`,
  1038			Value:     &MarshalerStruct{},
  1039		},
  1040		{
  1041			ExpectXML: `<outer xmlns="testns" int="10"></outer>`,
  1042			Value:     &OuterStruct{IntAttr: 10},
  1043		},
  1044		{
  1045			ExpectXML: `<test xmlns="outerns" int="10"></test>`,
  1046			Value:     &OuterNamedStruct{XMLName: Name{Space: "outerns", Local: "test"}, IntAttr: 10},
  1047		},
  1048		{
  1049			ExpectXML: `<test xmlns="outerns" int="10"></test>`,
  1050			Value:     &OuterNamedOrderedStruct{XMLName: Name{Space: "outerns", Local: "test"}, IntAttr: 10},
  1051		},
  1052		{
  1053			ExpectXML: `<outer xmlns="testns" int="10"></outer>`,
  1054			Value:     &OuterOuterStruct{OuterStruct{IntAttr: 10}},
  1055		},
  1056		{
  1057			ExpectXML: `<NestedAndChardata><A><B></B><B></B></A>test</NestedAndChardata>`,
  1058			Value:     &NestedAndChardata{AB: make([]string, 2), Chardata: "test"},
  1059		},
  1060		{
  1061			ExpectXML: `<NestedAndComment><A><B></B><B></B></A><!--test--></NestedAndComment>`,
  1062			Value:     &NestedAndComment{AB: make([]string, 2), Comment: "test"},
  1063		},
  1064		{
  1065			ExpectXML: `<NestedAndCData><A><B></B><B></B></A><![CDATA[test]]></NestedAndCData>`,
  1066			Value:     &NestedAndCData{AB: make([]string, 2), CDATA: "test"},
  1067		},
  1068	}
  1069	
  1070	func TestMarshal(t *testing.T) {
  1071		for idx, test := range marshalTests {
  1072			if test.UnmarshalOnly {
  1073				continue
  1074			}
  1075			data, err := Marshal(test.Value)
  1076			if err != nil {
  1077				t.Errorf("#%d: marshal(%#v): %s", idx, test.Value, err)
  1078				continue
  1079			}
  1080			if got, want := string(data), test.ExpectXML; got != want {
  1081				if strings.Contains(want, "\n") {
  1082					t.Errorf("#%d: marshal(%#v):\nHAVE:\n%s\nWANT:\n%s", idx, test.Value, got, want)
  1083				} else {
  1084					t.Errorf("#%d: marshal(%#v):\nhave %#q\nwant %#q", idx, test.Value, got, want)
  1085				}
  1086			}
  1087		}
  1088	}
  1089	
  1090	type AttrParent struct {
  1091		X string `xml:"X>Y,attr"`
  1092	}
  1093	
  1094	type BadAttr struct {
  1095		Name []string `xml:"name,attr"`
  1096	}
  1097	
  1098	var marshalErrorTests = []struct {
  1099		Value interface{}
  1100		Err   string
  1101		Kind  reflect.Kind
  1102	}{
  1103		{
  1104			Value: make(chan bool),
  1105			Err:   "xml: unsupported type: chan bool",
  1106			Kind:  reflect.Chan,
  1107		},
  1108		{
  1109			Value: map[string]string{
  1110				"question": "What do you get when you multiply six by nine?",
  1111				"answer":   "42",
  1112			},
  1113			Err:  "xml: unsupported type: map[string]string",
  1114			Kind: reflect.Map,
  1115		},
  1116		{
  1117			Value: map[*Ship]bool{nil: false},
  1118			Err:   "xml: unsupported type: map[*xml.Ship]bool",
  1119			Kind:  reflect.Map,
  1120		},
  1121		{
  1122			Value: &Domain{Comment: []byte("f--bar")},
  1123			Err:   `xml: comments must not contain "--"`,
  1124		},
  1125		// Reject parent chain with attr, never worked; see golang.org/issue/5033.
  1126		{
  1127			Value: &AttrParent{},
  1128			Err:   `xml: X>Y chain not valid with attr flag`,
  1129		},
  1130		{
  1131			Value: BadAttr{[]string{"X", "Y"}},
  1132			Err:   `xml: unsupported type: []string`,
  1133		},
  1134	}
  1135	
  1136	var marshalIndentTests = []struct {
  1137		Value     interface{}
  1138		Prefix    string
  1139		Indent    string
  1140		ExpectXML string
  1141	}{
  1142		{
  1143			Value: &SecretAgent{
  1144				Handle:    "007",
  1145				Identity:  "James Bond",
  1146				Obfuscate: "<redacted/>",
  1147			},
  1148			Prefix:    "",
  1149			Indent:    "\t",
  1150			ExpectXML: fmt.Sprintf("<agent handle=\"007\">\n\t<Identity>James Bond</Identity><redacted/>\n</agent>"),
  1151		},
  1152	}
  1153	
  1154	func TestMarshalErrors(t *testing.T) {
  1155		for idx, test := range marshalErrorTests {
  1156			data, err := Marshal(test.Value)
  1157			if err == nil {
  1158				t.Errorf("#%d: marshal(%#v) = [success] %q, want error %v", idx, test.Value, data, test.Err)
  1159				continue
  1160			}
  1161			if err.Error() != test.Err {
  1162				t.Errorf("#%d: marshal(%#v) = [error] %v, want %v", idx, test.Value, err, test.Err)
  1163			}
  1164			if test.Kind != reflect.Invalid {
  1165				if kind := err.(*UnsupportedTypeError).Type.Kind(); kind != test.Kind {
  1166					t.Errorf("#%d: marshal(%#v) = [error kind] %s, want %s", idx, test.Value, kind, test.Kind)
  1167				}
  1168			}
  1169		}
  1170	}
  1171	
  1172	// Do invertibility testing on the various structures that we test
  1173	func TestUnmarshal(t *testing.T) {
  1174		for i, test := range marshalTests {
  1175			if test.MarshalOnly {
  1176				continue
  1177			}
  1178			if _, ok := test.Value.(*Plain); ok {
  1179				continue
  1180			}
  1181			if test.ExpectXML == `<top>`+
  1182				`<x><b xmlns="space">b</b>`+
  1183				`<b xmlns="space1">b1</b></x>`+
  1184				`</top>` {
  1185				// TODO(rogpeppe): re-enable this test in
  1186				// https://go-review.googlesource.com/#/c/5910/
  1187				continue
  1188			}
  1189	
  1190			vt := reflect.TypeOf(test.Value)
  1191			dest := reflect.New(vt.Elem()).Interface()
  1192			err := Unmarshal([]byte(test.ExpectXML), dest)
  1193	
  1194			switch fix := dest.(type) {
  1195			case *Feed:
  1196				fix.Author.InnerXML = ""
  1197				for i := range fix.Entry {
  1198					fix.Entry[i].Author.InnerXML = ""
  1199				}
  1200			}
  1201	
  1202			if err != nil {
  1203				t.Errorf("#%d: unexpected error: %#v", i, err)
  1204			} else if got, want := dest, test.Value; !reflect.DeepEqual(got, want) {
  1205				t.Errorf("#%d: unmarshal(%q):\nhave %#v\nwant %#v", i, test.ExpectXML, got, want)
  1206			}
  1207		}
  1208	}
  1209	
  1210	func TestMarshalIndent(t *testing.T) {
  1211		for i, test := range marshalIndentTests {
  1212			data, err := MarshalIndent(test.Value, test.Prefix, test.Indent)
  1213			if err != nil {
  1214				t.Errorf("#%d: Error: %s", i, err)
  1215				continue
  1216			}
  1217			if got, want := string(data), test.ExpectXML; got != want {
  1218				t.Errorf("#%d: MarshalIndent:\nGot:%s\nWant:\n%s", i, got, want)
  1219			}
  1220		}
  1221	}
  1222	
  1223	type limitedBytesWriter struct {
  1224		w      io.Writer
  1225		remain int // until writes fail
  1226	}
  1227	
  1228	func (lw *limitedBytesWriter) Write(p []byte) (n int, err error) {
  1229		if lw.remain <= 0 {
  1230			println("error")
  1231			return 0, errors.New("write limit hit")
  1232		}
  1233		if len(p) > lw.remain {
  1234			p = p[:lw.remain]
  1235			n, _ = lw.w.Write(p)
  1236			lw.remain = 0
  1237			return n, errors.New("write limit hit")
  1238		}
  1239		n, err = lw.w.Write(p)
  1240		lw.remain -= n
  1241		return n, err
  1242	}
  1243	
  1244	func TestMarshalWriteErrors(t *testing.T) {
  1245		var buf bytes.Buffer
  1246		const writeCap = 1024
  1247		w := &limitedBytesWriter{&buf, writeCap}
  1248		enc := NewEncoder(w)
  1249		var err error
  1250		var i int
  1251		const n = 4000
  1252		for i = 1; i <= n; i++ {
  1253			err = enc.Encode(&Passenger{
  1254				Name:   []string{"Alice", "Bob"},
  1255				Weight: 5,
  1256			})
  1257			if err != nil {
  1258				break
  1259			}
  1260		}
  1261		if err == nil {
  1262			t.Error("expected an error")
  1263		}
  1264		if i == n {
  1265			t.Errorf("expected to fail before the end")
  1266		}
  1267		if buf.Len() != writeCap {
  1268			t.Errorf("buf.Len() = %d; want %d", buf.Len(), writeCap)
  1269		}
  1270	}
  1271	
  1272	func TestMarshalWriteIOErrors(t *testing.T) {
  1273		enc := NewEncoder(errWriter{})
  1274	
  1275		expectErr := "unwritable"
  1276		err := enc.Encode(&Passenger{})
  1277		if err == nil || err.Error() != expectErr {
  1278			t.Errorf("EscapeTest = [error] %v, want %v", err, expectErr)
  1279		}
  1280	}
  1281	
  1282	func TestMarshalFlush(t *testing.T) {
  1283		var buf bytes.Buffer
  1284		enc := NewEncoder(&buf)
  1285		if err := enc.EncodeToken(CharData("hello world")); err != nil {
  1286			t.Fatalf("enc.EncodeToken: %v", err)
  1287		}
  1288		if buf.Len() > 0 {
  1289			t.Fatalf("enc.EncodeToken caused actual write: %q", buf.Bytes())
  1290		}
  1291		if err := enc.Flush(); err != nil {
  1292			t.Fatalf("enc.Flush: %v", err)
  1293		}
  1294		if buf.String() != "hello world" {
  1295			t.Fatalf("after enc.Flush, buf.String() = %q, want %q", buf.String(), "hello world")
  1296		}
  1297	}
  1298	
  1299	func BenchmarkMarshal(b *testing.B) {
  1300		b.ReportAllocs()
  1301		for i := 0; i < b.N; i++ {
  1302			Marshal(atomValue)
  1303		}
  1304	}
  1305	
  1306	func BenchmarkUnmarshal(b *testing.B) {
  1307		b.ReportAllocs()
  1308		xml := []byte(atomXml)
  1309		for i := 0; i < b.N; i++ {
  1310			Unmarshal(xml, &Feed{})
  1311		}
  1312	}
  1313	
  1314	// golang.org/issue/6556
  1315	func TestStructPointerMarshal(t *testing.T) {
  1316		type A struct {
  1317			XMLName string `xml:"a"`
  1318			B       []interface{}
  1319		}
  1320		type C struct {
  1321			XMLName Name
  1322			Value   string `xml:"value"`
  1323		}
  1324	
  1325		a := new(A)
  1326		a.B = append(a.B, &C{
  1327			XMLName: Name{Local: "c"},
  1328			Value:   "x",
  1329		})
  1330	
  1331		b, err := Marshal(a)
  1332		if err != nil {
  1333			t.Fatal(err)
  1334		}
  1335		if x := string(b); x != "<a><c><value>x</value></c></a>" {
  1336			t.Fatal(x)
  1337		}
  1338		var v A
  1339		err = Unmarshal(b, &v)
  1340		if err != nil {
  1341			t.Fatal(err)
  1342		}
  1343	}
  1344	
  1345	var encodeTokenTests = []struct {
  1346		desc string
  1347		toks []Token
  1348		want string
  1349		err  string
  1350	}{{
  1351		desc: "start element with name space",
  1352		toks: []Token{
  1353			StartElement{Name{"space", "local"}, nil},
  1354		},
  1355		want: `<local xmlns="space">`,
  1356	}, {
  1357		desc: "start element with no name",
  1358		toks: []Token{
  1359			StartElement{Name{"space", ""}, nil},
  1360		},
  1361		err: "xml: start tag with no name",
  1362	}, {
  1363		desc: "end element with no name",
  1364		toks: []Token{
  1365			EndElement{Name{"space", ""}},
  1366		},
  1367		err: "xml: end tag with no name",
  1368	}, {
  1369		desc: "char data",
  1370		toks: []Token{
  1371			CharData("foo"),
  1372		},
  1373		want: `foo`,
  1374	}, {
  1375		desc: "char data with escaped chars",
  1376		toks: []Token{
  1377			CharData(" \t\n"),
  1378		},
  1379		want: " &#x9;\n",
  1380	}, {
  1381		desc: "comment",
  1382		toks: []Token{
  1383			Comment("foo"),
  1384		},
  1385		want: `<!--foo-->`,
  1386	}, {
  1387		desc: "comment with invalid content",
  1388		toks: []Token{
  1389			Comment("foo-->"),
  1390		},
  1391		err: "xml: EncodeToken of Comment containing --> marker",
  1392	}, {
  1393		desc: "proc instruction",
  1394		toks: []Token{
  1395			ProcInst{"Target", []byte("Instruction")},
  1396		},
  1397		want: `<?Target Instruction?>`,
  1398	}, {
  1399		desc: "proc instruction with empty target",
  1400		toks: []Token{
  1401			ProcInst{"", []byte("Instruction")},
  1402		},
  1403		err: "xml: EncodeToken of ProcInst with invalid Target",
  1404	}, {
  1405		desc: "proc instruction with bad content",
  1406		toks: []Token{
  1407			ProcInst{"", []byte("Instruction?>")},
  1408		},
  1409		err: "xml: EncodeToken of ProcInst with invalid Target",
  1410	}, {
  1411		desc: "directive",
  1412		toks: []Token{
  1413			Directive("foo"),
  1414		},
  1415		want: `<!foo>`,
  1416	}, {
  1417		desc: "more complex directive",
  1418		toks: []Token{
  1419			Directive("DOCTYPE doc [ <!ELEMENT doc '>'> <!-- com>ment --> ]"),
  1420		},
  1421		want: `<!DOCTYPE doc [ <!ELEMENT doc '>'> <!-- com>ment --> ]>`,
  1422	}, {
  1423		desc: "directive instruction with bad name",
  1424		toks: []Token{
  1425			Directive("foo>"),
  1426		},
  1427		err: "xml: EncodeToken of Directive containing wrong < or > markers",
  1428	}, {
  1429		desc: "end tag without start tag",
  1430		toks: []Token{
  1431			EndElement{Name{"foo", "bar"}},
  1432		},
  1433		err: "xml: end tag </bar> without start tag",
  1434	}, {
  1435		desc: "mismatching end tag local name",
  1436		toks: []Token{
  1437			StartElement{Name{"", "foo"}, nil},
  1438			EndElement{Name{"", "bar"}},
  1439		},
  1440		err:  "xml: end tag </bar> does not match start tag <foo>",
  1441		want: `<foo>`,
  1442	}, {
  1443		desc: "mismatching end tag namespace",
  1444		toks: []Token{
  1445			StartElement{Name{"space", "foo"}, nil},
  1446			EndElement{Name{"another", "foo"}},
  1447		},
  1448		err:  "xml: end tag </foo> in namespace another does not match start tag <foo> in namespace space",
  1449		want: `<foo xmlns="space">`,
  1450	}, {
  1451		desc: "start element with explicit namespace",
  1452		toks: []Token{
  1453			StartElement{Name{"space", "local"}, []Attr{
  1454				{Name{"xmlns", "x"}, "space"},
  1455				{Name{"space", "foo"}, "value"},
  1456			}},
  1457		},
  1458		want: `<local xmlns="space" xmlns:_xmlns="xmlns" _xmlns:x="space" xmlns:space="space" space:foo="value">`,
  1459	}, {
  1460		desc: "start element with explicit namespace and colliding prefix",
  1461		toks: []Token{
  1462			StartElement{Name{"space", "local"}, []Attr{
  1463				{Name{"xmlns", "x"}, "space"},
  1464				{Name{"space", "foo"}, "value"},
  1465				{Name{"x", "bar"}, "other"},
  1466			}},
  1467		},
  1468		want: `<local xmlns="space" xmlns:_xmlns="xmlns" _xmlns:x="space" xmlns:space="space" space:foo="value" xmlns:x="x" x:bar="other">`,
  1469	}, {
  1470		desc: "start element using previously defined namespace",
  1471		toks: []Token{
  1472			StartElement{Name{"", "local"}, []Attr{
  1473				{Name{"xmlns", "x"}, "space"},
  1474			}},
  1475			StartElement{Name{"space", "foo"}, []Attr{
  1476				{Name{"space", "x"}, "y"},
  1477			}},
  1478		},
  1479		want: `<local xmlns:_xmlns="xmlns" _xmlns:x="space"><foo xmlns="space" xmlns:space="space" space:x="y">`,
  1480	}, {
  1481		desc: "nested name space with same prefix",
  1482		toks: []Token{
  1483			StartElement{Name{"", "foo"}, []Attr{
  1484				{Name{"xmlns", "x"}, "space1"},
  1485			}},
  1486			StartElement{Name{"", "foo"}, []Attr{
  1487				{Name{"xmlns", "x"}, "space2"},
  1488			}},
  1489			StartElement{Name{"", "foo"}, []Attr{
  1490				{Name{"space1", "a"}, "space1 value"},
  1491				{Name{"space2", "b"}, "space2 value"},
  1492			}},
  1493			EndElement{Name{"", "foo"}},
  1494			EndElement{Name{"", "foo"}},
  1495			StartElement{Name{"", "foo"}, []Attr{
  1496				{Name{"space1", "a"}, "space1 value"},
  1497				{Name{"space2", "b"}, "space2 value"},
  1498			}},
  1499		},
  1500		want: `<foo xmlns:_xmlns="xmlns" _xmlns:x="space1"><foo _xmlns:x="space2"><foo xmlns:space1="space1" space1:a="space1 value" xmlns:space2="space2" space2:b="space2 value"></foo></foo><foo xmlns:space1="space1" space1:a="space1 value" xmlns:space2="space2" space2:b="space2 value">`,
  1501	}, {
  1502		desc: "start element defining several prefixes for the same name space",
  1503		toks: []Token{
  1504			StartElement{Name{"space", "foo"}, []Attr{
  1505				{Name{"xmlns", "a"}, "space"},
  1506				{Name{"xmlns", "b"}, "space"},
  1507				{Name{"space", "x"}, "value"},
  1508			}},
  1509		},
  1510		want: `<foo xmlns="space" xmlns:_xmlns="xmlns" _xmlns:a="space" _xmlns:b="space" xmlns:space="space" space:x="value">`,
  1511	}, {
  1512		desc: "nested element redefines name space",
  1513		toks: []Token{
  1514			StartElement{Name{"", "foo"}, []Attr{
  1515				{Name{"xmlns", "x"}, "space"},
  1516			}},
  1517			StartElement{Name{"space", "foo"}, []Attr{
  1518				{Name{"xmlns", "y"}, "space"},
  1519				{Name{"space", "a"}, "value"},
  1520			}},
  1521		},
  1522		want: `<foo xmlns:_xmlns="xmlns" _xmlns:x="space"><foo xmlns="space" _xmlns:y="space" xmlns:space="space" space:a="value">`,
  1523	}, {
  1524		desc: "nested element creates alias for default name space",
  1525		toks: []Token{
  1526			StartElement{Name{"space", "foo"}, []Attr{
  1527				{Name{"", "xmlns"}, "space"},
  1528			}},
  1529			StartElement{Name{"space", "foo"}, []Attr{
  1530				{Name{"xmlns", "y"}, "space"},
  1531				{Name{"space", "a"}, "value"},
  1532			}},
  1533		},
  1534		want: `<foo xmlns="space" xmlns="space"><foo xmlns="space" xmlns:_xmlns="xmlns" _xmlns:y="space" xmlns:space="space" space:a="value">`,
  1535	}, {
  1536		desc: "nested element defines default name space with existing prefix",
  1537		toks: []Token{
  1538			StartElement{Name{"", "foo"}, []Attr{
  1539				{Name{"xmlns", "x"}, "space"},
  1540			}},
  1541			StartElement{Name{"space", "foo"}, []Attr{
  1542				{Name{"", "xmlns"}, "space"},
  1543				{Name{"space", "a"}, "value"},
  1544			}},
  1545		},
  1546		want: `<foo xmlns:_xmlns="xmlns" _xmlns:x="space"><foo xmlns="space" xmlns="space" xmlns:space="space" space:a="value">`,
  1547	}, {
  1548		desc: "nested element uses empty attribute name space when default ns defined",
  1549		toks: []Token{
  1550			StartElement{Name{"space", "foo"}, []Attr{
  1551				{Name{"", "xmlns"}, "space"},
  1552			}},
  1553			StartElement{Name{"space", "foo"}, []Attr{
  1554				{Name{"", "attr"}, "value"},
  1555			}},
  1556		},
  1557		want: `<foo xmlns="space" xmlns="space"><foo xmlns="space" attr="value">`,
  1558	}, {
  1559		desc: "redefine xmlns",
  1560		toks: []Token{
  1561			StartElement{Name{"", "foo"}, []Attr{
  1562				{Name{"foo", "xmlns"}, "space"},
  1563			}},
  1564		},
  1565		want: `<foo xmlns:foo="foo" foo:xmlns="space">`,
  1566	}, {
  1567		desc: "xmlns with explicit name space #1",
  1568		toks: []Token{
  1569			StartElement{Name{"space", "foo"}, []Attr{
  1570				{Name{"xml", "xmlns"}, "space"},
  1571			}},
  1572		},
  1573		want: `<foo xmlns="space" xmlns:_xml="xml" _xml:xmlns="space">`,
  1574	}, {
  1575		desc: "xmlns with explicit name space #2",
  1576		toks: []Token{
  1577			StartElement{Name{"space", "foo"}, []Attr{
  1578				{Name{xmlURL, "xmlns"}, "space"},
  1579			}},
  1580		},
  1581		want: `<foo xmlns="space" xml:xmlns="space">`,
  1582	}, {
  1583		desc: "empty name space declaration is ignored",
  1584		toks: []Token{
  1585			StartElement{Name{"", "foo"}, []Attr{
  1586				{Name{"xmlns", "foo"}, ""},
  1587			}},
  1588		},
  1589		want: `<foo xmlns:_xmlns="xmlns" _xmlns:foo="">`,
  1590	}, {
  1591		desc: "attribute with no name is ignored",
  1592		toks: []Token{
  1593			StartElement{Name{"", "foo"}, []Attr{
  1594				{Name{"", ""}, "value"},
  1595			}},
  1596		},
  1597		want: `<foo>`,
  1598	}, {
  1599		desc: "namespace URL with non-valid name",
  1600		toks: []Token{
  1601			StartElement{Name{"/34", "foo"}, []Attr{
  1602				{Name{"/34", "x"}, "value"},
  1603			}},
  1604		},
  1605		want: `<foo xmlns="/34" xmlns:_="/34" _:x="value">`,
  1606	}, {
  1607		desc: "nested element resets default namespace to empty",
  1608		toks: []Token{
  1609			StartElement{Name{"space", "foo"}, []Attr{
  1610				{Name{"", "xmlns"}, "space"},
  1611			}},
  1612			StartElement{Name{"", "foo"}, []Attr{
  1613				{Name{"", "xmlns"}, ""},
  1614				{Name{"", "x"}, "value"},
  1615				{Name{"space", "x"}, "value"},
  1616			}},
  1617		},
  1618		want: `<foo xmlns="space" xmlns="space"><foo xmlns="" x="value" xmlns:space="space" space:x="value">`,
  1619	}, {
  1620		desc: "nested element requires empty default name space",
  1621		toks: []Token{
  1622			StartElement{Name{"space", "foo"}, []Attr{
  1623				{Name{"", "xmlns"}, "space"},
  1624			}},
  1625			StartElement{Name{"", "foo"}, nil},
  1626		},
  1627		want: `<foo xmlns="space" xmlns="space"><foo>`,
  1628	}, {
  1629		desc: "attribute uses name space from xmlns",
  1630		toks: []Token{
  1631			StartElement{Name{"some/space", "foo"}, []Attr{
  1632				{Name{"", "attr"}, "value"},
  1633				{Name{"some/space", "other"}, "other value"},
  1634			}},
  1635		},
  1636		want: `<foo xmlns="some/space" attr="value" xmlns:space="some/space" space:other="other value">`,
  1637	}, {
  1638		desc: "default name space should not be used by attributes",
  1639		toks: []Token{
  1640			StartElement{Name{"space", "foo"}, []Attr{
  1641				{Name{"", "xmlns"}, "space"},
  1642				{Name{"xmlns", "bar"}, "space"},
  1643				{Name{"space", "baz"}, "foo"},
  1644			}},
  1645			StartElement{Name{"space", "baz"}, nil},
  1646			EndElement{Name{"space", "baz"}},
  1647			EndElement{Name{"space", "foo"}},
  1648		},
  1649		want: `<foo xmlns="space" xmlns="space" xmlns:_xmlns="xmlns" _xmlns:bar="space" xmlns:space="space" space:baz="foo"><baz xmlns="space"></baz></foo>`,
  1650	}, {
  1651		desc: "default name space not used by attributes, not explicitly defined",
  1652		toks: []Token{
  1653			StartElement{Name{"space", "foo"}, []Attr{
  1654				{Name{"", "xmlns"}, "space"},
  1655				{Name{"space", "baz"}, "foo"},
  1656			}},
  1657			StartElement{Name{"space", "baz"}, nil},
  1658			EndElement{Name{"space", "baz"}},
  1659			EndElement{Name{"space", "foo"}},
  1660		},
  1661		want: `<foo xmlns="space" xmlns="space" xmlns:space="space" space:baz="foo"><baz xmlns="space"></baz></foo>`,
  1662	}, {
  1663		desc: "impossible xmlns declaration",
  1664		toks: []Token{
  1665			StartElement{Name{"", "foo"}, []Attr{
  1666				{Name{"", "xmlns"}, "space"},
  1667			}},
  1668			StartElement{Name{"space", "bar"}, []Attr{
  1669				{Name{"space", "attr"}, "value"},
  1670			}},
  1671		},
  1672		want: `<foo xmlns="space"><bar xmlns="space" xmlns:space="space" space:attr="value">`,
  1673	}}
  1674	
  1675	func TestEncodeToken(t *testing.T) {
  1676	loop:
  1677		for i, tt := range encodeTokenTests {
  1678			var buf bytes.Buffer
  1679			enc := NewEncoder(&buf)
  1680			var err error
  1681			for j, tok := range tt.toks {
  1682				err = enc.EncodeToken(tok)
  1683				if err != nil && j < len(tt.toks)-1 {
  1684					t.Errorf("#%d %s token #%d: %v", i, tt.desc, j, err)
  1685					continue loop
  1686				}
  1687			}
  1688			errorf := func(f string, a ...interface{}) {
  1689				t.Errorf("#%d %s token #%d:%s", i, tt.desc, len(tt.toks)-1, fmt.Sprintf(f, a...))
  1690			}
  1691			switch {
  1692			case tt.err != "" && err == nil:
  1693				errorf(" expected error; got none")
  1694				continue
  1695			case tt.err == "" && err != nil:
  1696				errorf(" got error: %v", err)
  1697				continue
  1698			case tt.err != "" && err != nil && tt.err != err.Error():
  1699				errorf(" error mismatch; got %v, want %v", err, tt.err)
  1700				continue
  1701			}
  1702			if err := enc.Flush(); err != nil {
  1703				errorf(" %v", err)
  1704				continue
  1705			}
  1706			if got := buf.String(); got != tt.want {
  1707				errorf("\ngot  %v\nwant %v", got, tt.want)
  1708				continue
  1709			}
  1710		}
  1711	}
  1712	
  1713	func TestProcInstEncodeToken(t *testing.T) {
  1714		var buf bytes.Buffer
  1715		enc := NewEncoder(&buf)
  1716	
  1717		if err := enc.EncodeToken(ProcInst{"xml", []byte("Instruction")}); err != nil {
  1718			t.Fatalf("enc.EncodeToken: expected to be able to encode xml target ProcInst as first token, %s", err)
  1719		}
  1720	
  1721		if err := enc.EncodeToken(ProcInst{"Target", []byte("Instruction")}); err != nil {
  1722			t.Fatalf("enc.EncodeToken: expected to be able to add non-xml target ProcInst")
  1723		}
  1724	
  1725		if err := enc.EncodeToken(ProcInst{"xml", []byte("Instruction")}); err == nil {
  1726			t.Fatalf("enc.EncodeToken: expected to not be allowed to encode xml target ProcInst when not first token")
  1727		}
  1728	}
  1729	
  1730	func TestDecodeEncode(t *testing.T) {
  1731		var in, out bytes.Buffer
  1732		in.WriteString(`<?xml version="1.0" encoding="UTF-8"?>
  1733	<?Target Instruction?>
  1734	<root>
  1735	</root>	
  1736	`)
  1737		dec := NewDecoder(&in)
  1738		enc := NewEncoder(&out)
  1739		for tok, err := dec.Token(); err == nil; tok, err = dec.Token() {
  1740			err = enc.EncodeToken(tok)
  1741			if err != nil {
  1742				t.Fatalf("enc.EncodeToken: Unable to encode token (%#v), %v", tok, err)
  1743			}
  1744		}
  1745	}
  1746	
  1747	// Issue 9796. Used to fail with GORACE="halt_on_error=1" -race.
  1748	func TestRace9796(t *testing.T) {
  1749		type A struct{}
  1750		type B struct {
  1751			C []A `xml:"X>Y"`
  1752		}
  1753		var wg sync.WaitGroup
  1754		for i := 0; i < 2; i++ {
  1755			wg.Add(1)
  1756			go func() {
  1757				Marshal(B{[]A{{}}})
  1758				wg.Done()
  1759			}()
  1760		}
  1761		wg.Wait()
  1762	}
  1763	
  1764	func TestIsValidDirective(t *testing.T) {
  1765		testOK := []string{
  1766			"<>",
  1767			"< < > >",
  1768			"<!DOCTYPE '<' '>' '>' <!--nothing-->>",
  1769			"<!DOCTYPE doc [ <!ELEMENT doc ANY> <!ELEMENT doc ANY> ]>",
  1770			"<!DOCTYPE doc [ <!ELEMENT doc \"ANY> '<' <!E\" LEMENT '>' doc ANY> ]>",
  1771			"<!DOCTYPE doc <!-- just>>>> a < comment --> [ <!ITEM anything> ] >",
  1772		}
  1773		testKO := []string{
  1774			"<",
  1775			">",
  1776			"<!--",
  1777			"-->",
  1778			"< > > < < >",
  1779			"<!dummy <!-- > -->",
  1780			"<!DOCTYPE doc '>",
  1781			"<!DOCTYPE doc '>'",
  1782			"<!DOCTYPE doc <!--comment>",
  1783		}
  1784		for _, s := range testOK {
  1785			if !isValidDirective(Directive(s)) {
  1786				t.Errorf("Directive %q is expected to be valid", s)
  1787			}
  1788		}
  1789		for _, s := range testKO {
  1790			if isValidDirective(Directive(s)) {
  1791				t.Errorf("Directive %q is expected to be invalid", s)
  1792			}
  1793		}
  1794	}
  1795	
  1796	// Issue 11719. EncodeToken used to silently eat tokens with an invalid type.
  1797	func TestSimpleUseOfEncodeToken(t *testing.T) {
  1798		var buf bytes.Buffer
  1799		enc := NewEncoder(&buf)
  1800		if err := enc.EncodeToken(&StartElement{Name: Name{"", "object1"}}); err == nil {
  1801			t.Errorf("enc.EncodeToken: pointer type should be rejected")
  1802		}
  1803		if err := enc.EncodeToken(&EndElement{Name: Name{"", "object1"}}); err == nil {
  1804			t.Errorf("enc.EncodeToken: pointer type should be rejected")
  1805		}
  1806		if err := enc.EncodeToken(StartElement{Name: Name{"", "object2"}}); err != nil {
  1807			t.Errorf("enc.EncodeToken: StartElement %s", err)
  1808		}
  1809		if err := enc.EncodeToken(EndElement{Name: Name{"", "object2"}}); err != nil {
  1810			t.Errorf("enc.EncodeToken: EndElement %s", err)
  1811		}
  1812		if err := enc.EncodeToken(Universe{}); err == nil {
  1813			t.Errorf("enc.EncodeToken: invalid type not caught")
  1814		}
  1815		if err := enc.Flush(); err != nil {
  1816			t.Errorf("enc.Flush: %s", err)
  1817		}
  1818		if buf.Len() == 0 {
  1819			t.Errorf("enc.EncodeToken: empty buffer")
  1820		}
  1821		want := "<object2></object2>"
  1822		if buf.String() != want {
  1823			t.Errorf("enc.EncodeToken: expected %q; got %q", want, buf.String())
  1824		}
  1825	}
  1826	

View as plain text