| // Copyright 2020 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" |
| "strings" |
| "testing" |
| |
| "github.com/google/go-cmp/cmp" |
| ) |
| |
| func TestQuote(t *testing.T) { |
| testCases := []struct { |
| form Form |
| in string |
| out string |
| lossy bool |
| }{ |
| {form: String, in: "\x00", out: `"\u0000"`}, |
| {form: String, in: "abc\xffdef", out: `"abc�def"`, lossy: true}, |
| {form: Bytes, in: "abc\xffdef", out: `'abc\xffdef'`}, |
| {form: String.WithASCIIOnly(), |
| in: "abc\xffdef", out: `"abc\ufffddef"`, lossy: true}, |
| {form: String, in: "\a\b\f\r\n\t\v", out: `"\a\b\f\r\n\t\v"`}, |
| {form: String, in: "\"", out: `"\""`}, |
| {form: String, in: "\\", out: `"\\"`}, |
| {form: String, in: "\u263a", out: `"☺"`}, |
| {form: String, in: "\U0010ffff", out: `"\U0010ffff"`}, |
| {form: String, in: "\x04", out: `"\u0004"`}, |
| {form: Bytes, in: "\x04", out: `'\x04'`}, |
| {form: String.WithASCIIOnly(), in: "\u263a", out: `"\u263a"`}, |
| {form: String.WithGraphicOnly(), in: "\u263a", out: `"☺"`}, |
| { |
| form: String.WithASCIIOnly(), |
| in: "!\u00a0!\u2000!\u3000!", |
| out: `"!\u00a0!\u2000!\u3000!"`, |
| }, |
| {form: String, in: "a\nb", out: `"a\nb"`}, |
| {form: String.WithTabIndent(3), in: "a\nb", out: `""" |
| a |
| b |
| """`}, |
| {form: String.WithTabIndent(3), in: "a", out: `""" |
| a |
| """`}, |
| {form: String.WithTabIndent(3), in: "a\n", out: `""" |
| a |
| |
| """`}, |
| {form: String.WithTabIndent(3), in: "", out: `""" |
| """`}, |
| {form: String.WithTabIndent(3), in: "\n", out: `""" |
| |
| |
| """`}, |
| {form: String.WithTabIndent(3), in: "\n\n", out: `""" |
| |
| |
| |
| """`}, |
| {form: String.WithOptionalTabIndent(3), in: "a", out: `"a"`}, |
| {form: String.WithOptionalTabIndent(3), in: "a\n", out: `""" |
| a |
| |
| """`}, |
| |
| // Issue #541 |
| {form: String.WithTabIndent(3), in: "foo\n\"bar\"", out: `""" |
| foo |
| "bar" |
| """`}, |
| {form: String.WithTabIndent(3), in: "foo\n\"\"\"bar\"", out: `#""" |
| foo |
| """bar" |
| """#`}, |
| {form: String.WithTabIndent(3), in: "foo\n\"\"\"\"\"###bar\"", out: `####""" |
| foo |
| """""###bar" |
| """####`}, |
| {form: String.WithTabIndent(3), in: "foo\n\"\"\"\r\f\\", out: `#""" |
| foo |
| """\#r\#f\#\ |
| """#`}, |
| {form: Bytes.WithTabIndent(3), in: "foo'''\nhello", out: `#''' |
| foo''' |
| hello |
| '''#`}, |
| {form: Bytes.WithTabIndent(3), in: "foo\n'''\r\f\\", out: `#''' |
| foo |
| '''\#r\#f\#\ |
| '''#`}, |
| } |
| for _, tc := range testCases { |
| t.Run(fmt.Sprintf("%q", tc.in), func(t *testing.T) { |
| got := tc.form.Quote(tc.in) |
| if got != tc.out { |
| t.Errorf("Quote: %s", cmp.Diff(tc.out, got)) |
| } |
| |
| got = string(tc.form.Append(nil, tc.in)) |
| if got != tc.out { |
| t.Errorf("Append: %s", cmp.Diff(tc.out, got)) |
| } |
| |
| str, err := Unquote(got) |
| if err != nil { |
| t.Errorf("Roundtrip error: %v", err) |
| } |
| |
| if !tc.lossy && str != tc.in { |
| t.Errorf("Quote: %s", cmp.Diff(tc.in, str)) |
| } |
| }) |
| } |
| } |
| |
| func TestAppendEscaped(t *testing.T) { |
| testCases := []struct { |
| form Form |
| in string |
| out string |
| }{ |
| {String, "a", "a"}, |
| {String, "", ""}, |
| {String.WithTabIndent(2), "", ""}, |
| {String.WithTabIndent(2), "\n", "\n"}, |
| {String.WithTabIndent(2), "a\n", "a\n"}, |
| {String.WithTabIndent(2), "a\nb", "a\n\t\tb"}, |
| } |
| for _, tc := range testCases { |
| t.Run(tc.in, func(t *testing.T) { |
| buf := tc.form.AppendEscaped(nil, tc.in) |
| if got := string(buf); got != tc.out { |
| t.Error(cmp.Diff(tc.out, got)) |
| } |
| }) |
| } |
| } |
| |
| func BenchmarkQuote(b *testing.B) { |
| inputs := []string{ |
| "aaaa", |
| "aaaaaaa\n\naaaaaa", |
| strings.Repeat("aaaaaaaaaaa\n", 1000), |
| } |
| |
| for _, f := range []Form{ |
| String, |
| Bytes, |
| String.WithTabIndent(3), |
| String.WithOptionalTabIndent(3), |
| } { |
| b.Run("", func(b *testing.B) { |
| for i := 0; i < b.N; i++ { |
| for _, s := range inputs { |
| f.Quote(s) |
| } |
| } |
| }) |
| } |
| } |