OSDN Git Service

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