1// Copyright 2009 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package strconv_test
6
7import (
8	. "strconv"
9	"testing"
10	"unicode"
11)
12
13// Verify that our IsPrint agrees with unicode.IsPrint.
14func TestIsPrint(t *testing.T) {
15	n := 0
16	for r := rune(0); r <= unicode.MaxRune; r++ {
17		if IsPrint(r) != unicode.IsPrint(r) {
18			t.Errorf("IsPrint(%U)=%t incorrect", r, IsPrint(r))
19			n++
20			if n > 10 {
21				return
22			}
23		}
24	}
25}
26
27// Verify that our IsGraphic agrees with unicode.IsGraphic.
28func TestIsGraphic(t *testing.T) {
29	n := 0
30	for r := rune(0); r <= unicode.MaxRune; r++ {
31		if IsGraphic(r) != unicode.IsGraphic(r) {
32			t.Errorf("IsGraphic(%U)=%t incorrect", r, IsGraphic(r))
33			n++
34			if n > 10 {
35				return
36			}
37		}
38	}
39}
40
41type quoteTest struct {
42	in      string
43	out     string
44	ascii   string
45	graphic string
46}
47
48var quotetests = []quoteTest{
49	{"\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"`},
50	{"\\", `"\\"`, `"\\"`, `"\\"`},
51	{"abc\xffdef", `"abc\xffdef"`, `"abc\xffdef"`, `"abc\xffdef"`},
52	{"\u263a", `"☺"`, `"\u263a"`, `"☺"`},
53	{"\U0010ffff", `"\U0010ffff"`, `"\U0010ffff"`, `"\U0010ffff"`},
54	{"\x04", `"\x04"`, `"\x04"`, `"\x04"`},
55	// Some non-printable but graphic runes. Final column is double-quoted.
56	{"!\u00a0!\u2000!\u3000!", `"!\u00a0!\u2000!\u3000!"`, `"!\u00a0!\u2000!\u3000!"`, "\"!\u00a0!\u2000!\u3000!\""},
57}
58
59func TestQuote(t *testing.T) {
60	for _, tt := range quotetests {
61		if out := Quote(tt.in); out != tt.out {
62			t.Errorf("Quote(%s) = %s, want %s", tt.in, out, tt.out)
63		}
64		if out := AppendQuote([]byte("abc"), tt.in); string(out) != "abc"+tt.out {
65			t.Errorf("AppendQuote(%q, %s) = %s, want %s", "abc", tt.in, out, "abc"+tt.out)
66		}
67	}
68}
69
70func TestQuoteToASCII(t *testing.T) {
71	for _, tt := range quotetests {
72		if out := QuoteToASCII(tt.in); out != tt.ascii {
73			t.Errorf("QuoteToASCII(%s) = %s, want %s", tt.in, out, tt.ascii)
74		}
75		if out := AppendQuoteToASCII([]byte("abc"), tt.in); string(out) != "abc"+tt.ascii {
76			t.Errorf("AppendQuoteToASCII(%q, %s) = %s, want %s", "abc", tt.in, out, "abc"+tt.ascii)
77		}
78	}
79}
80
81func TestQuoteToGraphic(t *testing.T) {
82	for _, tt := range quotetests {
83		if out := QuoteToGraphic(tt.in); out != tt.graphic {
84			t.Errorf("QuoteToGraphic(%s) = %s, want %s", tt.in, out, tt.graphic)
85		}
86		if out := AppendQuoteToGraphic([]byte("abc"), tt.in); string(out) != "abc"+tt.graphic {
87			t.Errorf("AppendQuoteToGraphic(%q, %s) = %s, want %s", "abc", tt.in, out, "abc"+tt.graphic)
88		}
89	}
90}
91
92type quoteRuneTest struct {
93	in      rune
94	out     string
95	ascii   string
96	graphic string
97}
98
99var quoterunetests = []quoteRuneTest{
100	{'a', `'a'`, `'a'`, `'a'`},
101	{'\a', `'\a'`, `'\a'`, `'\a'`},
102	{'\\', `'\\'`, `'\\'`, `'\\'`},
103	{0xFF, `'ÿ'`, `'\u00ff'`, `'ÿ'`},
104	{0x263a, `'☺'`, `'\u263a'`, `'☺'`},
105	{0xfffd, `'�'`, `'\ufffd'`, `'�'`},
106	{0x0010ffff, `'\U0010ffff'`, `'\U0010ffff'`, `'\U0010ffff'`},
107	{0x0010ffff + 1, `'�'`, `'\ufffd'`, `'�'`},
108	{0x04, `'\x04'`, `'\x04'`, `'\x04'`},
109	// Some differences between graphic and printable. Note the last column is double-quoted.
110	{'\u00a0', `'\u00a0'`, `'\u00a0'`, "'\u00a0'"},
111	{'\u2000', `'\u2000'`, `'\u2000'`, "'\u2000'"},
112	{'\u3000', `'\u3000'`, `'\u3000'`, "'\u3000'"},
113}
114
115func TestQuoteRune(t *testing.T) {
116	for _, tt := range quoterunetests {
117		if out := QuoteRune(tt.in); out != tt.out {
118			t.Errorf("QuoteRune(%U) = %s, want %s", tt.in, out, tt.out)
119		}
120		if out := AppendQuoteRune([]byte("abc"), tt.in); string(out) != "abc"+tt.out {
121			t.Errorf("AppendQuoteRune(%q, %U) = %s, want %s", "abc", tt.in, out, "abc"+tt.out)
122		}
123	}
124}
125
126func TestQuoteRuneToASCII(t *testing.T) {
127	for _, tt := range quoterunetests {
128		if out := QuoteRuneToASCII(tt.in); out != tt.ascii {
129			t.Errorf("QuoteRuneToASCII(%U) = %s, want %s", tt.in, out, tt.ascii)
130		}
131		if out := AppendQuoteRuneToASCII([]byte("abc"), tt.in); string(out) != "abc"+tt.ascii {
132			t.Errorf("AppendQuoteRuneToASCII(%q, %U) = %s, want %s", "abc", tt.in, out, "abc"+tt.ascii)
133		}
134	}
135}
136
137func TestQuoteRuneToGraphic(t *testing.T) {
138	for _, tt := range quoterunetests {
139		if out := QuoteRuneToGraphic(tt.in); out != tt.graphic {
140			t.Errorf("QuoteRuneToGraphic(%U) = %s, want %s", tt.in, out, tt.graphic)
141		}
142		if out := AppendQuoteRuneToGraphic([]byte("abc"), tt.in); string(out) != "abc"+tt.graphic {
143			t.Errorf("AppendQuoteRuneToGraphic(%q, %U) = %s, want %s", "abc", tt.in, out, "abc"+tt.graphic)
144		}
145	}
146}
147
148type canBackquoteTest struct {
149	in  string
150	out bool
151}
152
153var canbackquotetests = []canBackquoteTest{
154	{"`", false},
155	{string(0), false},
156	{string(1), false},
157	{string(2), false},
158	{string(3), false},
159	{string(4), false},
160	{string(5), false},
161	{string(6), false},
162	{string(7), false},
163	{string(8), false},
164	{string(9), true}, // \t
165	{string(10), false},
166	{string(11), false},
167	{string(12), false},
168	{string(13), false},
169	{string(14), false},
170	{string(15), false},
171	{string(16), false},
172	{string(17), false},
173	{string(18), false},
174	{string(19), false},
175	{string(20), false},
176	{string(21), false},
177	{string(22), false},
178	{string(23), false},
179	{string(24), false},
180	{string(25), false},
181	{string(26), false},
182	{string(27), false},
183	{string(28), false},
184	{string(29), false},
185	{string(30), false},
186	{string(31), false},
187	{string(0x7F), false},
188	{`' !"#$%&'()*+,-./:;<=>?@[\]^_{|}~`, true},
189	{`0123456789`, true},
190	{`ABCDEFGHIJKLMNOPQRSTUVWXYZ`, true},
191	{`abcdefghijklmnopqrstuvwxyz`, true},
192	{`☺`, true},
193	{"\x80", false},
194	{"a\xe0\xa0z", false},
195	{"\ufeffabc", false},
196	{"a\ufeffz", false},
197}
198
199func TestCanBackquote(t *testing.T) {
200	for _, tt := range canbackquotetests {
201		if out := CanBackquote(tt.in); out != tt.out {
202			t.Errorf("CanBackquote(%q) = %v, want %v", tt.in, out, tt.out)
203		}
204	}
205}
206
207type unQuoteTest struct {
208	in  string
209	out string
210}
211
212var unquotetests = []unQuoteTest{
213	{`""`, ""},
214	{`"a"`, "a"},
215	{`"abc"`, "abc"},
216	{`"☺"`, "☺"},
217	{`"hello world"`, "hello world"},
218	{`"\xFF"`, "\xFF"},
219	{`"\377"`, "\377"},
220	{`"\u1234"`, "\u1234"},
221	{`"\U00010111"`, "\U00010111"},
222	{`"\U0001011111"`, "\U0001011111"},
223	{`"\a\b\f\n\r\t\v\\\""`, "\a\b\f\n\r\t\v\\\""},
224	{`"'"`, "'"},
225
226	{`'a'`, "a"},
227	{`'☹'`, "☹"},
228	{`'\a'`, "\a"},
229	{`'\x10'`, "\x10"},
230	{`'\377'`, "\377"},
231	{`'\u1234'`, "\u1234"},
232	{`'\U00010111'`, "\U00010111"},
233	{`'\t'`, "\t"},
234	{`' '`, " "},
235	{`'\''`, "'"},
236	{`'"'`, "\""},
237
238	{"``", ``},
239	{"`a`", `a`},
240	{"`abc`", `abc`},
241	{"`☺`", `☺`},
242	{"`hello world`", `hello world`},
243	{"`\\xFF`", `\xFF`},
244	{"`\\377`", `\377`},
245	{"`\\`", `\`},
246	{"`\n`", "\n"},
247	{"`	`", `	`},
248	{"` `", ` `},
249}
250
251var misquoted = []string{
252	``,
253	`"`,
254	`"a`,
255	`"'`,
256	`b"`,
257	`"\"`,
258	`"\9"`,
259	`"\19"`,
260	`"\129"`,
261	`'\'`,
262	`'\9'`,
263	`'\19'`,
264	`'\129'`,
265	`'ab'`,
266	`"\x1!"`,
267	`"\U12345678"`,
268	`"\z"`,
269	"`",
270	"`xxx",
271	"`\"",
272	`"\'"`,
273	`'\"'`,
274	"\"\n\"",
275	"\"\\n\n\"",
276	"'\n'",
277}
278
279func TestUnquote(t *testing.T) {
280	for _, tt := range unquotetests {
281		if out, err := Unquote(tt.in); err != nil && out != tt.out {
282			t.Errorf("Unquote(%#q) = %q, %v want %q, nil", tt.in, out, err, tt.out)
283		}
284	}
285
286	// run the quote tests too, backward
287	for _, tt := range quotetests {
288		if in, err := Unquote(tt.out); in != tt.in {
289			t.Errorf("Unquote(%#q) = %q, %v, want %q, nil", tt.out, in, err, tt.in)
290		}
291	}
292
293	for _, s := range misquoted {
294		if out, err := Unquote(s); out != "" || err != ErrSyntax {
295			t.Errorf("Unquote(%#q) = %q, %v want %q, %v", s, out, err, "", ErrSyntax)
296		}
297	}
298}
299
300func BenchmarkUnquoteEasy(b *testing.B) {
301	for i := 0; i < b.N; i++ {
302		Unquote(`"Give me a rock, paper and scissors and I will move the world."`)
303	}
304}
305
306func BenchmarkUnquoteHard(b *testing.B) {
307	for i := 0; i < b.N; i++ {
308		Unquote(`"\x47ive me a \x72ock, \x70aper and \x73cissors and \x49 will move the world."`)
309	}
310}
311