1// Copyright 2015 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 big
6
7import (
8	"bytes"
9	"fmt"
10	"testing"
11)
12
13var stringTests = []struct {
14	in   string
15	out  string
16	base int
17	val  int64
18	ok   bool
19}{
20	// invalid inputs
21	{in: ""},
22	{in: "a"},
23	{in: "z"},
24	{in: "+"},
25	{in: "-"},
26	{in: "0b"},
27	{in: "0o"},
28	{in: "0x"},
29	{in: "0y"},
30	{in: "2", base: 2},
31	{in: "0b2", base: 0},
32	{in: "08"},
33	{in: "8", base: 8},
34	{in: "0xg", base: 0},
35	{in: "g", base: 16},
36
37	// invalid inputs with separators
38	// (smoke tests only - a comprehensive set of tests is in natconv_test.go)
39	{in: "_"},
40	{in: "0_"},
41	{in: "_0"},
42	{in: "-1__0"},
43	{in: "0x10_"},
44	{in: "1_000", base: 10}, // separators are not permitted for bases != 0
45	{in: "d_e_a_d", base: 16},
46
47	// valid inputs
48	{"0", "0", 0, 0, true},
49	{"0", "0", 10, 0, true},
50	{"0", "0", 16, 0, true},
51	{"+0", "0", 0, 0, true},
52	{"-0", "0", 0, 0, true},
53	{"10", "10", 0, 10, true},
54	{"10", "10", 10, 10, true},
55	{"10", "10", 16, 16, true},
56	{"-10", "-10", 16, -16, true},
57	{"+10", "10", 16, 16, true},
58	{"0b10", "2", 0, 2, true},
59	{"0o10", "8", 0, 8, true},
60	{"0x10", "16", 0, 16, true},
61	{in: "0x10", base: 16},
62	{"-0x10", "-16", 0, -16, true},
63	{"+0x10", "16", 0, 16, true},
64	{"00", "0", 0, 0, true},
65	{"0", "0", 8, 0, true},
66	{"07", "7", 0, 7, true},
67	{"7", "7", 8, 7, true},
68	{"023", "19", 0, 19, true},
69	{"23", "23", 8, 19, true},
70	{"cafebabe", "cafebabe", 16, 0xcafebabe, true},
71	{"0b0", "0", 0, 0, true},
72	{"-111", "-111", 2, -7, true},
73	{"-0b111", "-7", 0, -7, true},
74	{"0b1001010111", "599", 0, 0x257, true},
75	{"1001010111", "1001010111", 2, 0x257, true},
76	{"A", "a", 36, 10, true},
77	{"A", "A", 37, 36, true},
78	{"ABCXYZ", "abcxyz", 36, 623741435, true},
79	{"ABCXYZ", "ABCXYZ", 62, 33536793425, true},
80
81	// valid input with separators
82	// (smoke tests only - a comprehensive set of tests is in natconv_test.go)
83	{"1_000", "1000", 0, 1000, true},
84	{"0b_1010", "10", 0, 10, true},
85	{"+0o_660", "432", 0, 0660, true},
86	{"-0xF00D_1E", "-15731998", 0, -0xf00d1e, true},
87}
88
89func TestIntText(t *testing.T) {
90	z := new(Int)
91	for _, test := range stringTests {
92		if !test.ok {
93			continue
94		}
95
96		_, ok := z.SetString(test.in, test.base)
97		if !ok {
98			t.Errorf("%v: failed to parse", test)
99			continue
100		}
101
102		base := test.base
103		if base == 0 {
104			base = 10
105		}
106
107		if got := z.Text(base); got != test.out {
108			t.Errorf("%v: got %s; want %s", test, got, test.out)
109		}
110	}
111}
112
113func TestAppendText(t *testing.T) {
114	z := new(Int)
115	var buf []byte
116	for _, test := range stringTests {
117		if !test.ok {
118			continue
119		}
120
121		_, ok := z.SetString(test.in, test.base)
122		if !ok {
123			t.Errorf("%v: failed to parse", test)
124			continue
125		}
126
127		base := test.base
128		if base == 0 {
129			base = 10
130		}
131
132		i := len(buf)
133		buf = z.Append(buf, base)
134		if got := string(buf[i:]); got != test.out {
135			t.Errorf("%v: got %s; want %s", test, got, test.out)
136		}
137	}
138}
139
140func format(base int) string {
141	switch base {
142	case 2:
143		return "%b"
144	case 8:
145		return "%o"
146	case 16:
147		return "%x"
148	}
149	return "%d"
150}
151
152func TestGetString(t *testing.T) {
153	z := new(Int)
154	for i, test := range stringTests {
155		if !test.ok {
156			continue
157		}
158		z.SetInt64(test.val)
159
160		if test.base == 10 {
161			if got := z.String(); got != test.out {
162				t.Errorf("#%da got %s; want %s", i, got, test.out)
163			}
164		}
165
166		f := format(test.base)
167		got := fmt.Sprintf(f, z)
168		if f == "%d" {
169			if got != fmt.Sprintf("%d", test.val) {
170				t.Errorf("#%db got %s; want %d", i, got, test.val)
171			}
172		} else {
173			if got != test.out {
174				t.Errorf("#%dc got %s; want %s", i, got, test.out)
175			}
176		}
177	}
178}
179
180func TestSetString(t *testing.T) {
181	tmp := new(Int)
182	for i, test := range stringTests {
183		// initialize to a non-zero value so that issues with parsing
184		// 0 are detected
185		tmp.SetInt64(1234567890)
186		n1, ok1 := new(Int).SetString(test.in, test.base)
187		n2, ok2 := tmp.SetString(test.in, test.base)
188		expected := NewInt(test.val)
189		if ok1 != test.ok || ok2 != test.ok {
190			t.Errorf("#%d (input '%s') ok incorrect (should be %t)", i, test.in, test.ok)
191			continue
192		}
193		if !ok1 {
194			if n1 != nil {
195				t.Errorf("#%d (input '%s') n1 != nil", i, test.in)
196			}
197			continue
198		}
199		if !ok2 {
200			if n2 != nil {
201				t.Errorf("#%d (input '%s') n2 != nil", i, test.in)
202			}
203			continue
204		}
205
206		if ok1 && !isNormalized(n1) {
207			t.Errorf("#%d (input '%s'): %v is not normalized", i, test.in, *n1)
208		}
209		if ok2 && !isNormalized(n2) {
210			t.Errorf("#%d (input '%s'): %v is not normalized", i, test.in, *n2)
211		}
212
213		if n1.Cmp(expected) != 0 {
214			t.Errorf("#%d (input '%s') got: %s want: %d", i, test.in, n1, test.val)
215		}
216		if n2.Cmp(expected) != 0 {
217			t.Errorf("#%d (input '%s') got: %s want: %d", i, test.in, n2, test.val)
218		}
219	}
220}
221
222var formatTests = []struct {
223	input  string
224	format string
225	output string
226}{
227	{"<nil>", "%x", "<nil>"},
228	{"<nil>", "%#x", "<nil>"},
229	{"<nil>", "%#y", "%!y(big.Int=<nil>)"},
230
231	{"10", "%b", "1010"},
232	{"10", "%o", "12"},
233	{"10", "%d", "10"},
234	{"10", "%v", "10"},
235	{"10", "%x", "a"},
236	{"10", "%X", "A"},
237	{"-10", "%X", "-A"},
238	{"10", "%y", "%!y(big.Int=10)"},
239	{"-10", "%y", "%!y(big.Int=-10)"},
240
241	{"10", "%#b", "0b1010"},
242	{"10", "%#o", "012"},
243	{"10", "%O", "0o12"},
244	{"-10", "%#b", "-0b1010"},
245	{"-10", "%#o", "-012"},
246	{"-10", "%O", "-0o12"},
247	{"10", "%#d", "10"},
248	{"10", "%#v", "10"},
249	{"10", "%#x", "0xa"},
250	{"10", "%#X", "0XA"},
251	{"-10", "%#X", "-0XA"},
252	{"10", "%#y", "%!y(big.Int=10)"},
253	{"-10", "%#y", "%!y(big.Int=-10)"},
254
255	{"1234", "%d", "1234"},
256	{"1234", "%3d", "1234"},
257	{"1234", "%4d", "1234"},
258	{"-1234", "%d", "-1234"},
259	{"1234", "% 5d", " 1234"},
260	{"1234", "%+5d", "+1234"},
261	{"1234", "%-5d", "1234 "},
262	{"1234", "%x", "4d2"},
263	{"1234", "%X", "4D2"},
264	{"-1234", "%3x", "-4d2"},
265	{"-1234", "%4x", "-4d2"},
266	{"-1234", "%5x", " -4d2"},
267	{"-1234", "%-5x", "-4d2 "},
268	{"1234", "%03d", "1234"},
269	{"1234", "%04d", "1234"},
270	{"1234", "%05d", "01234"},
271	{"1234", "%06d", "001234"},
272	{"-1234", "%06d", "-01234"},
273	{"1234", "%+06d", "+01234"},
274	{"1234", "% 06d", " 01234"},
275	{"1234", "%-6d", "1234  "},
276	{"1234", "%-06d", "1234  "},
277	{"-1234", "%-06d", "-1234 "},
278
279	{"1234", "%.3d", "1234"},
280	{"1234", "%.4d", "1234"},
281	{"1234", "%.5d", "01234"},
282	{"1234", "%.6d", "001234"},
283	{"-1234", "%.3d", "-1234"},
284	{"-1234", "%.4d", "-1234"},
285	{"-1234", "%.5d", "-01234"},
286	{"-1234", "%.6d", "-001234"},
287
288	{"1234", "%8.3d", "    1234"},
289	{"1234", "%8.4d", "    1234"},
290	{"1234", "%8.5d", "   01234"},
291	{"1234", "%8.6d", "  001234"},
292	{"-1234", "%8.3d", "   -1234"},
293	{"-1234", "%8.4d", "   -1234"},
294	{"-1234", "%8.5d", "  -01234"},
295	{"-1234", "%8.6d", " -001234"},
296
297	{"1234", "%+8.3d", "   +1234"},
298	{"1234", "%+8.4d", "   +1234"},
299	{"1234", "%+8.5d", "  +01234"},
300	{"1234", "%+8.6d", " +001234"},
301	{"-1234", "%+8.3d", "   -1234"},
302	{"-1234", "%+8.4d", "   -1234"},
303	{"-1234", "%+8.5d", "  -01234"},
304	{"-1234", "%+8.6d", " -001234"},
305
306	{"1234", "% 8.3d", "    1234"},
307	{"1234", "% 8.4d", "    1234"},
308	{"1234", "% 8.5d", "   01234"},
309	{"1234", "% 8.6d", "  001234"},
310	{"-1234", "% 8.3d", "   -1234"},
311	{"-1234", "% 8.4d", "   -1234"},
312	{"-1234", "% 8.5d", "  -01234"},
313	{"-1234", "% 8.6d", " -001234"},
314
315	{"1234", "%.3x", "4d2"},
316	{"1234", "%.4x", "04d2"},
317	{"1234", "%.5x", "004d2"},
318	{"1234", "%.6x", "0004d2"},
319	{"-1234", "%.3x", "-4d2"},
320	{"-1234", "%.4x", "-04d2"},
321	{"-1234", "%.5x", "-004d2"},
322	{"-1234", "%.6x", "-0004d2"},
323
324	{"1234", "%8.3x", "     4d2"},
325	{"1234", "%8.4x", "    04d2"},
326	{"1234", "%8.5x", "   004d2"},
327	{"1234", "%8.6x", "  0004d2"},
328	{"-1234", "%8.3x", "    -4d2"},
329	{"-1234", "%8.4x", "   -04d2"},
330	{"-1234", "%8.5x", "  -004d2"},
331	{"-1234", "%8.6x", " -0004d2"},
332
333	{"1234", "%+8.3x", "    +4d2"},
334	{"1234", "%+8.4x", "   +04d2"},
335	{"1234", "%+8.5x", "  +004d2"},
336	{"1234", "%+8.6x", " +0004d2"},
337	{"-1234", "%+8.3x", "    -4d2"},
338	{"-1234", "%+8.4x", "   -04d2"},
339	{"-1234", "%+8.5x", "  -004d2"},
340	{"-1234", "%+8.6x", " -0004d2"},
341
342	{"1234", "% 8.3x", "     4d2"},
343	{"1234", "% 8.4x", "    04d2"},
344	{"1234", "% 8.5x", "   004d2"},
345	{"1234", "% 8.6x", "  0004d2"},
346	{"1234", "% 8.7x", " 00004d2"},
347	{"1234", "% 8.8x", " 000004d2"},
348	{"-1234", "% 8.3x", "    -4d2"},
349	{"-1234", "% 8.4x", "   -04d2"},
350	{"-1234", "% 8.5x", "  -004d2"},
351	{"-1234", "% 8.6x", " -0004d2"},
352	{"-1234", "% 8.7x", "-00004d2"},
353	{"-1234", "% 8.8x", "-000004d2"},
354
355	{"1234", "%-8.3d", "1234    "},
356	{"1234", "%-8.4d", "1234    "},
357	{"1234", "%-8.5d", "01234   "},
358	{"1234", "%-8.6d", "001234  "},
359	{"1234", "%-8.7d", "0001234 "},
360	{"1234", "%-8.8d", "00001234"},
361	{"-1234", "%-8.3d", "-1234   "},
362	{"-1234", "%-8.4d", "-1234   "},
363	{"-1234", "%-8.5d", "-01234  "},
364	{"-1234", "%-8.6d", "-001234 "},
365	{"-1234", "%-8.7d", "-0001234"},
366	{"-1234", "%-8.8d", "-00001234"},
367
368	{"16777215", "%b", "111111111111111111111111"}, // 2**24 - 1
369
370	{"0", "%.d", ""},
371	{"0", "%.0d", ""},
372	{"0", "%3.d", ""},
373}
374
375func TestFormat(t *testing.T) {
376	for i, test := range formatTests {
377		var x *Int
378		if test.input != "<nil>" {
379			var ok bool
380			x, ok = new(Int).SetString(test.input, 0)
381			if !ok {
382				t.Errorf("#%d failed reading input %s", i, test.input)
383			}
384		}
385		output := fmt.Sprintf(test.format, x)
386		if output != test.output {
387			t.Errorf("#%d got %q; want %q, {%q, %q, %q}", i, output, test.output, test.input, test.format, test.output)
388		}
389	}
390}
391
392var scanTests = []struct {
393	input     string
394	format    string
395	output    string
396	remaining int
397}{
398	{"1010", "%b", "10", 0},
399	{"0b1010", "%v", "10", 0},
400	{"12", "%o", "10", 0},
401	{"012", "%v", "10", 0},
402	{"10", "%d", "10", 0},
403	{"10", "%v", "10", 0},
404	{"a", "%x", "10", 0},
405	{"0xa", "%v", "10", 0},
406	{"A", "%X", "10", 0},
407	{"-A", "%X", "-10", 0},
408	{"+0b1011001", "%v", "89", 0},
409	{"0xA", "%v", "10", 0},
410	{"0 ", "%v", "0", 1},
411	{"2+3", "%v", "2", 2},
412	{"0XABC 12", "%v", "2748", 3},
413}
414
415func TestScan(t *testing.T) {
416	var buf bytes.Buffer
417	for i, test := range scanTests {
418		x := new(Int)
419		buf.Reset()
420		buf.WriteString(test.input)
421		if _, err := fmt.Fscanf(&buf, test.format, x); err != nil {
422			t.Errorf("#%d error: %s", i, err)
423		}
424		if x.String() != test.output {
425			t.Errorf("#%d got %s; want %s", i, x.String(), test.output)
426		}
427		if buf.Len() != test.remaining {
428			t.Errorf("#%d got %d bytes remaining; want %d", i, buf.Len(), test.remaining)
429		}
430	}
431}
432