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

View as plain text