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	"errors"
9	"reflect"
10	. "strconv"
11	"testing"
12)
13
14type atoui64Test struct {
15	in  string
16	out uint64
17	err error
18}
19
20var atoui64tests = []atoui64Test{
21	{"", 0, ErrSyntax},
22	{"0", 0, nil},
23	{"1", 1, nil},
24	{"12345", 12345, nil},
25	{"012345", 12345, nil},
26	{"12345x", 0, ErrSyntax},
27	{"98765432100", 98765432100, nil},
28	{"18446744073709551615", 1<<64 - 1, nil},
29	{"18446744073709551616", 1<<64 - 1, ErrRange},
30	{"18446744073709551620", 1<<64 - 1, ErrRange},
31}
32
33var btoui64tests = []atoui64Test{
34	{"", 0, ErrSyntax},
35	{"0", 0, nil},
36	{"0x", 0, ErrSyntax},
37	{"0X", 0, ErrSyntax},
38	{"1", 1, nil},
39	{"12345", 12345, nil},
40	{"012345", 012345, nil},
41	{"0x12345", 0x12345, nil},
42	{"0X12345", 0x12345, nil},
43	{"12345x", 0, ErrSyntax},
44	{"0xabcdefg123", 0, ErrSyntax},
45	{"123456789abc", 0, ErrSyntax},
46	{"98765432100", 98765432100, nil},
47	{"18446744073709551615", 1<<64 - 1, nil},
48	{"18446744073709551616", 1<<64 - 1, ErrRange},
49	{"18446744073709551620", 1<<64 - 1, ErrRange},
50	{"0xFFFFFFFFFFFFFFFF", 1<<64 - 1, nil},
51	{"0x10000000000000000", 1<<64 - 1, ErrRange},
52	{"01777777777777777777777", 1<<64 - 1, nil},
53	{"01777777777777777777778", 0, ErrSyntax},
54	{"02000000000000000000000", 1<<64 - 1, ErrRange},
55	{"0200000000000000000000", 1 << 61, nil},
56}
57
58type atoi64Test struct {
59	in  string
60	out int64
61	err error
62}
63
64var atoi64tests = []atoi64Test{
65	{"", 0, ErrSyntax},
66	{"0", 0, nil},
67	{"-0", 0, nil},
68	{"1", 1, nil},
69	{"-1", -1, nil},
70	{"12345", 12345, nil},
71	{"-12345", -12345, nil},
72	{"012345", 12345, nil},
73	{"-012345", -12345, nil},
74	{"98765432100", 98765432100, nil},
75	{"-98765432100", -98765432100, nil},
76	{"9223372036854775807", 1<<63 - 1, nil},
77	{"-9223372036854775807", -(1<<63 - 1), nil},
78	{"9223372036854775808", 1<<63 - 1, ErrRange},
79	{"-9223372036854775808", -1 << 63, nil},
80	{"9223372036854775809", 1<<63 - 1, ErrRange},
81	{"-9223372036854775809", -1 << 63, ErrRange},
82}
83
84type btoi64Test struct {
85	in   string
86	base int
87	out  int64
88	err  error
89}
90
91var btoi64tests = []btoi64Test{
92	{"", 0, 0, ErrSyntax},
93	{"0", 0, 0, nil},
94	{"-0", 0, 0, nil},
95	{"1", 0, 1, nil},
96	{"-1", 0, -1, nil},
97	{"12345", 0, 12345, nil},
98	{"-12345", 0, -12345, nil},
99	{"012345", 0, 012345, nil},
100	{"-012345", 0, -012345, nil},
101	{"0x12345", 0, 0x12345, nil},
102	{"-0X12345", 0, -0x12345, nil},
103	{"12345x", 0, 0, ErrSyntax},
104	{"-12345x", 0, 0, ErrSyntax},
105	{"98765432100", 0, 98765432100, nil},
106	{"-98765432100", 0, -98765432100, nil},
107	{"9223372036854775807", 0, 1<<63 - 1, nil},
108	{"-9223372036854775807", 0, -(1<<63 - 1), nil},
109	{"9223372036854775808", 0, 1<<63 - 1, ErrRange},
110	{"-9223372036854775808", 0, -1 << 63, nil},
111	{"9223372036854775809", 0, 1<<63 - 1, ErrRange},
112	{"-9223372036854775809", 0, -1 << 63, ErrRange},
113
114	// other bases
115	{"g", 17, 16, nil},
116	{"10", 25, 25, nil},
117	{"holycow", 35, (((((17*35+24)*35+21)*35+34)*35+12)*35+24)*35 + 32, nil},
118	{"holycow", 36, (((((17*36+24)*36+21)*36+34)*36+12)*36+24)*36 + 32, nil},
119
120	// base 2
121	{"0", 2, 0, nil},
122	{"-1", 2, -1, nil},
123	{"1010", 2, 10, nil},
124	{"1000000000000000", 2, 1 << 15, nil},
125	{"111111111111111111111111111111111111111111111111111111111111111", 2, 1<<63 - 1, nil},
126	{"1000000000000000000000000000000000000000000000000000000000000000", 2, 1<<63 - 1, ErrRange},
127	{"-1000000000000000000000000000000000000000000000000000000000000000", 2, -1 << 63, nil},
128	{"-1000000000000000000000000000000000000000000000000000000000000001", 2, -1 << 63, ErrRange},
129
130	// base 8
131	{"-10", 8, -8, nil},
132	{"57635436545", 8, 057635436545, nil},
133	{"100000000", 8, 1 << 24, nil},
134
135	// base 16
136	{"10", 16, 16, nil},
137	{"-123456789abcdef", 16, -0x123456789abcdef, nil},
138	{"7fffffffffffffff", 16, 1<<63 - 1, nil},
139}
140
141type atoui32Test struct {
142	in  string
143	out uint32
144	err error
145}
146
147var atoui32tests = []atoui32Test{
148	{"", 0, ErrSyntax},
149	{"0", 0, nil},
150	{"1", 1, nil},
151	{"12345", 12345, nil},
152	{"012345", 12345, nil},
153	{"12345x", 0, ErrSyntax},
154	{"987654321", 987654321, nil},
155	{"4294967295", 1<<32 - 1, nil},
156	{"4294967296", 1<<32 - 1, ErrRange},
157}
158
159type atoi32Test struct {
160	in  string
161	out int32
162	err error
163}
164
165var atoi32tests = []atoi32Test{
166	{"", 0, ErrSyntax},
167	{"0", 0, nil},
168	{"-0", 0, nil},
169	{"1", 1, nil},
170	{"-1", -1, nil},
171	{"12345", 12345, nil},
172	{"-12345", -12345, nil},
173	{"012345", 12345, nil},
174	{"-012345", -12345, nil},
175	{"12345x", 0, ErrSyntax},
176	{"-12345x", 0, ErrSyntax},
177	{"987654321", 987654321, nil},
178	{"-987654321", -987654321, nil},
179	{"2147483647", 1<<31 - 1, nil},
180	{"-2147483647", -(1<<31 - 1), nil},
181	{"2147483648", 1<<31 - 1, ErrRange},
182	{"-2147483648", -1 << 31, nil},
183	{"2147483649", 1<<31 - 1, ErrRange},
184	{"-2147483649", -1 << 31, ErrRange},
185}
186
187type numErrorTest struct {
188	num, want string
189}
190
191var numErrorTests = []numErrorTest{
192	{"0", `strconv.ParseFloat: parsing "0": failed`},
193	{"`", "strconv.ParseFloat: parsing \"`\": failed"},
194	{"1\x00.2", `strconv.ParseFloat: parsing "1\x00.2": failed`},
195}
196
197func init() {
198	// The atoi routines return NumErrors wrapping
199	// the error and the string.  Convert the tables above.
200	for i := range atoui64tests {
201		test := &atoui64tests[i]
202		if test.err != nil {
203			test.err = &NumError{"ParseUint", test.in, test.err}
204		}
205	}
206	for i := range btoui64tests {
207		test := &btoui64tests[i]
208		if test.err != nil {
209			test.err = &NumError{"ParseUint", test.in, test.err}
210		}
211	}
212	for i := range atoi64tests {
213		test := &atoi64tests[i]
214		if test.err != nil {
215			test.err = &NumError{"ParseInt", test.in, test.err}
216		}
217	}
218	for i := range btoi64tests {
219		test := &btoi64tests[i]
220		if test.err != nil {
221			test.err = &NumError{"ParseInt", test.in, test.err}
222		}
223	}
224	for i := range atoui32tests {
225		test := &atoui32tests[i]
226		if test.err != nil {
227			test.err = &NumError{"ParseUint", test.in, test.err}
228		}
229	}
230	for i := range atoi32tests {
231		test := &atoi32tests[i]
232		if test.err != nil {
233			test.err = &NumError{"ParseInt", test.in, test.err}
234		}
235	}
236}
237
238func TestParseUint64(t *testing.T) {
239	for i := range atoui64tests {
240		test := &atoui64tests[i]
241		out, err := ParseUint(test.in, 10, 64)
242		if test.out != out || !reflect.DeepEqual(test.err, err) {
243			t.Errorf("Atoui64(%q) = %v, %v want %v, %v",
244				test.in, out, err, test.out, test.err)
245		}
246	}
247}
248
249func TestParseUint64Base(t *testing.T) {
250	for i := range btoui64tests {
251		test := &btoui64tests[i]
252		out, err := ParseUint(test.in, 0, 64)
253		if test.out != out || !reflect.DeepEqual(test.err, err) {
254			t.Errorf("ParseUint(%q) = %v, %v want %v, %v",
255				test.in, out, err, test.out, test.err)
256		}
257	}
258}
259
260func TestParseInt64(t *testing.T) {
261	for i := range atoi64tests {
262		test := &atoi64tests[i]
263		out, err := ParseInt(test.in, 10, 64)
264		if test.out != out || !reflect.DeepEqual(test.err, err) {
265			t.Errorf("Atoi64(%q) = %v, %v want %v, %v",
266				test.in, out, err, test.out, test.err)
267		}
268	}
269}
270
271func TestParseInt64Base(t *testing.T) {
272	for i := range btoi64tests {
273		test := &btoi64tests[i]
274		out, err := ParseInt(test.in, test.base, 64)
275		if test.out != out || !reflect.DeepEqual(test.err, err) {
276			t.Errorf("ParseInt(%q) = %v, %v want %v, %v",
277				test.in, out, err, test.out, test.err)
278		}
279	}
280}
281
282func TestParseUint(t *testing.T) {
283	switch IntSize {
284	case 32:
285		for i := range atoui32tests {
286			test := &atoui32tests[i]
287			out, err := ParseUint(test.in, 10, 0)
288			if test.out != uint32(out) || !reflect.DeepEqual(test.err, err) {
289				t.Errorf("Atoui(%q) = %v, %v want %v, %v",
290					test.in, out, err, test.out, test.err)
291			}
292		}
293	case 64:
294		for i := range atoui64tests {
295			test := &atoui64tests[i]
296			out, err := ParseUint(test.in, 10, 0)
297			if test.out != uint64(out) || !reflect.DeepEqual(test.err, err) {
298				t.Errorf("Atoui(%q) = %v, %v want %v, %v",
299					test.in, out, err, test.out, test.err)
300			}
301		}
302	}
303}
304
305func TestParseInt(t *testing.T) {
306	switch IntSize {
307	case 32:
308		for i := range atoi32tests {
309			test := &atoi32tests[i]
310			out, err := ParseInt(test.in, 10, 0)
311			if test.out != int32(out) || !reflect.DeepEqual(test.err, err) {
312				t.Errorf("Atoi(%q) = %v, %v want %v, %v",
313					test.in, out, err, test.out, test.err)
314			}
315		}
316	case 64:
317		for i := range atoi64tests {
318			test := &atoi64tests[i]
319			out, err := ParseInt(test.in, 10, 0)
320			if test.out != int64(out) || !reflect.DeepEqual(test.err, err) {
321				t.Errorf("Atoi(%q) = %v, %v want %v, %v",
322					test.in, out, err, test.out, test.err)
323			}
324		}
325	}
326}
327
328func TestNumError(t *testing.T) {
329	for _, test := range numErrorTests {
330		err := &NumError{
331			Func: "ParseFloat",
332			Num:  test.num,
333			Err:  errors.New("failed"),
334		}
335		if got := err.Error(); got != test.want {
336			t.Errorf(`(&NumError{"ParseFloat", %q, "failed"}).Error() = %v, want %v`, test.num, got, test.want)
337		}
338	}
339}
340
341func BenchmarkAtoi(b *testing.B) {
342	for i := 0; i < b.N; i++ {
343		ParseInt("12345678", 10, 0)
344	}
345}
346
347func BenchmarkAtoiNeg(b *testing.B) {
348	for i := 0; i < b.N; i++ {
349		ParseInt("-12345678", 10, 0)
350	}
351}
352
353func BenchmarkAtoi64(b *testing.B) {
354	for i := 0; i < b.N; i++ {
355		ParseInt("12345678901234", 10, 64)
356	}
357}
358
359func BenchmarkAtoi64Neg(b *testing.B) {
360	for i := 0; i < b.N; i++ {
361		ParseInt("-12345678901234", 10, 64)
362	}
363}
364