|  | // 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!\""}, | 
|  | } | 
|  |  | 
|  | 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."`) | 
|  | } | 
|  | } |