mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
encoding/xml: improve the test coverage, fix minor bugs
Improve the test coverage of encoding/xml package by adding the test cases for the execution paths that were not covered before. Since it reveals a couple of issues, fix them as well while we're at it. As I used an `strings.EqualFold` instead of adding one more `strings.ToLower`, our fix to `autoClose()` tends to run faster as well as a result. name old time/op new time/op delta HTMLAutoClose-8 5.93µs ± 2% 5.75µs ± 3% -3.16% (p=0.000 n=10+10) name old alloc/op new alloc/op delta HTMLAutoClose-8 2.60kB ± 0% 2.58kB ± 0% -0.46% (p=0.000 n=10+10) name old allocs/op new allocs/op delta HTMLAutoClose-8 72.0 ± 0% 67.0 ± 0% -6.94% (p=0.000 n=10+10) The overall `encoding/xml` test coverage increase is `88.1% -> 89.9%`; although it may look insignificant, this CL covers some important corner cases, like `autoClose()` functionality (that was not tested at all). Fixes #49635 Fixes #49636 Change-Id: I50b2769896c197eb285672313b7148f4fe8bdb38 Reviewed-on: https://go-review.googlesource.com/c/go/+/364734 Trust: Bryan Mills <bcmills@google.com> Reviewed-by: Daniel Martí <mvdan@mvdan.cc> Trust: Daniel Martí <mvdan@mvdan.cc> Run-TryBot: Daniel Martí <mvdan@mvdan.cc> TryBot-Result: Gopher Robot <gobot@golang.org>
This commit is contained in:
parent
2b8aa2b734
commit
e79c39f004
2 changed files with 168 additions and 7 deletions
|
|
@ -673,6 +673,19 @@ func TestCopyTokenStartElement(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestCopyTokenComment(t *testing.T) {
|
||||
data := []byte("<!-- some comment -->")
|
||||
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 := "<P>Foo<P>\n\n<P>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 `<?xml version="1.0" encoding="UTF-8"?>` + s
|
||||
}
|
||||
tests := []struct {
|
||||
src string
|
||||
err string
|
||||
}{
|
||||
{withDefaultHeader(`</foo>`), `unexpected end element </foo>`},
|
||||
{withDefaultHeader(`<x:foo></y:foo>`), `element <foo> in space x closed by </foo> in space y`},
|
||||
{withDefaultHeader(`<? not ok ?>`), `expected target name after <?`},
|
||||
{withDefaultHeader(`<!- not ok -->`), `invalid sequence <!- not part of <!--`},
|
||||
{withDefaultHeader(`<!-? not ok -->`), `invalid sequence <!- not part of <!--`},
|
||||
{withDefaultHeader(`<![not ok]>`), `invalid <![ sequence`},
|
||||
{withDefaultHeader("\xf1"), `invalid UTF-8`},
|
||||
|
||||
// Header-related errors.
|
||||
{`<?xml version="1.1" encoding="UTF-8"?>`, `unsupported version "1.1"; only version 1.0 is supported`},
|
||||
|
||||
// Cases below are for "no errors".
|
||||
{withDefaultHeader(`<?ok?>`), ``},
|
||||
{withDefaultHeader(`<?ok version="ok"?>`), ``},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
d := NewDecoder(strings.NewReader(test.src))
|
||||
var err error
|
||||
for {
|
||||
_, err = d.Token()
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
if test.err == "" {
|
||||
if err != io.EOF {
|
||||
t.Errorf("parse %s: have %q error, expected none", test.src, err)
|
||||
}
|
||||
continue
|
||||
}
|
||||
if err == nil || err == io.EOF {
|
||||
t.Errorf("parse %s: have no error, expected a non-nil error", test.src)
|
||||
continue
|
||||
}
|
||||
if !strings.Contains(err.Error(), test.err) {
|
||||
t.Errorf("parse %s: can't find %q error sudbstring\nerror: %q", test.src, test.err, err)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const testInputHTMLAutoClose = `<?xml version="1.0" encoding="UTF-8"?>
|
||||
<br>
|
||||
<br/><br/>
|
||||
<br><br>
|
||||
<br></br>
|
||||
<BR>
|
||||
<BR/><BR/>
|
||||
<Br></Br>
|
||||
<BR><span id="test">abc</span><br/><br/>`
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue