github.com/joomcode/cue@v0.4.4-0.20221111115225-539fe3512047/cue/literal/string_test.go (about)

     1  // Copyright 2019 CUE Authors
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package literal
    16  
    17  import (
    18  	"fmt"
    19  	"testing"
    20  )
    21  
    22  func TestUnquote(t *testing.T) {
    23  	testCases := []struct {
    24  		in, out string
    25  		err     error
    26  	}{
    27  		{`"Hello"`, "Hello", nil},
    28  		{`'Hello'`, "Hello", nil},
    29  		{`'Hellø'`, "Hellø", nil},
    30  		{`"""` + "\n\t\tHello\n\t\t" + `"""`, "Hello", nil},
    31  		{"'''\n\t\tHello\n\t\t'''", "Hello", nil},
    32  		{"'''\n\t\tHello\n\n\t\t'''", "Hello\n", nil},
    33  		{"'''\n\n\t\tHello\n\t\t'''", "\nHello", nil},
    34  		{"'''\n\n\n\n\t\t'''", "\n\n", nil},
    35  		{"'''\n\t\t'''", "", nil},
    36  		{`"""` + "\n\raaa\n\rbbb\n\r" + `"""`, "aaa\nbbb", nil},
    37  		{`'\a\b\f\n\r\t\v\'\\\/'`, "\a\b\f\n\r\t\v'\\/", nil},
    38  		{`"\a\b\f\n\r\t\v\"\\\/"`, "\a\b\f\n\r\t\v\"\\/", nil},
    39  		{`#"The sequence "\U0001F604" renders as \#U0001F604."#`,
    40  			`The sequence "\U0001F604" renders as 😄.`,
    41  			nil},
    42  		{`"  \U00010FfF"`, "  \U00010fff", nil},
    43  		{`"\u0061 "`, "a ", nil},
    44  		{`'\x61\x55'`, "\x61\x55", nil},
    45  		{`'\061\055'`, "\061\055", nil},
    46  		{`'\377 '`, "\377 ", nil},
    47  		{"'e\u0300\\n'", "e\u0300\n", nil},
    48  		{`'\06\055'`, "", errSyntax},
    49  		{`'\0'`, "", errSyntax},
    50  		{`"\06\055"`, "", errSyntax},    // too short
    51  		{`'\777 '`, "", errSyntax},      // overflow
    52  		{`'\U012301'`, "", errSyntax},   // too short
    53  		{`'\U0123012G'`, "", errSyntax}, // invalid digit G
    54  		{`"\x04"`, "", errSyntax},       // not allowed in strings
    55  		{`'\U01230123'`, "", errSyntax}, // too large
    56  
    57  		// Surrogate pairs
    58  		{`"\uD834\uDD1E"`, "𝄞", nil},
    59  		{`"\uDD1E\uD834"`, "", errSurrogate},
    60  		{`"\uD834\uD834"`, "", errSurrogate},
    61  
    62  		{`"\\"`, "\\", nil},
    63  		{`"\'"`, "", errSyntax},
    64  		{`"\q"`, "", errSyntax},
    65  		{"'\n'", "", errSyntax},
    66  		{"'---\n---'", "", errSyntax},
    67  		{"'''\r'''", "", errMissingNewline},
    68  
    69  		{`#"Hello"#`, "Hello", nil},
    70  		{`#"Hello\v"#`, "Hello\\v", nil},
    71  		{`#"Hello\#v\r"#`, "Hello\v\\r", nil},
    72  		{`##"Hello\##v\r"##`, "Hello\v\\r", nil},
    73  		{`##"Hello\##v"##`, "Hello\v", nil},
    74  		{"#'''\n\t\tHello\\#v\n\t\t'''#", "Hello\v", nil},
    75  		{"##'''\n\t\tHello\\#v\n\t\t'''##", "Hello\\#v", nil},
    76  		{`#"""` + "\n\t\t\\#r\n\t\t" + `"""#`, "\r", nil},
    77  		{`#""#`, "", nil},
    78  		{`#" ""#`, ` "`, nil},
    79  		{`#" """#`, ` ""`, nil},
    80  		{`##" """# "##`, ` """# `, nil},
    81  		{`##" """# "##`, ` """# `, nil},
    82  		{`#"This is a "dog""#`, `This is a "dog"`, nil},
    83  		{"#\"\"\"\n\"\n\"\"\"#", `"`, nil},
    84  		{"#\"\"\"\n\"\"\"\n\"\"\"#", `"""`, nil},
    85  		{"#\"\"\"\n\na\n\n\"\"\"#", "\na\n", nil},
    86  		// Gobble extra \r
    87  		{"#\"\"\"\n\ra\n\r\"\"\"#", `a`, nil},
    88  		{"#\"\"\"\n\r\n\ra\n\r\n\r\"\"\"#", "\na\n", nil},
    89  		// Make sure this works for Windows.
    90  		{"#\"\"\"\r\n\r\na\r\n\r\n\"\"\"#", "\na\n", nil},
    91  		{"#\"\"\"\r\n \r\n a\r\n \r\n \"\"\"#", "\na\n", nil},
    92  		{"#\"\"\"\r\na\r\n\"\"\"#", `a`, nil},
    93  		{"#\"\"\"\r\n\ra\r\n\r\"\"\"#", `a`, nil},
    94  		{`####"   \"####`, `   \`, nil},
    95  
    96  		{"```", "", errSyntax},
    97  		{"Hello", "", errSyntax},
    98  		{`"Hello`, "", errUnmatchedQuote},
    99  		{`"""Hello"""`, "", errMissingNewline},
   100  		{"'''\n  Hello\n   '''", "", errInvalidWhitespace},
   101  		{"'''\n   a\n  b\n   '''", "", errInvalidWhitespace},
   102  		{`"Hello""`, "", errSyntax},
   103  		{`#"Hello"`, "", errUnmatchedQuote},
   104  		{`#"Hello'#`, "", errUnmatchedQuote},
   105  		{`#""" """#`, "", errMissingNewline},
   106  
   107  		// TODO: should this be legal?
   108  		{`#"""#`, "", errMissingNewline},
   109  	}
   110  	for i, tc := range testCases {
   111  		t.Run(fmt.Sprintf("%d/%s", i, tc.in), func(t *testing.T) {
   112  			if got, err := Unquote(tc.in); err != tc.err {
   113  				t.Errorf("error: got %q; want %q", err, tc.err)
   114  			} else if got != tc.out {
   115  				t.Errorf("value: got %q; want %q", got, tc.out)
   116  			}
   117  		})
   118  	}
   119  }
   120  
   121  func TestInterpolation(t *testing.T) {
   122  	testCases := []struct {
   123  		quotes string
   124  		in     string
   125  		out    string
   126  		err    error
   127  	}{
   128  		{`""`, `foo\(`, "foo", nil},
   129  		{`"""` + "\n" + `"""`, `foo`, "", errUnmatchedQuote},
   130  		{`#""#`, `foo\#(`, "foo", nil},
   131  		{`#""#`, `foo\(`, "", errUnmatchedQuote},
   132  		{`""`, `foo\(bar`, "", errSyntax},
   133  		{`""`, ``, "", errUnmatchedQuote},
   134  		{`#""#`, `"`, "", errUnmatchedQuote},
   135  		{`#""#`, `\`, "", errUnmatchedQuote},
   136  		{`##""##`, `\'`, "", errUnmatchedQuote},
   137  	}
   138  	for i, tc := range testCases {
   139  		t.Run(fmt.Sprintf("%d/%s/%s", i, tc.quotes, tc.in), func(t *testing.T) {
   140  			info, _, _, _ := ParseQuotes(tc.quotes, tc.quotes)
   141  			if got, err := info.Unquote(tc.in); err != tc.err {
   142  				t.Errorf("error: got %q; want %q", err, tc.err)
   143  			} else if got != tc.out {
   144  				t.Errorf("value: got %q; want %q", got, tc.out)
   145  			}
   146  		})
   147  	}
   148  }
   149  
   150  func TestIsDouble(t *testing.T) {
   151  	testCases := []struct {
   152  		quotes string
   153  		double bool
   154  	}{
   155  		{`""`, true},
   156  		{`"""` + "\n" + `"""`, true},
   157  		{`#""#`, true},
   158  		{`''`, false},
   159  		{`'''` + "\n" + `'''`, false},
   160  		{`#''#`, false},
   161  	}
   162  	for i, tc := range testCases {
   163  		t.Run(fmt.Sprintf("%d/%s", i, tc.quotes), func(t *testing.T) {
   164  			info, _, _, err := ParseQuotes(tc.quotes, tc.quotes)
   165  			if err != nil {
   166  				t.Fatal(err)
   167  			}
   168  			if got := info.IsDouble(); got != tc.double {
   169  				t.Errorf("got %v; want %v", got, tc.double)
   170  			}
   171  		})
   172  	}
   173  }