diff --git a/src/encoding/xml/xml.go b/src/encoding/xml/xml.go index 8a0a9c253a..ef51252dcb 100644 --- a/src/encoding/xml/xml.go +++ b/src/encoding/xml/xml.go @@ -10,9 +10,6 @@ package xml // Annotated XML spec: https://www.xml.com/axml/testaxml.htm // XML name spaces: https://www.w3.org/TR/REC-xml-names/ -// TODO(rsc): -// Test error handling. - import ( "bufio" "bytes" @@ -499,7 +496,7 @@ func (d *Decoder) popElement(t *EndElement) bool { return false case s.name.Space != name.Space: d.err = d.syntaxError("element <" + s.name.Local + "> in space " + s.name.Space + - "closed by " + name.Local + "> in space " + name.Space) + " closed by " + name.Local + "> in space " + name.Space) return false } @@ -523,12 +520,11 @@ func (d *Decoder) autoClose(t Token) (Token, bool) { if d.stk == nil || d.stk.kind != stkStart { return nil, false } - name := strings.ToLower(d.stk.name.Local) for _, s := range d.AutoClose { - if strings.ToLower(s) == name { + if strings.EqualFold(s, d.stk.name.Local) { // This one should be auto closed if t doesn't close it. et, ok := t.(EndElement) - if !ok || et.Name.Local != name { + if !ok || !strings.EqualFold(et.Name.Local, d.stk.name.Local) { return EndElement{d.stk.name}, true } break diff --git a/src/encoding/xml/xml_test.go b/src/encoding/xml/xml_test.go index 19152dbdb6..ab1dbf849b 100644 --- a/src/encoding/xml/xml_test.go +++ b/src/encoding/xml/xml_test.go @@ -673,6 +673,19 @@ func TestCopyTokenStartElement(t *testing.T) { } } +func TestCopyTokenComment(t *testing.T) { + data := []byte("") + var tok1 Token = Comment(data) + tok2 := CopyToken(tok1) + if !reflect.DeepEqual(tok1, tok2) { + t.Error("CopyToken(Comment) != Comment") + } + data[1] = 'o' + if reflect.DeepEqual(tok1, tok2) { + t.Error("CopyToken(Comment) uses same buffer.") + } +} + func TestSyntaxErrorLineNum(t *testing.T) { testInput := "
Foo
\n\n
Bar>\n"
d := NewDecoder(strings.NewReader(testInput))
@@ -1060,3 +1073,155 @@ func TestRoundTrip(t *testing.T) {
t.Run(name, func(t *testing.T) { testRoundTrip(t, input) })
}
}
+
+func TestParseErrors(t *testing.T) {
+ withDefaultHeader := func(s string) string {
+ return `` + s
+ }
+ tests := []struct {
+ src string
+ err string
+ }{
+ {withDefaultHeader(``), `unexpected end element `},
+ {withDefaultHeader(`
+
+
+
+
+
+
+
abc
`
+
+func BenchmarkHTMLAutoClose(b *testing.B) {
+ b.RunParallel(func(p *testing.PB) {
+ for p.Next() {
+ d := NewDecoder(strings.NewReader(testInputHTMLAutoClose))
+ d.Strict = false
+ d.AutoClose = HTMLAutoClose
+ d.Entity = HTMLEntity
+ for {
+ _, err := d.Token()
+ if err != nil {
+ if err == io.EOF {
+ break
+ }
+ b.Fatalf("unexpected error: %v", err)
+ }
+ }
+ }
+ })
+}
+
+func TestHTMLAutoClose(t *testing.T) {
+ wantTokens := []Token{
+ ProcInst{"xml", []byte(`version="1.0" encoding="UTF-8"`)},
+ CharData("\n"),
+ StartElement{Name{"", "br"}, []Attr{}},
+ EndElement{Name{"", "br"}},
+ CharData("\n"),
+ StartElement{Name{"", "br"}, []Attr{}},
+ EndElement{Name{"", "br"}},
+ StartElement{Name{"", "br"}, []Attr{}},
+ EndElement{Name{"", "br"}},
+ CharData("\n"),
+ StartElement{Name{"", "br"}, []Attr{}},
+ EndElement{Name{"", "br"}},
+ StartElement{Name{"", "br"}, []Attr{}},
+ EndElement{Name{"", "br"}},
+ CharData("\n"),
+ StartElement{Name{"", "br"}, []Attr{}},
+ EndElement{Name{"", "br"}},
+ CharData("\n"),
+ StartElement{Name{"", "BR"}, []Attr{}},
+ EndElement{Name{"", "BR"}},
+ CharData("\n"),
+ StartElement{Name{"", "BR"}, []Attr{}},
+ EndElement{Name{"", "BR"}},
+ StartElement{Name{"", "BR"}, []Attr{}},
+ EndElement{Name{"", "BR"}},
+ CharData("\n"),
+ StartElement{Name{"", "Br"}, []Attr{}},
+ EndElement{Name{"", "Br"}},
+ CharData("\n"),
+ StartElement{Name{"", "BR"}, []Attr{}},
+ EndElement{Name{"", "BR"}},
+ StartElement{Name{"", "span"}, []Attr{{Name: Name{"", "id"}, Value: "test"}}},
+ CharData("abc"),
+ EndElement{Name{"", "span"}},
+ StartElement{Name{"", "br"}, []Attr{}},
+ EndElement{Name{"", "br"}},
+ StartElement{Name{"", "br"}, []Attr{}},
+ EndElement{Name{"", "br"}},
+ }
+
+ d := NewDecoder(strings.NewReader(testInputHTMLAutoClose))
+ d.Strict = false
+ d.AutoClose = HTMLAutoClose
+ d.Entity = HTMLEntity
+ var haveTokens []Token
+ for {
+ tok, err := d.Token()
+ if err != nil {
+ if err == io.EOF {
+ break
+ }
+ t.Fatalf("unexpected error: %v", err)
+ }
+ haveTokens = append(haveTokens, CopyToken(tok))
+ }
+ if len(haveTokens) != len(wantTokens) {
+ t.Errorf("tokens count mismatch: have %d, want %d", len(haveTokens), len(wantTokens))
+ }
+ for i, want := range wantTokens {
+ if i >= len(haveTokens) {
+ t.Errorf("token[%d] expected %#v, have no token", i, want)
+ } else {
+ have := haveTokens[i]
+ if !reflect.DeepEqual(have, want) {
+ t.Errorf("token[%d] mismatch:\nhave: %#v\nwant: %#v", i, have, want)
+ }
+ }
+ }
+}