Non puoi selezionare più di 25 argomenti Gli argomenti devono iniziare con una lettera o un numero, possono includere trattini ('-') e possono essere lunghi fino a 35 caratteri.
 
 
 

1940 righe
48 KiB

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