"
d := NewDecoder(strings.NewReader(data))
d.Strict = false
token, err := d.Token()
if _, ok := err.(*SyntaxError); ok {
t.Errorf("Unexpected error: %v", err)
}
if token.(StartElement).Name.Local != "tag" {
t.Errorf("Unexpected tag name: %v", token.(StartElement).Name.Local)
}
attr := token.(StartElement).Attr[0]
if attr.Value != "azAZ09:-_" {
t.Errorf("Unexpected attribute value: %v", attr.Value)
}
if attr.Name.Local != "attr" {
t.Errorf("Unexpected attribute name: %v", attr.Name.Local)
}
}
func TestValuelessAttrs(t *testing.T) {
tests := [][3]string{
{"", "p", "nowrap"},
{"
", "p", "nowrap"},
{"", "input", "checked"},
{"", "input", "checked"},
}
for _, test := range tests {
d := NewDecoder(strings.NewReader(test[0]))
d.Strict = false
token, err := d.Token()
if _, ok := err.(*SyntaxError); ok {
t.Errorf("Unexpected error: %v", err)
}
if token.(StartElement).Name.Local != test[1] {
t.Errorf("Unexpected tag name: %v", token.(StartElement).Name.Local)
}
attr := token.(StartElement).Attr[0]
if attr.Value != test[2] {
t.Errorf("Unexpected attribute value: %v", attr.Value)
}
if attr.Name.Local != test[2] {
t.Errorf("Unexpected attribute name: %v", attr.Name.Local)
}
}
}
func TestCopyTokenCharData(t *testing.T) {
data := []byte("same data")
var tok1 Token = CharData(data)
tok2 := CopyToken(tok1)
if !reflect.DeepEqual(tok1, tok2) {
t.Error("CopyToken(CharData) != CharData")
}
data[1] = 'o'
if reflect.DeepEqual(tok1, tok2) {
t.Error("CopyToken(CharData) uses same buffer.")
}
}
func TestCopyTokenStartElement(t *testing.T) {
elt := StartElement{Name{"", "hello"}, []Attr{{Name{"", "lang"}, "en"}}}
var tok1 Token = elt
tok2 := CopyToken(tok1)
if tok1.(StartElement).Attr[0].Value != "en" {
t.Error("CopyToken overwrote Attr[0]")
}
if !reflect.DeepEqual(tok1, tok2) {
t.Error("CopyToken(StartElement) != StartElement")
}
tok1.(StartElement).Attr[0] = Attr{Name{"", "lang"}, "de"}
if reflect.DeepEqual(tok1, tok2) {
t.Error("CopyToken(CharData) uses same buffer.")
}
}
func TestSyntaxErrorLineNum(t *testing.T) {
testInput := "
Foo
\n\n
Bar>\n"
d := NewDecoder(strings.NewReader(testInput))
var err error
for _, err = d.Token(); err == nil; _, err = d.Token() {
}
synerr, ok := err.(*SyntaxError)
if !ok {
t.Error("Expected SyntaxError.")
}
if synerr.Line != 3 {
t.Error("SyntaxError didn't have correct line number.")
}
}
func TestTrailingRawToken(t *testing.T) {
input := ` `
d := NewDecoder(strings.NewReader(input))
var err error
for _, err = d.RawToken(); err == nil; _, err = d.RawToken() {
}
if err != io.EOF {
t.Fatalf("d.RawToken() = _, %v, want _, io.EOF", err)
}
}
func TestTrailingToken(t *testing.T) {
input := ` `
d := NewDecoder(strings.NewReader(input))
var err error
for _, err = d.Token(); err == nil; _, err = d.Token() {
}
if err != io.EOF {
t.Fatalf("d.Token() = _, %v, want _, io.EOF", err)
}
}
func TestEntityInsideCDATA(t *testing.T) {
input := ``
d := NewDecoder(strings.NewReader(input))
var err error
for _, err = d.Token(); err == nil; _, err = d.Token() {
}
if err != io.EOF {
t.Fatalf("d.Token() = _, %v, want _, io.EOF", err)
}
}
var characterTests = []struct {
in string
err string
}{
{"\x12", "illegal character code U+0012"},
{"\x0b", "illegal character code U+000B"},
{"\xef\xbf\xbe", "illegal character code U+FFFE"},
{"\r\n\x07", "illegal character code U+0007"},
{"what's up", "expected attribute name in element"},
{"&abc\x01;", "invalid character entity &abc (no semicolon)"},
{"&\x01;", "invalid character entity & (no semicolon)"},
{"&\xef\xbf\xbe;", "invalid character entity &\uFFFE;"},
{"&hello;", "invalid character entity &hello;"},
}
func TestDisallowedCharacters(t *testing.T) {
for i, tt := range characterTests {
d := NewDecoder(strings.NewReader(tt.in))
var err error
for err == nil {
_, err = d.Token()
}
synerr, ok := err.(*SyntaxError)
if !ok {
t.Fatalf("input %d d.Token() = _, %v, want _, *SyntaxError", i, err)
}
if synerr.Msg != tt.err {
t.Fatalf("input %d synerr.Msg wrong: want %q, got %q", i, tt.err, synerr.Msg)
}
}
}
func TestIsInCharacterRange(t *testing.T) {
invalid := []rune{
utf8.MaxRune + 1,
0xD800, // surrogate min
0xDFFF, // surrogate max
-1,
}
for _, r := range invalid {
if isInCharacterRange(r) {
t.Errorf("rune %U considered valid", r)
}
}
}
var procInstTests = []struct {
input string
expect [2]string
}{
{`version="1.0" encoding="utf-8"`, [2]string{"1.0", "utf-8"}},
{`version="1.0" encoding='utf-8'`, [2]string{"1.0", "utf-8"}},
{`version="1.0" encoding='utf-8' `, [2]string{"1.0", "utf-8"}},
{`version="1.0" encoding=utf-8`, [2]string{"1.0", ""}},
{`encoding="FOO" `, [2]string{"", "FOO"}},
}
func TestProcInstEncoding(t *testing.T) {
for _, test := range procInstTests {
if got := procInst("version", test.input); got != test.expect[0] {
t.Errorf("procInst(version, %q) = %q; want %q", test.input, got, test.expect[0])
}
if got := procInst("encoding", test.input); got != test.expect[1] {
t.Errorf("procInst(encoding, %q) = %q; want %q", test.input, got, test.expect[1])
}
}
}
// Ensure that directives with comments include the complete
// text of any nested directives.
var directivesWithCommentsInput = `
]>
]>
--> --> []>
`
var directivesWithCommentsTokens = []Token{
CharData("\n"),
Directive(`DOCTYPE []`),
CharData("\n"),
Directive(`DOCTYPE []`),
CharData("\n"),
Directive(`DOCTYPE []`),
CharData("\n"),
}
func TestDirectivesWithComments(t *testing.T) {
d := NewDecoder(strings.NewReader(directivesWithCommentsInput))
for i, want := range directivesWithCommentsTokens {
have, err := d.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)
}
}
}
// Writer whose Write method always returns an error.
type errWriter struct{}
func (errWriter) Write(p []byte) (n int, err error) { return 0, fmt.Errorf("unwritable") }
func TestEscapeTextIOErrors(t *testing.T) {
expectErr := "unwritable"
err := EscapeText(errWriter{}, []byte{'A'})
if err == nil || err.Error() != expectErr {
t.Errorf("have %v, want %v", err, expectErr)
}
}
func TestEscapeTextInvalidChar(t *testing.T) {
input := []byte("A \x00 terminated string.")
expected := "A \uFFFD terminated string."
buff := new(bytes.Buffer)
if err := EscapeText(buff, input); err != nil {
t.Fatalf("have %v, want nil", err)
}
text := buff.String()
if text != expected {
t.Errorf("have %v, want %v", text, expected)
}
}
func TestIssue5880(t *testing.T) {
type T []byte
data, err := Marshal(T{192, 168, 0, 1})
if err != nil {
t.Errorf("Marshal error: %v", err)
}
if !utf8.Valid(data) {
t.Errorf("Marshal generated invalid UTF-8: %x", data)
}
}
func TestIssue11405(t *testing.T) {
testCases := []string{
"",
"",
"",
}
for _, tc := range testCases {
d := NewDecoder(strings.NewReader(tc))
var err error
for {
_, err = d.Token()
if err != nil {
break
}
}
if _, ok := err.(*SyntaxError); !ok {
t.Errorf("%s: Token: Got error %v, want SyntaxError", tc, err)
}
}
}
func TestIssue12417(t *testing.T) {
testCases := []struct {
s string
ok bool
}{
{``, true},
{``, true},
{``, true},
{``, false},
}
for _, tc := range testCases {
d := NewDecoder(strings.NewReader(tc.s))
var err error
for {
_, err = d.Token()
if err != nil {
if err == io.EOF {
err = nil
}
break
}
}
if err != nil && tc.ok {
t.Errorf("%q: Encoding charset: expected no error, got %s", tc.s, err)
continue
}
if err == nil && !tc.ok {
t.Errorf("%q: Encoding charset: expected error, got nil", tc.s)
}
}
}
func tokenMap(mapping func(t Token) Token) func(TokenReader) TokenReader {
return func(src TokenReader) TokenReader {
return mapper{
t: src,
f: mapping,
}
}
}
type mapper struct {
t TokenReader
f func(Token) Token
}
func (m mapper) Token() (Token, error) {
tok, err := m.t.Token()
if err != nil {
return nil, err
}
return m.f(tok), nil
}
func TestNewTokenDecoderIdempotent(t *testing.T) {
d := NewDecoder(strings.NewReader(`
`))
d2 := NewTokenDecoder(d)
if d != d2 {
t.Error("NewTokenDecoder did not detect underlying Decoder")
}
}
func TestWrapDecoder(t *testing.T) {
d := NewDecoder(strings.NewReader(`[Re-enter Clown with a letter, and FABIAN]
`))
m := tokenMap(func(t Token) Token {
switch tok := t.(type) {
case StartElement:
if tok.Name.Local == "quote" {
tok.Name.Local = "blocking"
return tok
}
case EndElement:
if tok.Name.Local == "quote" {
tok.Name.Local = "blocking"
return tok
}
}
return t
})
d = NewTokenDecoder(m(d))
o := struct {
XMLName Name `xml:"blocking"`
Chardata string `xml:",chardata"`
}{}
if err := d.Decode(&o); err != nil {
t.Fatal("Got unexpected error while decoding:", err)
}
if o.Chardata != "[Re-enter Clown with a letter, and FABIAN]" {
t.Fatalf("Got unexpected chardata: `%s`\n", o.Chardata)
}
}
type tokReader struct{}
func (tokReader) Token() (Token, error) {
return StartElement{}, nil
}
type Failure struct{}
func (Failure) UnmarshalXML(*Decoder, StartElement) error {
return nil
}
func TestTokenUnmarshaler(t *testing.T) {
defer func() {
if r := recover(); r != nil {
t.Error("Unexpected panic using custom token unmarshaler")
}
}()
d := NewTokenDecoder(tokReader{})
d.Decode(&Failure{})
}