blob: 07de07e800fbd411f63813b38c7d0db6a81d65cb [file] [log] [blame]
// Copyright 2019 CUE Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package literal
import (
"fmt"
"testing"
)
func TestUnquote(t *testing.T) {
testCases := []struct {
in, out string
err error
}{
{`"Hello"`, "Hello", nil},
{`'Hello'`, "Hello", nil},
{`'Hellø'`, "Hellø", nil},
{`"""` + "\n\t\tHello\n\t\t" + `"""`, "Hello", nil},
{"'''\n\t\tHello\n\t\t'''", "Hello", nil},
{"'''\n\t\tHello\n\n\t\t'''", "Hello\n", nil},
{"'''\n\n\t\tHello\n\t\t'''", "\nHello", nil},
{"'''\n\n\n\n\t\t'''", "\n\n", nil},
{"'''\n\t\t'''", "", nil},
{`"""` + "\n\raaa\n\rbbb\n\r" + `"""`, "aaa\nbbb", nil},
{`'\a\b\f\n\r\t\v\'\\\/'`, "\a\b\f\n\r\t\v'\\/", nil},
{`"\a\b\f\n\r\t\v\"\\\/"`, "\a\b\f\n\r\t\v\"\\/", nil},
{`#"The sequence "\U0001F604" renders as \#U0001F604."#`,
`The sequence "\U0001F604" renders as 😄.`,
nil},
{`" \U00010FfF"`, " \U00010fff", nil},
{`"\u0061 "`, "a ", nil},
{`'\x61\x55'`, "\x61\x55", nil},
{`'\061\055'`, "\061\055", nil},
{`'\377 '`, "\377 ", nil},
{"'e\u0300\\n'", "e\u0300\n", nil},
{`'\06\055'`, "", errSyntax},
{`'\0'`, "", errSyntax},
{`"\06\055"`, "", errSyntax}, // too short
{`'\777 '`, "", errSyntax}, // overflow
{`'\U012301'`, "", errSyntax}, // too short
{`'\U0123012G'`, "", errSyntax}, // invalid digit G
{`"\x04"`, "", errSyntax}, // not allowed in strings
{`'\U01230123'`, "", errSyntax}, // too large
// Surrogate pairs
{`"\uD834\uDD1E"`, "𝄞", nil},
{`"\uDD1E\uD834"`, "", errSurrogate},
{`"\uD834\uD834"`, "", errSurrogate},
{`"\\"`, "\\", nil},
{`"\'"`, "", errSyntax},
{`"\q"`, "", errSyntax},
{"'\n'", "", errSyntax},
{"'---\n---'", "", errSyntax},
{"'''\r'''", "", errMissingNewline},
{`#"Hello"#`, "Hello", nil},
{`#"Hello\v"#`, "Hello\\v", nil},
{`#"Hello\#v\r"#`, "Hello\v\\r", nil},
{`##"Hello\##v\r"##`, "Hello\v\\r", nil},
{`##"Hello\##v"##`, "Hello\v", nil},
{"#'''\n\t\tHello\\#v\n\t\t'''#", "Hello\v", nil},
{"##'''\n\t\tHello\\#v\n\t\t'''##", "Hello\\#v", nil},
{`#"""` + "\n\t\t\\#r\n\t\t" + `"""#`, "\r", nil},
{`#""#`, "", nil},
{`#" ""#`, ` "`, nil},
{`#" """#`, ` ""`, nil},
{`##" """# "##`, ` """# `, nil},
{`##" """# "##`, ` """# `, nil},
{`#"This is a "dog""#`, `This is a "dog"`, nil},
{"#\"\"\"\n\"\n\"\"\"#", `"`, nil},
{"#\"\"\"\n\"\"\"\n\"\"\"#", `"""`, nil},
{"#\"\"\"\n\na\n\n\"\"\"#", "\na\n", nil},
// Gobble extra \r
{"#\"\"\"\n\ra\n\r\"\"\"#", `a`, nil},
{"#\"\"\"\n\r\n\ra\n\r\n\r\"\"\"#", "\na\n", nil},
// Make sure this works for Windows.
{"#\"\"\"\r\n\r\na\r\n\r\n\"\"\"#", "\na\n", nil},
{"#\"\"\"\r\n \r\n a\r\n \r\n \"\"\"#", "\na\n", nil},
{"#\"\"\"\r\na\r\n\"\"\"#", `a`, nil},
{"#\"\"\"\r\n\ra\r\n\r\"\"\"#", `a`, nil},
{`####" \"####`, ` \`, nil},
{"```", "", errSyntax},
{"Hello", "", errSyntax},
{`"Hello`, "", errUnmatchedQuote},
{`"""Hello"""`, "", errMissingNewline},
{"'''\n Hello\n '''", "", errInvalidWhitespace},
{"'''\n a\n b\n '''", "", errInvalidWhitespace},
{`"Hello""`, "", errSyntax},
{`#"Hello"`, "", errUnmatchedQuote},
{`#"Hello'#`, "", errUnmatchedQuote},
{`#""" """#`, "", errMissingNewline},
// TODO: should this be legal?
{`#"""#`, "", errMissingNewline},
}
for i, tc := range testCases {
t.Run(fmt.Sprintf("%d/%s", i, tc.in), func(t *testing.T) {
if got, err := Unquote(tc.in); err != tc.err {
t.Errorf("error: got %q; want %q", err, tc.err)
} else if got != tc.out {
t.Errorf("value: got %q; want %q", got, tc.out)
}
})
}
}
func TestInterpolation(t *testing.T) {
testCases := []struct {
quotes string
in string
out string
err error
}{
{`""`, `foo\(`, "foo", nil},
{`"""` + "\n" + `"""`, `foo`, "", errUnmatchedQuote},
{`#""#`, `foo\#(`, "foo", nil},
{`#""#`, `foo\(`, "", errUnmatchedQuote},
{`""`, `foo\(bar`, "", errSyntax},
{`""`, ``, "", errUnmatchedQuote},
{`#""#`, `"`, "", errUnmatchedQuote},
{`#""#`, `\`, "", errUnmatchedQuote},
{`##""##`, `\'`, "", errUnmatchedQuote},
}
for i, tc := range testCases {
t.Run(fmt.Sprintf("%d/%s/%s", i, tc.quotes, tc.in), func(t *testing.T) {
info, _, _, _ := ParseQuotes(tc.quotes, tc.quotes)
if got, err := info.Unquote(tc.in); err != tc.err {
t.Errorf("error: got %q; want %q", err, tc.err)
} else if got != tc.out {
t.Errorf("value: got %q; want %q", got, tc.out)
}
})
}
}
func TestIsDouble(t *testing.T) {
testCases := []struct {
quotes string
double bool
}{
{`""`, true},
{`"""` + "\n" + `"""`, true},
{`#""#`, true},
{`''`, false},
{`'''` + "\n" + `'''`, false},
{`#''#`, false},
}
for i, tc := range testCases {
t.Run(fmt.Sprintf("%d/%s", i, tc.quotes), func(t *testing.T) {
info, _, _, err := ParseQuotes(tc.quotes, tc.quotes)
if err != nil {
t.Fatal(err)
}
if got := info.IsDouble(); got != tc.double {
t.Errorf("got %v; want %v", got, tc.double)
}
})
}
}