OSDN Git Service

libgo: Update to weekly.2011-11-18.
[pf3gnuchains/gcc-fork.git] / libgo / go / encoding / xml / xml_test.go
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
5 package xml
6
7 import (
8         "bytes"
9         "io"
10         "reflect"
11         "strings"
12         "testing"
13 )
14
15 const testInput = `
16 <?xml version="1.0" encoding="UTF-8"?>
17 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
18   "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
19 <body xmlns:foo="ns1" xmlns="ns2" xmlns:tag="ns3" ` +
20         "\r\n\t" + `  >
21   <hello lang="en">World &lt;&gt;&apos;&quot; &#x767d;&#40300;翔</hello>
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
31 var rawTokens = []Token{
32         CharData([]byte("\n")),
33         ProcInst{"xml", []byte(`version="1.0" encoding="UTF-8"`)},
34         CharData([]byte("\n")),
35         Directive([]byte(`DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
36   "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"`),
37         ),
38         CharData([]byte("\n")),
39         StartElement{Name{"", "body"}, []Attr{{Name{"xmlns", "foo"}, "ns1"}, {Name{"", "xmlns"}, "ns2"}, {Name{"xmlns", "tag"}, "ns3"}}},
40         CharData([]byte("\n  ")),
41         StartElement{Name{"", "hello"}, []Attr{{Name{"", "lang"}, "en"}}},
42         CharData([]byte("World <>'\" 白鵬翔")),
43         EndElement{Name{"", "hello"}},
44         CharData([]byte("\n  ")),
45         StartElement{Name{"", "goodbye"}, []Attr{}},
46         EndElement{Name{"", "goodbye"}},
47         CharData([]byte("\n  ")),
48         StartElement{Name{"", "outer"}, []Attr{{Name{"foo", "attr"}, "value"}, {Name{"xmlns", "tag"}, "ns4"}}},
49         CharData([]byte("\n    ")),
50         StartElement{Name{"", "inner"}, []Attr{}},
51         EndElement{Name{"", "inner"}},
52         CharData([]byte("\n  ")),
53         EndElement{Name{"", "outer"}},
54         CharData([]byte("\n  ")),
55         StartElement{Name{"tag", "name"}, []Attr{}},
56         CharData([]byte("\n    ")),
57         CharData([]byte("Some text here.")),
58         CharData([]byte("\n  ")),
59         EndElement{Name{"tag", "name"}},
60         CharData([]byte("\n")),
61         EndElement{Name{"", "body"}},
62         Comment([]byte(" missing final newline ")),
63 }
64
65 var cookedTokens = []Token{
66         CharData([]byte("\n")),
67         ProcInst{"xml", []byte(`version="1.0" encoding="UTF-8"`)},
68         CharData([]byte("\n")),
69         Directive([]byte(`DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
70   "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"`),
71         ),
72         CharData([]byte("\n")),
73         StartElement{Name{"ns2", "body"}, []Attr{{Name{"xmlns", "foo"}, "ns1"}, {Name{"", "xmlns"}, "ns2"}, {Name{"xmlns", "tag"}, "ns3"}}},
74         CharData([]byte("\n  ")),
75         StartElement{Name{"ns2", "hello"}, []Attr{{Name{"", "lang"}, "en"}}},
76         CharData([]byte("World <>'\" 白鵬翔")),
77         EndElement{Name{"ns2", "hello"}},
78         CharData([]byte("\n  ")),
79         StartElement{Name{"ns2", "goodbye"}, []Attr{}},
80         EndElement{Name{"ns2", "goodbye"}},
81         CharData([]byte("\n  ")),
82         StartElement{Name{"ns2", "outer"}, []Attr{{Name{"ns1", "attr"}, "value"}, {Name{"xmlns", "tag"}, "ns4"}}},
83         CharData([]byte("\n    ")),
84         StartElement{Name{"ns2", "inner"}, []Attr{}},
85         EndElement{Name{"ns2", "inner"}},
86         CharData([]byte("\n  ")),
87         EndElement{Name{"ns2", "outer"}},
88         CharData([]byte("\n  ")),
89         StartElement{Name{"ns3", "name"}, []Attr{}},
90         CharData([]byte("\n    ")),
91         CharData([]byte("Some text here.")),
92         CharData([]byte("\n  ")),
93         EndElement{Name{"ns3", "name"}},
94         CharData([]byte("\n")),
95         EndElement{Name{"ns2", "body"}},
96         Comment([]byte(" missing final newline ")),
97 }
98
99 const testInputAltEncoding = `
100 <?xml version="1.0" encoding="x-testing-uppercase"?>
101 <TAG>VALUE</TAG>`
102
103 var rawTokensAltEncoding = []Token{
104         CharData([]byte("\n")),
105         ProcInst{"xml", []byte(`version="1.0" encoding="x-testing-uppercase"`)},
106         CharData([]byte("\n")),
107         StartElement{Name{"", "tag"}, []Attr{}},
108         CharData([]byte("value")),
109         EndElement{Name{"", "tag"}},
110 }
111
112 var xmlInput = []string{
113         // unexpected EOF cases
114         "<",
115         "<t",
116         "<t ",
117         "<t/",
118         "<!",
119         "<!-",
120         "<!--",
121         "<!--c-",
122         "<!--c--",
123         "<!d",
124         "<t></",
125         "<t></t",
126         "<?",
127         "<?p",
128         "<t a",
129         "<t a=",
130         "<t a='",
131         "<t a=''",
132         "<t/><![",
133         "<t/><![C",
134         "<t/><![CDATA[d",
135         "<t/><![CDATA[d]",
136         "<t/><![CDATA[d]]",
137
138         // other Syntax errors
139         "<>",
140         "<t/a",
141         "<0 />",
142         "<?0 >",
143         //      "<!0 >",        // let the Token() caller handle
144         "</0>",
145         "<t 0=''>",
146         "<t a='&'>",
147         "<t a='<'>",
148         "<t>&nbspc;</t>",
149         "<t a>",
150         "<t a=>",
151         "<t a=v>",
152         //      "<![CDATA[d]]>",        // let the Token() caller handle
153         "<t></e>",
154         "<t></>",
155         "<t></t!",
156         "<t>cdata]]></t>",
157 }
158
159 type stringReader struct {
160         s   string
161         off int
162 }
163
164 func (r *stringReader) Read(b []byte) (n int, err error) {
165         if r.off >= len(r.s) {
166                 return 0, io.EOF
167         }
168         for r.off < len(r.s) && n < len(b) {
169                 b[n] = r.s[r.off]
170                 n++
171                 r.off++
172         }
173         return
174 }
175
176 func (r *stringReader) ReadByte() (b byte, err error) {
177         if r.off >= len(r.s) {
178                 return 0, io.EOF
179         }
180         b = r.s[r.off]
181         r.off++
182         return
183 }
184
185 func StringReader(s string) io.Reader { return &stringReader{s, 0} }
186
187 func TestRawToken(t *testing.T) {
188         p := NewParser(StringReader(testInput))
189         testRawToken(t, p, rawTokens)
190 }
191
192 type downCaser struct {
193         t *testing.T
194         r io.ByteReader
195 }
196
197 func (d *downCaser) ReadByte() (c byte, err error) {
198         c, err = d.r.ReadByte()
199         if c >= 'A' && c <= 'Z' {
200                 c += 'a' - 'A'
201         }
202         return
203 }
204
205 func (d *downCaser) Read(p []byte) (int, error) {
206         d.t.Fatalf("unexpected Read call on downCaser reader")
207         panic("unreachable")
208 }
209
210 func TestRawTokenAltEncoding(t *testing.T) {
211         sawEncoding := ""
212         p := NewParser(StringReader(testInputAltEncoding))
213         p.CharsetReader = func(charset string, input io.Reader) (io.Reader, error) {
214                 sawEncoding = charset
215                 if charset != "x-testing-uppercase" {
216                         t.Fatalf("unexpected charset %q", charset)
217                 }
218                 return &downCaser{t, input.(io.ByteReader)}, nil
219         }
220         testRawToken(t, p, rawTokensAltEncoding)
221 }
222
223 func TestRawTokenAltEncodingNoConverter(t *testing.T) {
224         p := NewParser(StringReader(testInputAltEncoding))
225         token, err := p.RawToken()
226         if token == nil {
227                 t.Fatalf("expected a token on first RawToken call")
228         }
229         if err != nil {
230                 t.Fatal(err)
231         }
232         token, err = p.RawToken()
233         if token != nil {
234                 t.Errorf("expected a nil token; got %#v", token)
235         }
236         if err == nil {
237                 t.Fatalf("expected an error on second RawToken call")
238         }
239         const encoding = "x-testing-uppercase"
240         if !strings.Contains(err.Error(), encoding) {
241                 t.Errorf("expected error to contain %q; got error: %v",
242                         encoding, err)
243         }
244 }
245
246 func testRawToken(t *testing.T, p *Parser, rawTokens []Token) {
247         for i, want := range rawTokens {
248                 have, err := p.RawToken()
249                 if err != nil {
250                         t.Fatalf("token %d: unexpected error: %s", i, err)
251                 }
252                 if !reflect.DeepEqual(have, want) {
253                         t.Errorf("token %d = %#v want %#v", i, have, want)
254                 }
255         }
256 }
257
258 // Ensure that directives (specifically !DOCTYPE) include the complete
259 // text of any nested directives, noting that < and > do not change
260 // nesting depth if they are in single or double quotes.
261
262 var nestedDirectivesInput = `
263 <!DOCTYPE [<!ENTITY rdf "http://www.w3.org/1999/02/22-rdf-syntax-ns#">]>
264 <!DOCTYPE [<!ENTITY xlt ">">]>
265 <!DOCTYPE [<!ENTITY xlt "<">]>
266 <!DOCTYPE [<!ENTITY xlt '>'>]>
267 <!DOCTYPE [<!ENTITY xlt '<'>]>
268 <!DOCTYPE [<!ENTITY xlt '">'>]>
269 <!DOCTYPE [<!ENTITY xlt "'<">]>
270 `
271
272 var nestedDirectivesTokens = []Token{
273         CharData([]byte("\n")),
274         Directive([]byte(`DOCTYPE [<!ENTITY rdf "http://www.w3.org/1999/02/22-rdf-syntax-ns#">]`)),
275         CharData([]byte("\n")),
276         Directive([]byte(`DOCTYPE [<!ENTITY xlt ">">]`)),
277         CharData([]byte("\n")),
278         Directive([]byte(`DOCTYPE [<!ENTITY xlt "<">]`)),
279         CharData([]byte("\n")),
280         Directive([]byte(`DOCTYPE [<!ENTITY xlt '>'>]`)),
281         CharData([]byte("\n")),
282         Directive([]byte(`DOCTYPE [<!ENTITY xlt '<'>]`)),
283         CharData([]byte("\n")),
284         Directive([]byte(`DOCTYPE [<!ENTITY xlt '">'>]`)),
285         CharData([]byte("\n")),
286         Directive([]byte(`DOCTYPE [<!ENTITY xlt "'<">]`)),
287         CharData([]byte("\n")),
288 }
289
290 func TestNestedDirectives(t *testing.T) {
291         p := NewParser(StringReader(nestedDirectivesInput))
292
293         for i, want := range nestedDirectivesTokens {
294                 have, err := p.Token()
295                 if err != nil {
296                         t.Fatalf("token %d: unexpected error: %s", i, err)
297                 }
298                 if !reflect.DeepEqual(have, want) {
299                         t.Errorf("token %d = %#v want %#v", i, have, want)
300                 }
301         }
302 }
303
304 func TestToken(t *testing.T) {
305         p := NewParser(StringReader(testInput))
306
307         for i, want := range cookedTokens {
308                 have, err := p.Token()
309                 if err != nil {
310                         t.Fatalf("token %d: unexpected error: %s", i, err)
311                 }
312                 if !reflect.DeepEqual(have, want) {
313                         t.Errorf("token %d = %#v want %#v", i, have, want)
314                 }
315         }
316 }
317
318 func TestSyntax(t *testing.T) {
319         for i := range xmlInput {
320                 p := NewParser(StringReader(xmlInput[i]))
321                 var err error
322                 for _, err = p.Token(); err == nil; _, err = p.Token() {
323                 }
324                 if _, ok := err.(*SyntaxError); !ok {
325                         t.Fatalf(`xmlInput "%s": expected SyntaxError not received`, xmlInput[i])
326                 }
327         }
328 }
329
330 type allScalars struct {
331         True1     bool
332         True2     bool
333         False1    bool
334         False2    bool
335         Int       int
336         Int8      int8
337         Int16     int16
338         Int32     int32
339         Int64     int64
340         Uint      int
341         Uint8     uint8
342         Uint16    uint16
343         Uint32    uint32
344         Uint64    uint64
345         Uintptr   uintptr
346         Float32   float32
347         Float64   float64
348         String    string
349         PtrString *string
350 }
351
352 var all = allScalars{
353         True1:     true,
354         True2:     true,
355         False1:    false,
356         False2:    false,
357         Int:       1,
358         Int8:      -2,
359         Int16:     3,
360         Int32:     -4,
361         Int64:     5,
362         Uint:      6,
363         Uint8:     7,
364         Uint16:    8,
365         Uint32:    9,
366         Uint64:    10,
367         Uintptr:   11,
368         Float32:   13.0,
369         Float64:   14.0,
370         String:    "15",
371         PtrString: &sixteen,
372 }
373
374 var sixteen = "16"
375
376 const testScalarsInput = `<allscalars>
377         <true1>true</true1>
378         <true2>1</true2>
379         <false1>false</false1>
380         <false2>0</false2>
381         <int>1</int>
382         <int8>-2</int8>
383         <int16>3</int16>
384         <int32>-4</int32>
385         <int64>5</int64>
386         <uint>6</uint>
387         <uint8>7</uint8>
388         <uint16>8</uint16>
389         <uint32>9</uint32>
390         <uint64>10</uint64>
391         <uintptr>11</uintptr>
392         <float>12.0</float>
393         <float32>13.0</float32>
394         <float64>14.0</float64>
395         <string>15</string>
396         <ptrstring>16</ptrstring>
397 </allscalars>`
398
399 func TestAllScalars(t *testing.T) {
400         var a allScalars
401         buf := bytes.NewBufferString(testScalarsInput)
402         err := Unmarshal(buf, &a)
403
404         if err != nil {
405                 t.Fatal(err)
406         }
407         if !reflect.DeepEqual(a, all) {
408                 t.Errorf("have %+v want %+v", a, all)
409         }
410 }
411
412 type item struct {
413         Field_a string
414 }
415
416 func TestIssue569(t *testing.T) {
417         data := `<item><field_a>abcd</field_a></item>`
418         var i item
419         buf := bytes.NewBufferString(data)
420         err := Unmarshal(buf, &i)
421
422         if err != nil || i.Field_a != "abcd" {
423                 t.Fatal("Expecting abcd")
424         }
425 }
426
427 func TestUnquotedAttrs(t *testing.T) {
428         data := "<tag attr=azAZ09:-_\t>"
429         p := NewParser(StringReader(data))
430         p.Strict = false
431         token, err := p.Token()
432         if _, ok := err.(*SyntaxError); ok {
433                 t.Errorf("Unexpected error: %v", err)
434         }
435         if token.(StartElement).Name.Local != "tag" {
436                 t.Errorf("Unexpected tag name: %v", token.(StartElement).Name.Local)
437         }
438         attr := token.(StartElement).Attr[0]
439         if attr.Value != "azAZ09:-_" {
440                 t.Errorf("Unexpected attribute value: %v", attr.Value)
441         }
442         if attr.Name.Local != "attr" {
443                 t.Errorf("Unexpected attribute name: %v", attr.Name.Local)
444         }
445 }
446
447 func TestValuelessAttrs(t *testing.T) {
448         tests := [][3]string{
449                 {"<p nowrap>", "p", "nowrap"},
450                 {"<p nowrap >", "p", "nowrap"},
451                 {"<input checked/>", "input", "checked"},
452                 {"<input checked />", "input", "checked"},
453         }
454         for _, test := range tests {
455                 p := NewParser(StringReader(test[0]))
456                 p.Strict = false
457                 token, err := p.Token()
458                 if _, ok := err.(*SyntaxError); ok {
459                         t.Errorf("Unexpected error: %v", err)
460                 }
461                 if token.(StartElement).Name.Local != test[1] {
462                         t.Errorf("Unexpected tag name: %v", token.(StartElement).Name.Local)
463                 }
464                 attr := token.(StartElement).Attr[0]
465                 if attr.Value != test[2] {
466                         t.Errorf("Unexpected attribute value: %v", attr.Value)
467                 }
468                 if attr.Name.Local != test[2] {
469                         t.Errorf("Unexpected attribute name: %v", attr.Name.Local)
470                 }
471         }
472 }
473
474 func TestCopyTokenCharData(t *testing.T) {
475         data := []byte("same data")
476         var tok1 Token = CharData(data)
477         tok2 := CopyToken(tok1)
478         if !reflect.DeepEqual(tok1, tok2) {
479                 t.Error("CopyToken(CharData) != CharData")
480         }
481         data[1] = 'o'
482         if reflect.DeepEqual(tok1, tok2) {
483                 t.Error("CopyToken(CharData) uses same buffer.")
484         }
485 }
486
487 func TestCopyTokenStartElement(t *testing.T) {
488         elt := StartElement{Name{"", "hello"}, []Attr{{Name{"", "lang"}, "en"}}}
489         var tok1 Token = elt
490         tok2 := CopyToken(tok1)
491         if !reflect.DeepEqual(tok1, tok2) {
492                 t.Error("CopyToken(StartElement) != StartElement")
493         }
494         elt.Attr[0] = Attr{Name{"", "lang"}, "de"}
495         if reflect.DeepEqual(tok1, tok2) {
496                 t.Error("CopyToken(CharData) uses same buffer.")
497         }
498 }
499
500 func TestSyntaxErrorLineNum(t *testing.T) {
501         testInput := "<P>Foo<P>\n\n<P>Bar</>\n"
502         p := NewParser(StringReader(testInput))
503         var err error
504         for _, err = p.Token(); err == nil; _, err = p.Token() {
505         }
506         synerr, ok := err.(*SyntaxError)
507         if !ok {
508                 t.Error("Expected SyntaxError.")
509         }
510         if synerr.Line != 3 {
511                 t.Error("SyntaxError didn't have correct line number.")
512         }
513 }
514
515 func TestTrailingRawToken(t *testing.T) {
516         input := `<FOO></FOO>  `
517         p := NewParser(StringReader(input))
518         var err error
519         for _, err = p.RawToken(); err == nil; _, err = p.RawToken() {
520         }
521         if err != io.EOF {
522                 t.Fatalf("p.RawToken() = _, %v, want _, io.EOF", err)
523         }
524 }
525
526 func TestTrailingToken(t *testing.T) {
527         input := `<FOO></FOO>  `
528         p := NewParser(StringReader(input))
529         var err error
530         for _, err = p.Token(); err == nil; _, err = p.Token() {
531         }
532         if err != io.EOF {
533                 t.Fatalf("p.Token() = _, %v, want _, io.EOF", err)
534         }
535 }
536
537 func TestEntityInsideCDATA(t *testing.T) {
538         input := `<test><![CDATA[ &val=foo ]]></test>`
539         p := NewParser(StringReader(input))
540         var err error
541         for _, err = p.Token(); err == nil; _, err = p.Token() {
542         }
543         if err != io.EOF {
544                 t.Fatalf("p.Token() = _, %v, want _, io.EOF", err)
545         }
546 }
547
548 // The last three tests (respectively one for characters in attribute
549 // names and two for character entities) pass not because of code
550 // changed for issue 1259, but instead pass with the given messages
551 // from other parts of xml.Parser.  I provide these to note the
552 // current behavior of situations where one might think that character
553 // range checking would detect the error, but it does not in fact.
554
555 var characterTests = []struct {
556         in  string
557         err string
558 }{
559         {"\x12<doc/>", "illegal character code U+0012"},
560         {"<?xml version=\"1.0\"?>\x0b<doc/>", "illegal character code U+000B"},
561         {"\xef\xbf\xbe<doc/>", "illegal character code U+FFFE"},
562         {"<?xml version=\"1.0\"?><doc>\r\n<hiya/>\x07<toots/></doc>", "illegal character code U+0007"},
563         {"<?xml version=\"1.0\"?><doc \x12='value'>what's up</doc>", "expected attribute name in element"},
564         {"<doc>&\x01;</doc>", "invalid character entity &;"},
565         {"<doc>&\xef\xbf\xbe;</doc>", "invalid character entity &;"},
566 }
567
568 func TestDisallowedCharacters(t *testing.T) {
569
570         for i, tt := range characterTests {
571                 p := NewParser(StringReader(tt.in))
572                 var err error
573
574                 for err == nil {
575                         _, err = p.Token()
576                 }
577                 synerr, ok := err.(*SyntaxError)
578                 if !ok {
579                         t.Fatalf("input %d p.Token() = _, %v, want _, *SyntaxError", i, err)
580                 }
581                 if synerr.Msg != tt.err {
582                         t.Fatalf("input %d synerr.Msg wrong: want '%s', got '%s'", i, tt.err, synerr.Msg)
583                 }
584         }
585 }
586
587 type procInstEncodingTest struct {
588         expect, got string
589 }
590
591 var procInstTests = []struct {
592         input, expect string
593 }{
594         {`version="1.0" encoding="utf-8"`, "utf-8"},
595         {`version="1.0" encoding='utf-8'`, "utf-8"},
596         {`version="1.0" encoding='utf-8' `, "utf-8"},
597         {`version="1.0" encoding=utf-8`, ""},
598         {`encoding="FOO" `, "FOO"},
599 }
600
601 func TestProcInstEncoding(t *testing.T) {
602         for _, test := range procInstTests {
603                 got := procInstEncoding(test.input)
604                 if got != test.expect {
605                         t.Errorf("procInstEncoding(%q) = %q; want %q", test.input, got, test.expect)
606                 }
607         }
608 }