| // Copyright 2009 The Go Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style | |
| // license that can be found in the LICENSE file. | |
| package xml | |
| import ( | |
| "io"; | |
| "os"; | |
| "reflect"; | |
| "strings"; | |
| "testing"; | |
| ) | |
| const testInput = ` | |
| <?xml version="1.0" encoding="UTF-8"?> | |
| <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" | |
| "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> | |
| <body xmlns:foo="ns1" xmlns="ns2" xmlns:tag="ns3" ` | |
| "\r\n\t" ` > | |
| <hello lang="en">World <>'" 白鵬翔</hello> | |
| <goodbye /> | |
| <outer foo:attr="value" xmlns:tag="ns4"> | |
| <inner/> | |
| </outer> | |
| <tag:name> | |
| <![CDATA[Some text here.]]> | |
| </tag:name> | |
| </body><!-- missing final newline -->` | |
| var rawTokens = []Token{ | |
| CharData(strings.Bytes("\n")), | |
| ProcInst{"xml", strings.Bytes(`version="1.0" encoding="UTF-8"`)}, | |
| CharData(strings.Bytes("\n")), | |
| Directive(strings.Bytes(`DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" | |
| "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"`)), | |
| CharData(strings.Bytes("\n")), | |
| StartElement{Name{"", "body"}, []Attr{Attr{Name{"xmlns", "foo"}, "ns1"}, Attr{Name{"", "xmlns"}, "ns2"}, Attr{Name{"xmlns", "tag"}, "ns3"}}}, | |
| CharData(strings.Bytes("\n ")), | |
| StartElement{Name{"", "hello"}, []Attr{Attr{Name{"", "lang"}, "en"}}}, | |
| CharData(strings.Bytes("World <>'\" 白鵬翔")), | |
| EndElement{Name{"", "hello"}}, | |
| CharData(strings.Bytes("\n ")), | |
| StartElement{Name{"", "goodbye"}, nil}, | |
| EndElement{Name{"", "goodbye"}}, | |
| CharData(strings.Bytes("\n ")), | |
| StartElement{Name{"", "outer"}, []Attr{Attr{Name{"foo", "attr"}, "value"}, Attr{Name{"xmlns", "tag"}, "ns4"}}}, | |
| CharData(strings.Bytes("\n ")), | |
| StartElement{Name{"", "inner"}, nil}, | |
| EndElement{Name{"", "inner"}}, | |
| CharData(strings.Bytes("\n ")), | |
| EndElement{Name{"", "outer"}}, | |
| CharData(strings.Bytes("\n ")), | |
| StartElement{Name{"tag", "name"}, nil}, | |
| CharData(strings.Bytes("\n ")), | |
| CharData(strings.Bytes("Some text here.")), | |
| CharData(strings.Bytes("\n ")), | |
| EndElement{Name{"tag", "name"}}, | |
| CharData(strings.Bytes("\n")), | |
| EndElement{Name{"", "body"}}, | |
| Comment(strings.Bytes(" missing final newline ")), | |
| } | |
| var cookedTokens = []Token{ | |
| CharData(strings.Bytes("\n")), | |
| ProcInst{"xml", strings.Bytes(`version="1.0" encoding="UTF-8"`)}, | |
| CharData(strings.Bytes("\n")), | |
| Directive(strings.Bytes(`DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" | |
| "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"`)), | |
| CharData(strings.Bytes("\n")), | |
| StartElement{Name{"ns2", "body"}, []Attr{Attr{Name{"xmlns", "foo"}, "ns1"}, Attr{Name{"", "xmlns"}, "ns2"}, Attr{Name{"xmlns", "tag"}, "ns3"}}}, | |
| CharData(strings.Bytes("\n ")), | |
| StartElement{Name{"ns2", "hello"}, []Attr{Attr{Name{"", "lang"}, "en"}}}, | |
| CharData(strings.Bytes("World <>'\" 白鵬翔")), | |
| EndElement{Name{"ns2", "hello"}}, | |
| CharData(strings.Bytes("\n ")), | |
| StartElement{Name{"ns2", "goodbye"}, nil}, | |
| EndElement{Name{"ns2", "goodbye"}}, | |
| CharData(strings.Bytes("\n ")), | |
| StartElement{Name{"ns2", "outer"}, []Attr{Attr{Name{"ns1", "attr"}, "value"}, Attr{Name{"xmlns", "tag"}, "ns4"}}}, | |
| CharData(strings.Bytes("\n ")), | |
| StartElement{Name{"ns2", "inner"}, nil}, | |
| EndElement{Name{"ns2", "inner"}}, | |
| CharData(strings.Bytes("\n ")), | |
| EndElement{Name{"ns2", "outer"}}, | |
| CharData(strings.Bytes("\n ")), | |
| StartElement{Name{"ns3", "name"}, nil}, | |
| CharData(strings.Bytes("\n ")), | |
| CharData(strings.Bytes("Some text here.")), | |
| CharData(strings.Bytes("\n ")), | |
| EndElement{Name{"ns3", "name"}}, | |
| CharData(strings.Bytes("\n")), | |
| EndElement{Name{"ns2", "body"}}, | |
| Comment(strings.Bytes(" missing final newline ")), | |
| } | |
| type stringReader struct { | |
| s string; | |
| off int; | |
| } | |
| func (r *stringReader) Read(b []byte) (n int, err os.Error) { | |
| if r.off >= len(r.s) { | |
| return 0, os.EOF | |
| } | |
| for r.off < len(r.s) && n < len(b) { | |
| b[n] = r.s[r.off]; | |
| n++; | |
| r.off++; | |
| } | |
| return; | |
| } | |
| func (r *stringReader) ReadByte() (b byte, err os.Error) { | |
| if r.off >= len(r.s) { | |
| return 0, os.EOF | |
| } | |
| b = r.s[r.off]; | |
| r.off++; | |
| return; | |
| } | |
| func StringReader(s string) io.Reader { return &stringReader{s, 0} } | |
| func TestRawToken(t *testing.T) { | |
| p := NewParser(StringReader(testInput)); | |
| for i, want := range rawTokens { | |
| have, err := p.RawToken(); | |
| if err != nil { | |
| t.Fatalf("token %d: unexpected error: %s", i, err) | |
| } | |
| if !reflect.DeepEqual(have, want) { | |
| t.Errorf("token %d = %#v want %#v", i, have, want) | |
| } | |
| } | |
| } | |
| func TestToken(t *testing.T) { | |
| p := NewParser(StringReader(testInput)); | |
| for i, want := range cookedTokens { | |
| have, err := p.Token(); | |
| if err != nil { | |
| t.Fatalf("token %d: unexpected error: %s", i, err) | |
| } | |
| if !reflect.DeepEqual(have, want) { | |
| t.Errorf("token %d = %#v want %#v", i, have, want) | |
| } | |
| } | |
| } |