package parser import ( "fmt" "testing" ) func TestString(t *testing.T) { for _, test := range []parseTest{ {``, []string{`Error: unexpected end of file (expected a string value) at start of file`}}, {`no start quote"`, []string{`Error: unexpected input (expected a string value) at start of file`}}, {`"basic s\tring"`, []string{`string("basic s\tring")`}}, {"\"\"\"\n basic multi-line\n string value\n\"\"\"", []string{`string(" basic multi-line\n string value\n")`}}, {`'literal s\tring'`, []string{`string("literal s\\tring")`}}, {"'''\n literal multi-line\n string value\n'''", []string{`string(" literal multi-line\n string value\n")`}}, } { p := &parser{} testParseHandler(t, p, p.startString, test) } } func TestBasicString(t *testing.T) { for _, test := range []parseTest{ {``, []string{`Error: unexpected end of file (expected opening quotation marks) at start of file`}}, {`no start quote"`, []string{`Error: unexpected input (expected opening quotation marks) at start of file`}}, {`"no end quote`, []string{`Error: unexpected end of file (expected closing quotation marks) at line 1, column 14`}}, {`""`, []string{`string("")`}}, {`"simple string"`, []string{`string("simple string")`}}, {`"with\tsome\r\nvalid escapes\b"`, []string{`string("with\tsome\r\nvalid escapes\b")`}}, {`"with an \invalid escape"`, []string{`Error: invalid escape sequence at line 1, column 10`}}, {`"A cool UTF8 ƃuıɹʇs"`, []string{`string("A cool UTF8 ƃuıɹʇs")`}}, {`"A string with UTF8 escape \u2318"`, []string{`string("A string with UTF8 escape ⌘")`}}, {"\"Invalid character for UTF \xcd\"", []string{`Error: invalid UTF8 rune at line 1, column 28`}}, {"\"Character that mus\t be escaped\"", []string{`Error: invalid character in basic string: '\t' (must be escaped) at line 1, column 20`}}, {"\"Character that must be escaped \u0000\"", []string{`Error: invalid character in basic string: '\x00' (must be escaped) at line 1, column 33`}}, {"\"Character that must be escaped \x7f\"", []string{`Error: invalid character in basic string: '\u007f' (must be escaped) at line 1, column 33`}}, } { p := &parser{} testParseHandler(t, p, p.startBasicString, test) } } func TestMultiLineBasicString(t *testing.T) { for _, test := range []parseTest{ {``, []string{`Error: unexpected end of file (expected opening three quotation marks) at start of file`}}, {`"""missing close quote""`, []string{`Error: unexpected end of file (expected closing three quotation marks) at line 1, column 25`}}, {`""""""`, []string{`string("")`}}, {"\"\"\"\n\"\"\"", []string{`string("")`}}, {"\"\"\"\r\n\r\n\"\"\"", []string{`string("\n")`}}, {`"""\"\"\"\""""`, []string{`string("\"\"\"\"")`}}, {"\"\"\"\nThe quick brown \\\n\n\n \t fox jumps over \\\n\t the lazy dog.\\\n \"\"\"", []string{`string("The quick brown fox jumps over the lazy dog.")`}}, {"\"\"\"No control chars \f allowed\"\"\"", []string{`Error: invalid character in multi-line basic string: '\f' (must be escaped) at line 1, column 21`}}, {"\"\"\"Escaping control chars\\nis valid\"\"\"", []string{`string("Escaping control chars\nis valid")`}}, {"\"\"\"Invalid escaping \\is not allowed\"\"\"", []string{`Error: invalid escape sequence at line 1, column 21`}}, {"\"\"\"Invalid rune \xcd\"\"\"", []string{`Error: invalid UTF8 rune at line 1, column 17`}}, } { p := &parser{} testParseHandler(t, p, p.startMultiLineBasicString, test) } } func TestLiteralString(t *testing.T) { for _, test := range []parseTest{ {``, []string{`Error: unexpected end of file (expected opening single quote) at start of file`}}, {`'missing close quote`, []string{`Error: unexpected end of file (expected closing single quote) at line 1, column 21`}}, {`''`, []string{`string("")`}}, {`'simple'`, []string{`string("simple")`}}, {`'C:\Users\nodejs\templates'`, []string{`string("C:\\Users\\nodejs\\templates")`}}, {`'\\ServerX\admin$\system32\'`, []string{`string("\\\\ServerX\\admin$\\system32\\")`}}, {`'Tom "Dubs" Preston-Werner'`, []string{`string("Tom \"Dubs\" Preston-Werner")`}}, {`'<\i\c*\s*>'`, []string{`string("<\\i\\c*\\s*>")`}}, {"'No cont\rol chars allowed'", []string{`Error: invalid character in literal string: '\r' (no control chars allowed, except for tab) at line 1, column 9`}}, {"'Except\tfor\ttabs'", []string{`string("Except\tfor\ttabs")`}}, {"'Invalid rune \xcd'", []string{`Error: invalid UTF8 rune at line 1, column 15`}}, } { p := &parser{} testParseHandler(t, p, p.startLiteralString, test) } } func TestMultiLineLiteralString(t *testing.T) { for _, test := range []parseTest{ {``, []string{`Error: unexpected end of file (expected opening three single quotes) at start of file`}}, {`'''missing close quote''`, []string{`Error: unexpected end of file (expected closing three single quotes) at line 1, column 25`}}, {`''''''`, []string{`string("")`}}, {"'''\n'''", []string{`string("")`}}, {`'''I [dw]on't need \d{2} apples'''`, []string{`string("I [dw]on't need \\d{2} apples")`}}, {"'''\nThere can\nbe newlines\r\nand \ttabs!\r\n'''", []string{`string("There can\nbe newlines\nand \ttabs!\n")`}}, {"'''No other \f control characters'''", []string{`Error: invalid character in literal string: '\f' (no control chars allowed, except for tab and newline) at line 1, column 13`}}, {"'''No invalid runes allowed \xcd'''", []string{"Error: invalid UTF8 rune at line 1, column 29"}}, } { p := &parser{} testParseHandler(t, p, p.startMultiLineLiteralString, 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 := &parser{} input := fmt.Sprintf(`"%c"`, rune(i)) expected := fmt.Sprintf(`Error: invalid character in basic string: %q (must be escaped) at line 1, column 2`, rune(i)) testParseHandler(t, p, p.startString, parseTest{input, []string{expected}}) } }