You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

753 lines
19 KiB

  1. // Copyright 2009 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. "fmt"
  8. "io"
  9. "reflect"
  10. "strings"
  11. "testing"
  12. "unicode/utf8"
  13. )
  14. const testInput = `
  15. <?xml version="1.0" encoding="UTF-8"?>
  16. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  17. "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
  18. <body xmlns:foo="ns1" xmlns="ns2" xmlns:tag="ns3" ` +
  19. "\r\n\t" + ` >
  20. <hello lang="en">World &lt;&gt;&apos;&quot; &#x767d;&#40300;翔</hello>
  21. <query>&何; &is-it;</query>
  22. <goodbye />
  23. <outer foo:attr="value" xmlns:tag="ns4">
  24. <inner/>
  25. </outer>
  26. <tag:name>
  27. <![CDATA[Some text here.]]>
  28. </tag:name>
  29. </body><!-- missing final newline -->`
  30. var testEntity = map[string]string{"何": "What", "is-it": "is it?"}
  31. var rawTokens = []Token{
  32. CharData("\n"),
  33. ProcInst{"xml", []byte(`version="1.0" encoding="UTF-8"`)},
  34. CharData("\n"),
  35. Directive(`DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  36. "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"`),
  37. CharData("\n"),
  38. StartElement{Name{"", "body"}, []Attr{{Name{"xmlns", "foo"}, "ns1"}, {Name{"", "xmlns"}, "ns2"}, {Name{"xmlns", "tag"}, "ns3"}}},
  39. CharData("\n "),
  40. StartElement{Name{"", "hello"}, []Attr{{Name{"", "lang"}, "en"}}},
  41. CharData("World <>'\" 白鵬翔"),
  42. EndElement{Name{"", "hello"}},
  43. CharData("\n "),
  44. StartElement{Name{"", "query"}, []Attr{}},
  45. CharData("What is it?"),
  46. EndElement{Name{"", "query"}},
  47. CharData("\n "),
  48. StartElement{Name{"", "goodbye"}, []Attr{}},
  49. EndElement{Name{"", "goodbye"}},
  50. CharData("\n "),
  51. StartElement{Name{"", "outer"}, []Attr{{Name{"foo", "attr"}, "value"}, {Name{"xmlns", "tag"}, "ns4"}}},
  52. CharData("\n "),
  53. StartElement{Name{"", "inner"}, []Attr{}},
  54. EndElement{Name{"", "inner"}},
  55. CharData("\n "),
  56. EndElement{Name{"", "outer"}},
  57. CharData("\n "),
  58. StartElement{Name{"tag", "name"}, []Attr{}},
  59. CharData("\n "),
  60. CharData("Some text here."),
  61. CharData("\n "),
  62. EndElement{Name{"tag", "name"}},
  63. CharData("\n"),
  64. EndElement{Name{"", "body"}},
  65. Comment(" missing final newline "),
  66. }
  67. var cookedTokens = []Token{
  68. CharData("\n"),
  69. ProcInst{"xml", []byte(`version="1.0" encoding="UTF-8"`)},
  70. CharData("\n"),
  71. Directive(`DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  72. "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"`),
  73. CharData("\n"),
  74. StartElement{Name{"ns2", "body"}, []Attr{{Name{"xmlns", "foo"}, "ns1"}, {Name{"", "xmlns"}, "ns2"}, {Name{"xmlns", "tag"}, "ns3"}}},
  75. CharData("\n "),
  76. StartElement{Name{"ns2", "hello"}, []Attr{{Name{"", "lang"}, "en"}}},
  77. CharData("World <>'\" 白鵬翔"),
  78. EndElement{Name{"ns2", "hello"}},
  79. CharData("\n "),
  80. StartElement{Name{"ns2", "query"}, []Attr{}},
  81. CharData("What is it?"),
  82. EndElement{Name{"ns2", "query"}},
  83. CharData("\n "),
  84. StartElement{Name{"ns2", "goodbye"}, []Attr{}},
  85. EndElement{Name{"ns2", "goodbye"}},
  86. CharData("\n "),
  87. StartElement{Name{"ns2", "outer"}, []Attr{{Name{"ns1", "attr"}, "value"}, {Name{"xmlns", "tag"}, "ns4"}}},
  88. CharData("\n "),
  89. StartElement{Name{"ns2", "inner"}, []Attr{}},
  90. EndElement{Name{"ns2", "inner"}},
  91. CharData("\n "),
  92. EndElement{Name{"ns2", "outer"}},
  93. CharData("\n "),
  94. StartElement{Name{"ns3", "name"}, []Attr{}},
  95. CharData("\n "),
  96. CharData("Some text here."),
  97. CharData("\n "),
  98. EndElement{Name{"ns3", "name"}},
  99. CharData("\n"),
  100. EndElement{Name{"ns2", "body"}},
  101. Comment(" missing final newline "),
  102. }
  103. const testInputAltEncoding = `
  104. <?xml version="1.0" encoding="x-testing-uppercase"?>
  105. <TAG>VALUE</TAG>`
  106. var rawTokensAltEncoding = []Token{
  107. CharData("\n"),
  108. ProcInst{"xml", []byte(`version="1.0" encoding="x-testing-uppercase"`)},
  109. CharData("\n"),
  110. StartElement{Name{"", "tag"}, []Attr{}},
  111. CharData("value"),
  112. EndElement{Name{"", "tag"}},
  113. }
  114. var xmlInput = []string{
  115. // unexpected EOF cases
  116. "<",
  117. "<t",
  118. "<t ",
  119. "<t/",
  120. "<!",
  121. "<!-",
  122. "<!--",
  123. "<!--c-",
  124. "<!--c--",
  125. "<!d",
  126. "<t></",
  127. "<t></t",
  128. "<?",
  129. "<?p",
  130. "<t a",
  131. "<t a=",
  132. "<t a='",
  133. "<t a=''",
  134. "<t/><![",
  135. "<t/><![C",
  136. "<t/><![CDATA[d",
  137. "<t/><![CDATA[d]",
  138. "<t/><![CDATA[d]]",
  139. // other Syntax errors
  140. "<>",
  141. "<t/a",
  142. "<0 />",
  143. "<?0 >",
  144. // "<!0 >", // let the Token() caller handle
  145. "</0>",
  146. "<t 0=''>",
  147. "<t a='&'>",
  148. "<t a='<'>",
  149. "<t>&nbspc;</t>",
  150. "<t a>",
  151. "<t a=>",
  152. "<t a=v>",
  153. // "<![CDATA[d]]>", // let the Token() caller handle
  154. "<t></e>",
  155. "<t></>",
  156. "<t></t!",
  157. "<t>cdata]]></t>",
  158. }
  159. func TestRawToken(t *testing.T) {
  160. d := NewDecoder(strings.NewReader(testInput))
  161. d.Entity = testEntity
  162. testRawToken(t, d, testInput, rawTokens)
  163. }
  164. const nonStrictInput = `
  165. <tag>non&entity</tag>
  166. <tag>&unknown;entity</tag>
  167. <tag>&#123</tag>
  168. <tag>&#zzz;</tag>
  169. <tag>&なまえ3;</tag>
  170. <tag>&lt-gt;</tag>
  171. <tag>&;</tag>
  172. <tag>&0a;</tag>
  173. `
  174. var nonStringEntity = map[string]string{"": "oops!", "0a": "oops!"}
  175. var nonStrictTokens = []Token{
  176. CharData("\n"),
  177. StartElement{Name{"", "tag"}, []Attr{}},
  178. CharData("non&entity"),
  179. EndElement{Name{"", "tag"}},
  180. CharData("\n"),
  181. StartElement{Name{"", "tag"}, []Attr{}},
  182. CharData("&unknown;entity"),
  183. EndElement{Name{"", "tag"}},
  184. CharData("\n"),
  185. StartElement{Name{"", "tag"}, []Attr{}},
  186. CharData("&#123"),
  187. EndElement{Name{"", "tag"}},
  188. CharData("\n"),
  189. StartElement{Name{"", "tag"}, []Attr{}},
  190. CharData("&#zzz;"),
  191. EndElement{Name{"", "tag"}},
  192. CharData("\n"),
  193. StartElement{Name{"", "tag"}, []Attr{}},
  194. CharData("&なまえ3;"),
  195. EndElement{Name{"", "tag"}},
  196. CharData("\n"),
  197. StartElement{Name{"", "tag"}, []Attr{}},
  198. CharData("&lt-gt;"),
  199. EndElement{Name{"", "tag"}},
  200. CharData("\n"),
  201. StartElement{Name{"", "tag"}, []Attr{}},
  202. CharData("&;"),
  203. EndElement{Name{"", "tag"}},
  204. CharData("\n"),
  205. StartElement{Name{"", "tag"}, []Attr{}},
  206. CharData("&0a;"),
  207. EndElement{Name{"", "tag"}},
  208. CharData("\n"),
  209. }
  210. func TestNonStrictRawToken(t *testing.T) {
  211. d := NewDecoder(strings.NewReader(nonStrictInput))
  212. d.Strict = false
  213. testRawToken(t, d, nonStrictInput, nonStrictTokens)
  214. }
  215. type downCaser struct {
  216. t *testing.T
  217. r io.ByteReader
  218. }
  219. func (d *downCaser) ReadByte() (c byte, err error) {
  220. c, err = d.r.ReadByte()
  221. if c >= 'A' && c <= 'Z' {
  222. c += 'a' - 'A'
  223. }
  224. return
  225. }
  226. func (d *downCaser) Read(p []byte) (int, error) {
  227. d.t.Fatalf("unexpected Read call on downCaser reader")
  228. panic("unreachable")
  229. }
  230. func TestRawTokenAltEncoding(t *testing.T) {
  231. d := NewDecoder(strings.NewReader(testInputAltEncoding))
  232. d.CharsetReader = func(charset string, input io.Reader) (io.Reader, error) {
  233. if charset != "x-testing-uppercase" {
  234. t.Fatalf("unexpected charset %q", charset)
  235. }
  236. return &downCaser{t, input.(io.ByteReader)}, nil
  237. }
  238. testRawToken(t, d, testInputAltEncoding, rawTokensAltEncoding)
  239. }
  240. func TestRawTokenAltEncodingNoConverter(t *testing.T) {
  241. d := NewDecoder(strings.NewReader(testInputAltEncoding))
  242. token, err := d.RawToken()
  243. if token == nil {
  244. t.Fatalf("expected a token on first RawToken call")
  245. }
  246. if err != nil {
  247. t.Fatal(err)
  248. }
  249. token, err = d.RawToken()
  250. if token != nil {
  251. t.Errorf("expected a nil token; got %#v", token)
  252. }
  253. if err == nil {
  254. t.Fatalf("expected an error on second RawToken call")
  255. }
  256. const encoding = "x-testing-uppercase"
  257. if !strings.Contains(err.Error(), encoding) {
  258. t.Errorf("expected error to contain %q; got error: %v",
  259. encoding, err)
  260. }
  261. }
  262. func testRawToken(t *testing.T, d *Decoder, raw string, rawTokens []Token) {
  263. lastEnd := int64(0)
  264. for i, want := range rawTokens {
  265. start := d.InputOffset()
  266. have, err := d.RawToken()
  267. end := d.InputOffset()
  268. if err != nil {
  269. t.Fatalf("token %d: unexpected error: %s", i, err)
  270. }
  271. if !reflect.DeepEqual(have, want) {
  272. var shave, swant string
  273. if _, ok := have.(CharData); ok {
  274. shave = fmt.Sprintf("CharData(%q)", have)
  275. } else {
  276. shave = fmt.Sprintf("%#v", have)
  277. }
  278. if _, ok := want.(CharData); ok {
  279. swant = fmt.Sprintf("CharData(%q)", want)
  280. } else {
  281. swant = fmt.Sprintf("%#v", want)
  282. }
  283. t.Errorf("token %d = %s, want %s", i, shave, swant)
  284. }
  285. // Check that InputOffset returned actual token.
  286. switch {
  287. case start < lastEnd:
  288. t.Errorf("token %d: position [%d,%d) for %T is before previous token", i, start, end, have)
  289. case start >= end:
  290. // Special case: EndElement can be synthesized.
  291. if start == end && end == lastEnd {
  292. break
  293. }
  294. t.Errorf("token %d: position [%d,%d) for %T is empty", i, start, end, have)
  295. case end > int64(len(raw)):
  296. t.Errorf("token %d: position [%d,%d) for %T extends beyond input", i, start, end, have)
  297. default:
  298. text := raw[start:end]
  299. if strings.ContainsAny(text, "<>") && (!strings.HasPrefix(text, "<") || !strings.HasSuffix(text, ">")) {
  300. t.Errorf("token %d: misaligned raw token %#q for %T", i, text, have)
  301. }
  302. }
  303. lastEnd = end
  304. }
  305. }
  306. // Ensure that directives (specifically !DOCTYPE) include the complete
  307. // text of any nested directives, noting that < and > do not change
  308. // nesting depth if they are in single or double quotes.
  309. var nestedDirectivesInput = `
  310. <!DOCTYPE [<!ENTITY rdf "http://www.w3.org/1999/02/22-rdf-syntax-ns#">]>
  311. <!DOCTYPE [<!ENTITY xlt ">">]>
  312. <!DOCTYPE [<!ENTITY xlt "<">]>
  313. <!DOCTYPE [<!ENTITY xlt '>'>]>
  314. <!DOCTYPE [<!ENTITY xlt '<'>]>
  315. <!DOCTYPE [<!ENTITY xlt '">'>]>
  316. <!DOCTYPE [<!ENTITY xlt "'<">]>
  317. `
  318. var nestedDirectivesTokens = []Token{
  319. CharData("\n"),
  320. Directive(`DOCTYPE [<!ENTITY rdf "http://www.w3.org/1999/02/22-rdf-syntax-ns#">]`),
  321. CharData("\n"),
  322. Directive(`DOCTYPE [<!ENTITY xlt ">">]`),
  323. CharData("\n"),
  324. Directive(`DOCTYPE [<!ENTITY xlt "<">]`),
  325. CharData("\n"),
  326. Directive(`DOCTYPE [<!ENTITY xlt '>'>]`),
  327. CharData("\n"),
  328. Directive(`DOCTYPE [<!ENTITY xlt '<'>]`),
  329. CharData("\n"),
  330. Directive(`DOCTYPE [<!ENTITY xlt '">'>]`),
  331. CharData("\n"),
  332. Directive(`DOCTYPE [<!ENTITY xlt "'<">]`),
  333. CharData("\n"),
  334. }
  335. func TestNestedDirectives(t *testing.T) {
  336. d := NewDecoder(strings.NewReader(nestedDirectivesInput))
  337. for i, want := range nestedDirectivesTokens {
  338. have, err := d.Token()
  339. if err != nil {
  340. t.Fatalf("token %d: unexpected error: %s", i, err)
  341. }
  342. if !reflect.DeepEqual(have, want) {
  343. t.Errorf("token %d = %#v want %#v", i, have, want)
  344. }
  345. }
  346. }
  347. func TestToken(t *testing.T) {
  348. d := NewDecoder(strings.NewReader(testInput))
  349. d.Entity = testEntity
  350. for i, want := range cookedTokens {
  351. have, err := d.Token()
  352. if err != nil {
  353. t.Fatalf("token %d: unexpected error: %s", i, err)
  354. }
  355. if !reflect.DeepEqual(have, want) {
  356. t.Errorf("token %d = %#v want %#v", i, have, want)
  357. }
  358. }
  359. }
  360. func TestSyntax(t *testing.T) {
  361. for i := range xmlInput {
  362. d := NewDecoder(strings.NewReader(xmlInput[i]))
  363. var err error
  364. for _, err = d.Token(); err == nil; _, err = d.Token() {
  365. }
  366. if _, ok := err.(*SyntaxError); !ok {
  367. t.Fatalf(`xmlInput "%s": expected SyntaxError not received`, xmlInput[i])
  368. }
  369. }
  370. }
  371. type allScalars struct {
  372. True1 bool
  373. True2 bool
  374. False1 bool
  375. False2 bool
  376. Int int
  377. Int8 int8
  378. Int16 int16
  379. Int32 int32
  380. Int64 int64
  381. Uint int
  382. Uint8 uint8
  383. Uint16 uint16
  384. Uint32 uint32
  385. Uint64 uint64
  386. Uintptr uintptr
  387. Float32 float32
  388. Float64 float64
  389. String string
  390. PtrString *string
  391. }
  392. var all = allScalars{
  393. True1: true,
  394. True2: true,
  395. False1: false,
  396. False2: false,
  397. Int: 1,
  398. Int8: -2,
  399. Int16: 3,
  400. Int32: -4,
  401. Int64: 5,
  402. Uint: 6,
  403. Uint8: 7,
  404. Uint16: 8,
  405. Uint32: 9,
  406. Uint64: 10,
  407. Uintptr: 11,
  408. Float32: 13.0,
  409. Float64: 14.0,
  410. String: "15",
  411. PtrString: &sixteen,
  412. }
  413. var sixteen = "16"
  414. const testScalarsInput = `<allscalars>
  415. <True1>true</True1>
  416. <True2>1</True2>
  417. <False1>false</False1>
  418. <False2>0</False2>
  419. <Int>1</Int>
  420. <Int8>-2</Int8>
  421. <Int16>3</Int16>
  422. <Int32>-4</Int32>
  423. <Int64>5</Int64>
  424. <Uint>6</Uint>
  425. <Uint8>7</Uint8>
  426. <Uint16>8</Uint16>
  427. <Uint32>9</Uint32>
  428. <Uint64>10</Uint64>
  429. <Uintptr>11</Uintptr>
  430. <Float>12.0</Float>
  431. <Float32>13.0</Float32>
  432. <Float64>14.0</Float64>
  433. <String>15</String>
  434. <PtrString>16</PtrString>
  435. </allscalars>`
  436. func TestAllScalars(t *testing.T) {
  437. var a allScalars
  438. err := Unmarshal([]byte(testScalarsInput), &a)
  439. if err != nil {
  440. t.Fatal(err)
  441. }
  442. if !reflect.DeepEqual(a, all) {
  443. t.Errorf("have %+v want %+v", a, all)
  444. }
  445. }
  446. type item struct {
  447. Field_a string
  448. }
  449. func TestIssue569(t *testing.T) {
  450. data := `<item><Field_a>abcd</Field_a></item>`
  451. var i item
  452. err := Unmarshal([]byte(data), &i)
  453. if err != nil || i.Field_a != "abcd" {
  454. t.Fatal("Expecting abcd")
  455. }
  456. }
  457. func TestUnquotedAttrs(t *testing.T) {
  458. data := "<tag attr=azAZ09:-_\t>"
  459. d := NewDecoder(strings.NewReader(data))
  460. d.Strict = false
  461. token, err := d.Token()
  462. if _, ok := err.(*SyntaxError); ok {
  463. t.Errorf("Unexpected error: %v", err)
  464. }
  465. if token.(StartElement).Name.Local != "tag" {
  466. t.Errorf("Unexpected tag name: %v", token.(StartElement).Name.Local)
  467. }
  468. attr := token.(StartElement).Attr[0]
  469. if attr.Value != "azAZ09:-_" {
  470. t.Errorf("Unexpected attribute value: %v", attr.Value)
  471. }
  472. if attr.Name.Local != "attr" {
  473. t.Errorf("Unexpected attribute name: %v", attr.Name.Local)
  474. }
  475. }
  476. func TestValuelessAttrs(t *testing.T) {
  477. tests := [][3]string{
  478. {"<p nowrap>", "p", "nowrap"},
  479. {"<p nowrap >", "p", "nowrap"},
  480. {"<input checked/>", "input", "checked"},
  481. {"<input checked />", "input", "checked"},
  482. }
  483. for _, test := range tests {
  484. d := NewDecoder(strings.NewReader(test[0]))
  485. d.Strict = false
  486. token, err := d.Token()
  487. if _, ok := err.(*SyntaxError); ok {
  488. t.Errorf("Unexpected error: %v", err)
  489. }
  490. if token.(StartElement).Name.Local != test[1] {
  491. t.Errorf("Unexpected tag name: %v", token.(StartElement).Name.Local)
  492. }
  493. attr := token.(StartElement).Attr[0]
  494. if attr.Value != test[2] {
  495. t.Errorf("Unexpected attribute value: %v", attr.Value)
  496. }
  497. if attr.Name.Local != test[2] {
  498. t.Errorf("Unexpected attribute name: %v", attr.Name.Local)
  499. }
  500. }
  501. }
  502. func TestCopyTokenCharData(t *testing.T) {
  503. data := []byte("same data")
  504. var tok1 Token = CharData(data)
  505. tok2 := CopyToken(tok1)
  506. if !reflect.DeepEqual(tok1, tok2) {
  507. t.Error("CopyToken(CharData) != CharData")
  508. }
  509. data[1] = 'o'
  510. if reflect.DeepEqual(tok1, tok2) {
  511. t.Error("CopyToken(CharData) uses same buffer.")
  512. }
  513. }
  514. func TestCopyTokenStartElement(t *testing.T) {
  515. elt := StartElement{Name{"", "hello"}, []Attr{{Name{"", "lang"}, "en"}}}
  516. var tok1 Token = elt
  517. tok2 := CopyToken(tok1)
  518. if tok1.(StartElement).Attr[0].Value != "en" {
  519. t.Error("CopyToken overwrote Attr[0]")
  520. }
  521. if !reflect.DeepEqual(tok1, tok2) {
  522. t.Error("CopyToken(StartElement) != StartElement")
  523. }
  524. tok1.(StartElement).Attr[0] = Attr{Name{"", "lang"}, "de"}
  525. if reflect.DeepEqual(tok1, tok2) {
  526. t.Error("CopyToken(CharData) uses same buffer.")
  527. }
  528. }
  529. func TestSyntaxErrorLineNum(t *testing.T) {
  530. testInput := "<P>Foo<P>\n\n<P>Bar</>\n"
  531. d := NewDecoder(strings.NewReader(testInput))
  532. var err error
  533. for _, err = d.Token(); err == nil; _, err = d.Token() {
  534. }
  535. synerr, ok := err.(*SyntaxError)
  536. if !ok {
  537. t.Error("Expected SyntaxError.")
  538. }
  539. if synerr.Line != 3 {
  540. t.Error("SyntaxError didn't have correct line number.")
  541. }
  542. }
  543. func TestTrailingRawToken(t *testing.T) {
  544. input := `<FOO></FOO> `
  545. d := NewDecoder(strings.NewReader(input))
  546. var err error
  547. for _, err = d.RawToken(); err == nil; _, err = d.RawToken() {
  548. }
  549. if err != io.EOF {
  550. t.Fatalf("d.RawToken() = _, %v, want _, io.EOF", err)
  551. }
  552. }
  553. func TestTrailingToken(t *testing.T) {
  554. input := `<FOO></FOO> `
  555. d := NewDecoder(strings.NewReader(input))
  556. var err error
  557. for _, err = d.Token(); err == nil; _, err = d.Token() {
  558. }
  559. if err != io.EOF {
  560. t.Fatalf("d.Token() = _, %v, want _, io.EOF", err)
  561. }
  562. }
  563. func TestEntityInsideCDATA(t *testing.T) {
  564. input := `<test><![CDATA[ &val=foo ]]></test>`
  565. d := NewDecoder(strings.NewReader(input))
  566. var err error
  567. for _, err = d.Token(); err == nil; _, err = d.Token() {
  568. }
  569. if err != io.EOF {
  570. t.Fatalf("d.Token() = _, %v, want _, io.EOF", err)
  571. }
  572. }
  573. var characterTests = []struct {
  574. in string
  575. err string
  576. }{
  577. {"\x12<doc/>", "illegal character code U+0012"},
  578. {"<?xml version=\"1.0\"?>\x0b<doc/>", "illegal character code U+000B"},
  579. {"\xef\xbf\xbe<doc/>", "illegal character code U+FFFE"},
  580. {"<?xml version=\"1.0\"?><doc>\r\n<hiya/>\x07<toots/></doc>", "illegal character code U+0007"},
  581. {"<?xml version=\"1.0\"?><doc \x12='value'>what's up</doc>", "expected attribute name in element"},
  582. {"<doc>&abc\x01;</doc>", "invalid character entity &abc (no semicolon)"},
  583. {"<doc>&\x01;</doc>", "invalid character entity & (no semicolon)"},
  584. {"<doc>&\xef\xbf\xbe;</doc>", "invalid character entity &\uFFFE;"},
  585. {"<doc>&hello;</doc>", "invalid character entity &hello;"},
  586. }
  587. func TestDisallowedCharacters(t *testing.T) {
  588. for i, tt := range characterTests {
  589. d := NewDecoder(strings.NewReader(tt.in))
  590. var err error
  591. for err == nil {
  592. _, err = d.Token()
  593. }
  594. synerr, ok := err.(*SyntaxError)
  595. if !ok {
  596. t.Fatalf("input %d d.Token() = _, %v, want _, *SyntaxError", i, err)
  597. }
  598. if synerr.Msg != tt.err {
  599. t.Fatalf("input %d synerr.Msg wrong: want %q, got %q", i, tt.err, synerr.Msg)
  600. }
  601. }
  602. }
  603. type procInstEncodingTest struct {
  604. expect, got string
  605. }
  606. var procInstTests = []struct {
  607. input string
  608. expect [2]string
  609. }{
  610. {`version="1.0" encoding="utf-8"`, [2]string{"1.0", "utf-8"}},
  611. {`version="1.0" encoding='utf-8'`, [2]string{"1.0", "utf-8"}},
  612. {`version="1.0" encoding='utf-8' `, [2]string{"1.0", "utf-8"}},
  613. {`version="1.0" encoding=utf-8`, [2]string{"1.0", ""}},
  614. {`encoding="FOO" `, [2]string{"", "FOO"}},
  615. }
  616. func TestProcInstEncoding(t *testing.T) {
  617. for _, test := range procInstTests {
  618. if got := procInst("version", test.input); got != test.expect[0] {
  619. t.Errorf("procInst(version, %q) = %q; want %q", test.input, got, test.expect[0])
  620. }
  621. if got := procInst("encoding", test.input); got != test.expect[1] {
  622. t.Errorf("procInst(encoding, %q) = %q; want %q", test.input, got, test.expect[1])
  623. }
  624. }
  625. }
  626. // Ensure that directives with comments include the complete
  627. // text of any nested directives.
  628. var directivesWithCommentsInput = `
  629. <!DOCTYPE [<!-- a comment --><!ENTITY rdf "http://www.w3.org/1999/02/22-rdf-syntax-ns#">]>
  630. <!DOCTYPE [<!ENTITY go "Golang"><!-- a comment-->]>
  631. <!DOCTYPE <!-> <!> <!----> <!-->--> <!--->--> [<!ENTITY go "Golang"><!-- a comment-->]>
  632. `
  633. var directivesWithCommentsTokens = []Token{
  634. CharData("\n"),
  635. Directive(`DOCTYPE [<!ENTITY rdf "http://www.w3.org/1999/02/22-rdf-syntax-ns#">]`),
  636. CharData("\n"),
  637. Directive(`DOCTYPE [<!ENTITY go "Golang">]`),
  638. CharData("\n"),
  639. Directive(`DOCTYPE <!-> <!> [<!ENTITY go "Golang">]`),
  640. CharData("\n"),
  641. }
  642. func TestDirectivesWithComments(t *testing.T) {
  643. d := NewDecoder(strings.NewReader(directivesWithCommentsInput))
  644. for i, want := range directivesWithCommentsTokens {
  645. have, err := d.Token()
  646. if err != nil {
  647. t.Fatalf("token %d: unexpected error: %s", i, err)
  648. }
  649. if !reflect.DeepEqual(have, want) {
  650. t.Errorf("token %d = %#v want %#v", i, have, want)
  651. }
  652. }
  653. }
  654. // Writer whose Write method always returns an error.
  655. type errWriter struct{}
  656. func (errWriter) Write(p []byte) (n int, err error) { return 0, fmt.Errorf("unwritable") }
  657. func TestEscapeTextIOErrors(t *testing.T) {
  658. expectErr := "unwritable"
  659. err := EscapeText(errWriter{}, []byte{'A'})
  660. if err == nil || err.Error() != expectErr {
  661. t.Errorf("have %v, want %v", err, expectErr)
  662. }
  663. }
  664. func TestEscapeTextInvalidChar(t *testing.T) {
  665. input := []byte("A \x00 terminated string.")
  666. expected := "A \uFFFD terminated string."
  667. buff := new(bytes.Buffer)
  668. if err := EscapeText(buff, input); err != nil {
  669. t.Fatalf("have %v, want nil", err)
  670. }
  671. text := buff.String()
  672. if text != expected {
  673. t.Errorf("have %v, want %v", text, expected)
  674. }
  675. }
  676. func TestIssue5880(t *testing.T) {
  677. type T []byte
  678. data, err := Marshal(T{192, 168, 0, 1})
  679. if err != nil {
  680. t.Errorf("Marshal error: %v", err)
  681. }
  682. if !utf8.Valid(data) {
  683. t.Errorf("Marshal generated invalid UTF-8: %x", data)
  684. }
  685. }