summaryrefslogtreecommitdiffstats
path: root/src/strconv/quote_test.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/strconv/quote_test.go')
-rw-r--r--src/strconv/quote_test.go384
1 files changed, 384 insertions, 0 deletions
diff --git a/src/strconv/quote_test.go b/src/strconv/quote_test.go
new file mode 100644
index 0000000..fc000de
--- /dev/null
+++ b/src/strconv/quote_test.go
@@ -0,0 +1,384 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package strconv_test
+
+import (
+ . "strconv"
+ "strings"
+ "testing"
+ "unicode"
+)
+
+// Verify that our IsPrint agrees with unicode.IsPrint.
+func TestIsPrint(t *testing.T) {
+ n := 0
+ for r := rune(0); r <= unicode.MaxRune; r++ {
+ if IsPrint(r) != unicode.IsPrint(r) {
+ t.Errorf("IsPrint(%U)=%t incorrect", r, IsPrint(r))
+ n++
+ if n > 10 {
+ return
+ }
+ }
+ }
+}
+
+// Verify that our IsGraphic agrees with unicode.IsGraphic.
+func TestIsGraphic(t *testing.T) {
+ n := 0
+ for r := rune(0); r <= unicode.MaxRune; r++ {
+ if IsGraphic(r) != unicode.IsGraphic(r) {
+ t.Errorf("IsGraphic(%U)=%t incorrect", r, IsGraphic(r))
+ n++
+ if n > 10 {
+ return
+ }
+ }
+ }
+}
+
+type quoteTest struct {
+ in string
+ out string
+ ascii string
+ graphic string
+}
+
+var quotetests = []quoteTest{
+ {"\a\b\f\r\n\t\v", `"\a\b\f\r\n\t\v"`, `"\a\b\f\r\n\t\v"`, `"\a\b\f\r\n\t\v"`},
+ {"\\", `"\\"`, `"\\"`, `"\\"`},
+ {"abc\xffdef", `"abc\xffdef"`, `"abc\xffdef"`, `"abc\xffdef"`},
+ {"\u263a", `"☺"`, `"\u263a"`, `"☺"`},
+ {"\U0010ffff", `"\U0010ffff"`, `"\U0010ffff"`, `"\U0010ffff"`},
+ {"\x04", `"\x04"`, `"\x04"`, `"\x04"`},
+ // Some non-printable but graphic runes. Final column is double-quoted.
+ {"!\u00a0!\u2000!\u3000!", `"!\u00a0!\u2000!\u3000!"`, `"!\u00a0!\u2000!\u3000!"`, "\"!\u00a0!\u2000!\u3000!\""},
+ {"\x7f", `"\x7f"`, `"\x7f"`, `"\x7f"`},
+}
+
+func TestQuote(t *testing.T) {
+ for _, tt := range quotetests {
+ if out := Quote(tt.in); out != tt.out {
+ t.Errorf("Quote(%s) = %s, want %s", tt.in, out, tt.out)
+ }
+ if out := AppendQuote([]byte("abc"), tt.in); string(out) != "abc"+tt.out {
+ t.Errorf("AppendQuote(%q, %s) = %s, want %s", "abc", tt.in, out, "abc"+tt.out)
+ }
+ }
+}
+
+func TestQuoteToASCII(t *testing.T) {
+ for _, tt := range quotetests {
+ if out := QuoteToASCII(tt.in); out != tt.ascii {
+ t.Errorf("QuoteToASCII(%s) = %s, want %s", tt.in, out, tt.ascii)
+ }
+ if out := AppendQuoteToASCII([]byte("abc"), tt.in); string(out) != "abc"+tt.ascii {
+ t.Errorf("AppendQuoteToASCII(%q, %s) = %s, want %s", "abc", tt.in, out, "abc"+tt.ascii)
+ }
+ }
+}
+
+func TestQuoteToGraphic(t *testing.T) {
+ for _, tt := range quotetests {
+ if out := QuoteToGraphic(tt.in); out != tt.graphic {
+ t.Errorf("QuoteToGraphic(%s) = %s, want %s", tt.in, out, tt.graphic)
+ }
+ if out := AppendQuoteToGraphic([]byte("abc"), tt.in); string(out) != "abc"+tt.graphic {
+ t.Errorf("AppendQuoteToGraphic(%q, %s) = %s, want %s", "abc", tt.in, out, "abc"+tt.graphic)
+ }
+ }
+}
+
+func BenchmarkQuote(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Quote("\a\b\f\r\n\t\v\a\b\f\r\n\t\v\a\b\f\r\n\t\v")
+ }
+}
+
+func BenchmarkQuoteRune(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ QuoteRune('\a')
+ }
+}
+
+var benchQuoteBuf []byte
+
+func BenchmarkAppendQuote(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ benchQuoteBuf = AppendQuote(benchQuoteBuf[:0], "\a\b\f\r\n\t\v\a\b\f\r\n\t\v\a\b\f\r\n\t\v")
+ }
+}
+
+var benchQuoteRuneBuf []byte
+
+func BenchmarkAppendQuoteRune(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ benchQuoteRuneBuf = AppendQuoteRune(benchQuoteRuneBuf[:0], '\a')
+ }
+}
+
+type quoteRuneTest struct {
+ in rune
+ out string
+ ascii string
+ graphic string
+}
+
+var quoterunetests = []quoteRuneTest{
+ {'a', `'a'`, `'a'`, `'a'`},
+ {'\a', `'\a'`, `'\a'`, `'\a'`},
+ {'\\', `'\\'`, `'\\'`, `'\\'`},
+ {0xFF, `'ÿ'`, `'\u00ff'`, `'ÿ'`},
+ {0x263a, `'☺'`, `'\u263a'`, `'☺'`},
+ {0xdead, `'�'`, `'\ufffd'`, `'�'`},
+ {0xfffd, `'�'`, `'\ufffd'`, `'�'`},
+ {0x0010ffff, `'\U0010ffff'`, `'\U0010ffff'`, `'\U0010ffff'`},
+ {0x0010ffff + 1, `'�'`, `'\ufffd'`, `'�'`},
+ {0x04, `'\x04'`, `'\x04'`, `'\x04'`},
+ // Some differences between graphic and printable. Note the last column is double-quoted.
+ {'\u00a0', `'\u00a0'`, `'\u00a0'`, "'\u00a0'"},
+ {'\u2000', `'\u2000'`, `'\u2000'`, "'\u2000'"},
+ {'\u3000', `'\u3000'`, `'\u3000'`, "'\u3000'"},
+}
+
+func TestQuoteRune(t *testing.T) {
+ for _, tt := range quoterunetests {
+ if out := QuoteRune(tt.in); out != tt.out {
+ t.Errorf("QuoteRune(%U) = %s, want %s", tt.in, out, tt.out)
+ }
+ if out := AppendQuoteRune([]byte("abc"), tt.in); string(out) != "abc"+tt.out {
+ t.Errorf("AppendQuoteRune(%q, %U) = %s, want %s", "abc", tt.in, out, "abc"+tt.out)
+ }
+ }
+}
+
+func TestQuoteRuneToASCII(t *testing.T) {
+ for _, tt := range quoterunetests {
+ if out := QuoteRuneToASCII(tt.in); out != tt.ascii {
+ t.Errorf("QuoteRuneToASCII(%U) = %s, want %s", tt.in, out, tt.ascii)
+ }
+ if out := AppendQuoteRuneToASCII([]byte("abc"), tt.in); string(out) != "abc"+tt.ascii {
+ t.Errorf("AppendQuoteRuneToASCII(%q, %U) = %s, want %s", "abc", tt.in, out, "abc"+tt.ascii)
+ }
+ }
+}
+
+func TestQuoteRuneToGraphic(t *testing.T) {
+ for _, tt := range quoterunetests {
+ if out := QuoteRuneToGraphic(tt.in); out != tt.graphic {
+ t.Errorf("QuoteRuneToGraphic(%U) = %s, want %s", tt.in, out, tt.graphic)
+ }
+ if out := AppendQuoteRuneToGraphic([]byte("abc"), tt.in); string(out) != "abc"+tt.graphic {
+ t.Errorf("AppendQuoteRuneToGraphic(%q, %U) = %s, want %s", "abc", tt.in, out, "abc"+tt.graphic)
+ }
+ }
+}
+
+type canBackquoteTest struct {
+ in string
+ out bool
+}
+
+var canbackquotetests = []canBackquoteTest{
+ {"`", false},
+ {string(rune(0)), false},
+ {string(rune(1)), false},
+ {string(rune(2)), false},
+ {string(rune(3)), false},
+ {string(rune(4)), false},
+ {string(rune(5)), false},
+ {string(rune(6)), false},
+ {string(rune(7)), false},
+ {string(rune(8)), false},
+ {string(rune(9)), true}, // \t
+ {string(rune(10)), false},
+ {string(rune(11)), false},
+ {string(rune(12)), false},
+ {string(rune(13)), false},
+ {string(rune(14)), false},
+ {string(rune(15)), false},
+ {string(rune(16)), false},
+ {string(rune(17)), false},
+ {string(rune(18)), false},
+ {string(rune(19)), false},
+ {string(rune(20)), false},
+ {string(rune(21)), false},
+ {string(rune(22)), false},
+ {string(rune(23)), false},
+ {string(rune(24)), false},
+ {string(rune(25)), false},
+ {string(rune(26)), false},
+ {string(rune(27)), false},
+ {string(rune(28)), false},
+ {string(rune(29)), false},
+ {string(rune(30)), false},
+ {string(rune(31)), false},
+ {string(rune(0x7F)), false},
+ {`' !"#$%&'()*+,-./:;<=>?@[\]^_{|}~`, true},
+ {`0123456789`, true},
+ {`ABCDEFGHIJKLMNOPQRSTUVWXYZ`, true},
+ {`abcdefghijklmnopqrstuvwxyz`, true},
+ {`☺`, true},
+ {"\x80", false},
+ {"a\xe0\xa0z", false},
+ {"\ufeffabc", false},
+ {"a\ufeffz", false},
+}
+
+func TestCanBackquote(t *testing.T) {
+ for _, tt := range canbackquotetests {
+ if out := CanBackquote(tt.in); out != tt.out {
+ t.Errorf("CanBackquote(%q) = %v, want %v", tt.in, out, tt.out)
+ }
+ }
+}
+
+type unQuoteTest struct {
+ in string
+ out string
+}
+
+var unquotetests = []unQuoteTest{
+ {`""`, ""},
+ {`"a"`, "a"},
+ {`"abc"`, "abc"},
+ {`"☺"`, "☺"},
+ {`"hello world"`, "hello world"},
+ {`"\xFF"`, "\xFF"},
+ {`"\377"`, "\377"},
+ {`"\u1234"`, "\u1234"},
+ {`"\U00010111"`, "\U00010111"},
+ {`"\U0001011111"`, "\U0001011111"},
+ {`"\a\b\f\n\r\t\v\\\""`, "\a\b\f\n\r\t\v\\\""},
+ {`"'"`, "'"},
+
+ {`'a'`, "a"},
+ {`'☹'`, "☹"},
+ {`'\a'`, "\a"},
+ {`'\x10'`, "\x10"},
+ {`'\377'`, "\377"},
+ {`'\u1234'`, "\u1234"},
+ {`'\U00010111'`, "\U00010111"},
+ {`'\t'`, "\t"},
+ {`' '`, " "},
+ {`'\''`, "'"},
+ {`'"'`, "\""},
+
+ {"``", ``},
+ {"`a`", `a`},
+ {"`abc`", `abc`},
+ {"`☺`", `☺`},
+ {"`hello world`", `hello world`},
+ {"`\\xFF`", `\xFF`},
+ {"`\\377`", `\377`},
+ {"`\\`", `\`},
+ {"`\n`", "\n"},
+ {"` `", ` `},
+ {"` `", ` `},
+ {"`a\rb`", "ab"},
+}
+
+var misquoted = []string{
+ ``,
+ `"`,
+ `"a`,
+ `"'`,
+ `b"`,
+ `"\"`,
+ `"\9"`,
+ `"\19"`,
+ `"\129"`,
+ `'\'`,
+ `'\9'`,
+ `'\19'`,
+ `'\129'`,
+ `'ab'`,
+ `"\x1!"`,
+ `"\U12345678"`,
+ `"\z"`,
+ "`",
+ "`xxx",
+ "``x\r",
+ "`\"",
+ `"\'"`,
+ `'\"'`,
+ "\"\n\"",
+ "\"\\n\n\"",
+ "'\n'",
+ `"\udead"`,
+ `"\ud83d\ude4f"`,
+}
+
+func TestUnquote(t *testing.T) {
+ for _, tt := range unquotetests {
+ testUnquote(t, tt.in, tt.out, nil)
+ }
+ for _, tt := range quotetests {
+ testUnquote(t, tt.out, tt.in, nil)
+ }
+ for _, s := range misquoted {
+ testUnquote(t, s, "", ErrSyntax)
+ }
+}
+
+// Issue 23685: invalid UTF-8 should not go through the fast path.
+func TestUnquoteInvalidUTF8(t *testing.T) {
+ tests := []struct {
+ in string
+
+ // one of:
+ want string
+ wantErr error
+ }{
+ {in: `"foo"`, want: "foo"},
+ {in: `"foo`, wantErr: ErrSyntax},
+ {in: `"` + "\xc0" + `"`, want: "\xef\xbf\xbd"},
+ {in: `"a` + "\xc0" + `"`, want: "a\xef\xbf\xbd"},
+ {in: `"\t` + "\xc0" + `"`, want: "\t\xef\xbf\xbd"},
+ }
+ for _, tt := range tests {
+ testUnquote(t, tt.in, tt.want, tt.wantErr)
+ }
+}
+
+func testUnquote(t *testing.T, in, want string, wantErr error) {
+ // Test Unquote.
+ got, gotErr := Unquote(in)
+ if got != want || gotErr != wantErr {
+ t.Errorf("Unquote(%q) = (%q, %v), want (%q, %v)", in, got, gotErr, want, wantErr)
+ }
+
+ // Test QuotedPrefix.
+ // Adding an arbitrary suffix should not change the result of QuotedPrefix
+ // assume that the suffix doesn't accidentally terminate a truncated input.
+ if gotErr == nil {
+ want = in
+ }
+ suffix := "\n\r\\\"`'" // special characters for quoted strings
+ if len(in) > 0 {
+ suffix = strings.ReplaceAll(suffix, in[:1], "")
+ }
+ in += suffix
+ got, gotErr = QuotedPrefix(in)
+ if gotErr == nil && wantErr != nil {
+ _, wantErr = Unquote(got) // original input had trailing junk, reparse with only valid prefix
+ want = got
+ }
+ if got != want || gotErr != wantErr {
+ t.Errorf("QuotedPrefix(%q) = (%q, %v), want (%q, %v)", in, got, gotErr, want, wantErr)
+ }
+}
+
+func BenchmarkUnquoteEasy(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Unquote(`"Give me a rock, paper and scissors and I will move the world."`)
+ }
+}
+
+func BenchmarkUnquoteHard(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Unquote(`"\x47ive me a \x72ock, \x70aper and \x73cissors and \x49 will move the world."`)
+ }
+}