136 lines
6.6 KiB
Go
136 lines
6.6 KiB
Go
package parse
|
||
|
||
import (
|
||
"fmt"
|
||
"testing"
|
||
|
||
"git.makaay.nl/mauricem/go-parsekit/parse"
|
||
)
|
||
|
||
func TestStartString(t *testing.T) {
|
||
parser := newParser()
|
||
wrapper := func(p *parse.API) { parser.parseString(p) }
|
||
testParse(t, parser, wrapper, parseTest{"(not a string)", "{}", "unexpected input (expected a string value) at start of file"})
|
||
}
|
||
|
||
func TestStartBasicString(t *testing.T) {
|
||
parser := newParser()
|
||
wrapper := func(p *parse.API) { parser.parseBasicString("xyz", p) }
|
||
testParse(t, parser, wrapper, parseTest{"(not a string)", "{}", "unexpected input (expected opening quotation marks) at start of file"})
|
||
}
|
||
|
||
func TestStartLiteralString(t *testing.T) {
|
||
parser := newParser()
|
||
wrapper := func(p *parse.API) { parser.parseLiteralString("xyz", p) }
|
||
testParse(t, parser, wrapper, parseTest{"(not a string)", "{}", "unexpected input (expected opening single quote) at start of file"})
|
||
}
|
||
|
||
func TestStartMultiLineBasicString(t *testing.T) {
|
||
parser := newParser()
|
||
wrapper := func(p *parse.API) { parser.parseMultiLineBasicString(p) }
|
||
testParse(t, parser, wrapper, parseTest{"(not a string)", "{}", "unexpected input (expected opening three quotation marks) at start of file"})
|
||
}
|
||
|
||
func TestStartMultiLineLiteralString(t *testing.T) {
|
||
parser := newParser()
|
||
wrapper := func(p *parse.API) { parser.parseMultiLineLiteralString(p) }
|
||
testParse(t, parser, wrapper, parseTest{"(not a string)", "{}", "unexpected input (expected opening three single quotes) at start of file"})
|
||
}
|
||
|
||
func TestString(t *testing.T) {
|
||
for _, test := range []parseTest{
|
||
{`x=no start quote"`, `{}`, `unexpected input (expected a value) at line 1, column 3`},
|
||
{`x="basic s\tring"`, `{"x": "basic s\tring"}`, ``},
|
||
{"x=\"\"\"\n basic multi-line\n string value\n\"\"\"", `{"x": " basic multi-line\n string value\n"}`, ``},
|
||
{`x='literal s\tring'`, `{"x": "literal s\\tring"}`, ``},
|
||
{"x='''\n literal multi-line\n string value\n'''", `{"x": " literal multi-line\n string value\n"}`, ``},
|
||
} {
|
||
p := newParser()
|
||
testParse(t, p, p.startDocument, test)
|
||
}
|
||
}
|
||
|
||
func TestBasicString(t *testing.T) {
|
||
for _, test := range []parseTest{
|
||
{`x="no end quote`, `{}`, `unexpected end of file (expected closing quotation marks) at line 1, column 16`},
|
||
{`x=""`, `{"x": ""}`, ``},
|
||
{`x="simple string"`, `{"x": "simple string"}`, ``},
|
||
{`x="with\tsome\r\nvalid escapes\b"`, `{"x": "with\tsome\r\nvalid escapes\b"}`, ``},
|
||
{`x="with an \invalid escape"`, `{}`, `invalid escape sequence at line 1, column 12`},
|
||
{`x="A cool UTF8 ƃuıɹʇs"`, `{"x": "A cool UTF8 ƃuıɹʇs"}`, ``},
|
||
{`x="A string with UTF8 escape \u2318"`, `{"x": "A string with UTF8 escape ⌘"}`, ``},
|
||
{"x=\"Invalid character for UTF \xcd\"", `{}`, `invalid UTF8 rune at line 1, column 30`},
|
||
{`x="\uD801 is not a valid rune"`, `{}`, `invalid UTF8 escape '\uD801' at line 1, column 10`},
|
||
{`x="\U00D80000 is not a valid rune"`, `{}`, `invalid UTF8 escape '\U00D80000' at line 1, column 14`},
|
||
{"x=\"Character that mus\t be escaped\"", `{}`, `invalid character in string value: '\t' (must be escaped) at line 1, column 22`},
|
||
{"x=\"Character that must be escaped \u0000\"", `{}`, `invalid character in string value: '\x00' (must be escaped) at line 1, column 35`},
|
||
{"x=\"Character that must be escaped \x7f\"", `{}`, `invalid character in string value: '\u007f' (must be escaped) at line 1, column 35`},
|
||
{`x="\b\t\n\f\r\"\\\u2318\U00002318" # all escape codes`, `{"x": "\b\t\n\f\r\"\\⌘⌘"}`, ``},
|
||
} {
|
||
p := newParser()
|
||
testParse(t, p, p.startDocument, test)
|
||
}
|
||
}
|
||
|
||
func TestMultiLineBasicString(t *testing.T) {
|
||
for _, test := range []parseTest{
|
||
{`x="""missing close quote""`, `{}`, `unexpected end of file (expected closing three quotation marks) at line 1, column 27`},
|
||
{`x=""""""`, `{"x": ""}`, ``},
|
||
{"x=\"\"\"\n\"\"\"", `{"x": ""}`, ``},
|
||
{"x=\"\"\"\r\n\r\n\"\"\"", `{"x": "\n"}`, ``},
|
||
{`x="""\"\"\"\""""`, `{"x": "\"\"\"\""}`, ``},
|
||
{"x=\"\"\"\nThe quick brown \\\n\n\n \t fox jumps over \\\n\t the lazy dog.\\\n \"\"\"", `{"x": "The quick brown fox jumps over the lazy dog."}`, ``},
|
||
{"x=\"\"\"No control chars \f allowed\"\"\"", `{}`, `invalid character in multi-line basic string: '\f' (must be escaped) at line 1, column 23`},
|
||
{"x=\"\"\"Escaping control chars\\nis valid\"\"\"", `{"x": "Escaping control chars\nis valid"}`, ``},
|
||
{"x=\"\"\"Invalid escaping \\is not allowed\"\"\"", `{}`, `invalid escape sequence at line 1, column 23`},
|
||
{"x=\"\"\"Invalid rune \xcd\"\"\"", `{}`, `invalid UTF8 rune at line 1, column 19`},
|
||
} {
|
||
p := newParser()
|
||
testParse(t, p, p.startDocument, test)
|
||
}
|
||
}
|
||
|
||
func TestLiteralString(t *testing.T) {
|
||
for _, test := range []parseTest{
|
||
{`x='missing close quote`, `{}`, `unexpected end of file (expected closing single quote) at line 1, column 23`},
|
||
{`x=''`, `{"x": ""}`, ``},
|
||
{`x='simple'`, `{"x": "simple"}`, ``},
|
||
{`x='C:\Users\nodejs\templates'`, `{"x": "C:\\Users\\nodejs\\templates"}`, ``},
|
||
{`x='\\ServerX\admin$\system32\'`, `{"x": "\\\\ServerX\\admin$\\system32\\"}`, ``},
|
||
{`x='Tom "Dubs" Preston-Werner'`, `{"x": "Tom \"Dubs\" Preston-Werner"}`, ``},
|
||
{`x='<\i\c*\s*>'`, `{"x": "<\\i\\c*\\s*>"}`, ``},
|
||
{"x='No cont\rol chars allowed'", `{}`, `invalid character in string value: '\r' (no control chars allowed, except for tab) at line 1, column 11`},
|
||
{"x='Except\tfor\ttabs'", `{"x": "Except\tfor\ttabs"}`, ``},
|
||
{"x='Invalid rune \xcd'", `{}`, `invalid UTF8 rune at line 1, column 17`},
|
||
} {
|
||
p := newParser()
|
||
testParse(t, p, p.startDocument, test)
|
||
}
|
||
}
|
||
|
||
func TestMultiLineLiteralString(t *testing.T) {
|
||
for _, test := range []parseTest{
|
||
{`x='''missing close quote''`, `{}`, `unexpected end of file (expected closing three single quotes) at line 1, column 27`},
|
||
{`x=''''''`, `{"x": ""}`, ``},
|
||
{"x='''\n'''", `{"x": ""}`, ``},
|
||
{`x='''I [dw]on't need \d{2} apples'''`, `{"x": "I [dw]on't need \\d{2} apples"}`, ``},
|
||
{"x='''\nThere can\nbe newlines\r\nand \ttabs!\r\n'''", `{"x": "There can\nbe newlines\nand \ttabs!\n"}`, ``},
|
||
{"x='''No other \f control characters'''", `{}`, `invalid character in literal string: '\f' (no control chars allowed, except for tab and newline) at line 1, column 15`},
|
||
{"x='''No invalid runes allowed \xcd'''", `{}`, `invalid UTF8 rune at line 1, column 31`},
|
||
} {
|
||
p := newParser()
|
||
testParse(t, p, p.startDocument, test)
|
||
}
|
||
}
|
||
|
||
func TestBasicStringWithUnescapedControlCharacters(t *testing.T) {
|
||
// A quick check for almost all characters that must be escaped.
|
||
// The missing one (\x7f) is covered in the previous test.
|
||
for i := 0x00; i <= 0x1F; i++ {
|
||
p := newParser()
|
||
input := fmt.Sprintf(`x="%c"`, rune(i))
|
||
expected := fmt.Sprintf(`invalid character in string value: %q (must be escaped) at line 1, column 4`, rune(i))
|
||
testParse(t, p, p.startDocument, parseTest{input, "{}", expected})
|
||
}
|
||
}
|