// Copyright 2015 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 big import ( "bytes" "fmt" "testing" ) var stringTests = []struct { in string out string base int val int64 ok bool }{ // invalid inputs {in: ""}, {in: "a"}, {in: "z"}, {in: "+"}, {in: "-"}, {in: "0b"}, {in: "0o"}, {in: "0x"}, {in: "0y"}, {in: "2", base: 2}, {in: "0b2", base: 0}, {in: "08"}, {in: "8", base: 8}, {in: "0xg", base: 0}, {in: "g", base: 16}, // invalid inputs with separators // (smoke tests only - a comprehensive set of tests is in natconv_test.go) {in: "_"}, {in: "0_"}, {in: "_0"}, {in: "-1__0"}, {in: "0x10_"}, {in: "1_000", base: 10}, // separators are not permitted for bases != 0 {in: "d_e_a_d", base: 16}, // valid inputs {"0", "0", 0, 0, true}, {"0", "0", 10, 0, true}, {"0", "0", 16, 0, true}, {"+0", "0", 0, 0, true}, {"-0", "0", 0, 0, true}, {"10", "10", 0, 10, true}, {"10", "10", 10, 10, true}, {"10", "10", 16, 16, true}, {"-10", "-10", 16, -16, true}, {"+10", "10", 16, 16, true}, {"0b10", "2", 0, 2, true}, {"0o10", "8", 0, 8, true}, {"0x10", "16", 0, 16, true}, {in: "0x10", base: 16}, {"-0x10", "-16", 0, -16, true}, {"+0x10", "16", 0, 16, true}, {"00", "0", 0, 0, true}, {"0", "0", 8, 0, true}, {"07", "7", 0, 7, true}, {"7", "7", 8, 7, true}, {"023", "19", 0, 19, true}, {"23", "23", 8, 19, true}, {"cafebabe", "cafebabe", 16, 0xcafebabe, true}, {"0b0", "0", 0, 0, true}, {"-111", "-111", 2, -7, true}, {"-0b111", "-7", 0, -7, true}, {"0b1001010111", "599", 0, 0x257, true}, {"1001010111", "1001010111", 2, 0x257, true}, {"A", "a", 36, 10, true}, {"A", "A", 37, 36, true}, {"ABCXYZ", "abcxyz", 36, 623741435, true}, {"ABCXYZ", "ABCXYZ", 62, 33536793425, true}, // valid input with separators // (smoke tests only - a comprehensive set of tests is in natconv_test.go) {"1_000", "1000", 0, 1000, true}, {"0b_1010", "10", 0, 10, true}, {"+0o_660", "432", 0, 0660, true}, {"-0xF00D_1E", "-15731998", 0, -0xf00d1e, true}, } func TestIntText(t *testing.T) { z := new(Int) for _, test := range stringTests { if !test.ok { continue } _, ok := z.SetString(test.in, test.base) if !ok { t.Errorf("%v: failed to parse", test) continue } base := test.base if base == 0 { base = 10 } if got := z.Text(base); got != test.out { t.Errorf("%v: got %s; want %s", test, got, test.out) } } } func TestAppendText(t *testing.T) { z := new(Int) var buf []byte for _, test := range stringTests { if !test.ok { continue } _, ok := z.SetString(test.in, test.base) if !ok { t.Errorf("%v: failed to parse", test) continue } base := test.base if base == 0 { base = 10 } i := len(buf) buf = z.Append(buf, base) if got := string(buf[i:]); got != test.out { t.Errorf("%v: got %s; want %s", test, got, test.out) } } } func format(base int) string { switch base { case 2: return "%b" case 8: return "%o" case 16: return "%x" } return "%d" } func TestGetString(t *testing.T) { z := new(Int) for i, test := range stringTests { if !test.ok { continue } z.SetInt64(test.val) if test.base == 10 { if got := z.String(); got != test.out { t.Errorf("#%da got %s; want %s", i, got, test.out) } } f := format(test.base) got := fmt.Sprintf(f, z) if f == "%d" { if got != fmt.Sprintf("%d", test.val) { t.Errorf("#%db got %s; want %d", i, got, test.val) } } else { if got != test.out { t.Errorf("#%dc got %s; want %s", i, got, test.out) } } } } func TestSetString(t *testing.T) { tmp := new(Int) for i, test := range stringTests { // initialize to a non-zero value so that issues with parsing // 0 are detected tmp.SetInt64(1234567890) n1, ok1 := new(Int).SetString(test.in, test.base) n2, ok2 := tmp.SetString(test.in, test.base) expected := NewInt(test.val) if ok1 != test.ok || ok2 != test.ok { t.Errorf("#%d (input '%s') ok incorrect (should be %t)", i, test.in, test.ok) continue } if !ok1 { if n1 != nil { t.Errorf("#%d (input '%s') n1 != nil", i, test.in) } continue } if !ok2 { if n2 != nil { t.Errorf("#%d (input '%s') n2 != nil", i, test.in) } continue } if ok1 && !isNormalized(n1) { t.Errorf("#%d (input '%s'): %v is not normalized", i, test.in, *n1) } if ok2 && !isNormalized(n2) { t.Errorf("#%d (input '%s'): %v is not normalized", i, test.in, *n2) } if n1.Cmp(expected) != 0 { t.Errorf("#%d (input '%s') got: %s want: %d", i, test.in, n1, test.val) } if n2.Cmp(expected) != 0 { t.Errorf("#%d (input '%s') got: %s want: %d", i, test.in, n2, test.val) } } } var formatTests = []struct { input string format string output string }{ {"", "%x", ""}, {"", "%#x", ""}, {"", "%#y", "%!y(big.Int=)"}, {"10", "%b", "1010"}, {"10", "%o", "12"}, {"10", "%d", "10"}, {"10", "%v", "10"}, {"10", "%x", "a"}, {"10", "%X", "A"}, {"-10", "%X", "-A"}, {"10", "%y", "%!y(big.Int=10)"}, {"-10", "%y", "%!y(big.Int=-10)"}, {"10", "%#b", "0b1010"}, {"10", "%#o", "012"}, {"10", "%O", "0o12"}, {"-10", "%#b", "-0b1010"}, {"-10", "%#o", "-012"}, {"-10", "%O", "-0o12"}, {"10", "%#d", "10"}, {"10", "%#v", "10"}, {"10", "%#x", "0xa"}, {"10", "%#X", "0XA"}, {"-10", "%#X", "-0XA"}, {"10", "%#y", "%!y(big.Int=10)"}, {"-10", "%#y", "%!y(big.Int=-10)"}, {"1234", "%d", "1234"}, {"1234", "%3d", "1234"}, {"1234", "%4d", "1234"}, {"-1234", "%d", "-1234"}, {"1234", "% 5d", " 1234"}, {"1234", "%+5d", "+1234"}, {"1234", "%-5d", "1234 "}, {"1234", "%x", "4d2"}, {"1234", "%X", "4D2"}, {"-1234", "%3x", "-4d2"}, {"-1234", "%4x", "-4d2"}, {"-1234", "%5x", " -4d2"}, {"-1234", "%-5x", "-4d2 "}, {"1234", "%03d", "1234"}, {"1234", "%04d", "1234"}, {"1234", "%05d", "01234"}, {"1234", "%06d", "001234"}, {"-1234", "%06d", "-01234"}, {"1234", "%+06d", "+01234"}, {"1234", "% 06d", " 01234"}, {"1234", "%-6d", "1234 "}, {"1234", "%-06d", "1234 "}, {"-1234", "%-06d", "-1234 "}, {"1234", "%.3d", "1234"}, {"1234", "%.4d", "1234"}, {"1234", "%.5d", "01234"}, {"1234", "%.6d", "001234"}, {"-1234", "%.3d", "-1234"}, {"-1234", "%.4d", "-1234"}, {"-1234", "%.5d", "-01234"}, {"-1234", "%.6d", "-001234"}, {"1234", "%8.3d", " 1234"}, {"1234", "%8.4d", " 1234"}, {"1234", "%8.5d", " 01234"}, {"1234", "%8.6d", " 001234"}, {"-1234", "%8.3d", " -1234"}, {"-1234", "%8.4d", " -1234"}, {"-1234", "%8.5d", " -01234"}, {"-1234", "%8.6d", " -001234"}, {"1234", "%+8.3d", " +1234"}, {"1234", "%+8.4d", " +1234"}, {"1234", "%+8.5d", " +01234"}, {"1234", "%+8.6d", " +001234"}, {"-1234", "%+8.3d", " -1234"}, {"-1234", "%+8.4d", " -1234"}, {"-1234", "%+8.5d", " -01234"}, {"-1234", "%+8.6d", " -001234"}, {"1234", "% 8.3d", " 1234"}, {"1234", "% 8.4d", " 1234"}, {"1234", "% 8.5d", " 01234"}, {"1234", "% 8.6d", " 001234"}, {"-1234", "% 8.3d", " -1234"}, {"-1234", "% 8.4d", " -1234"}, {"-1234", "% 8.5d", " -01234"}, {"-1234", "% 8.6d", " -001234"}, {"1234", "%.3x", "4d2"}, {"1234", "%.4x", "04d2"}, {"1234", "%.5x", "004d2"}, {"1234", "%.6x", "0004d2"}, {"-1234", "%.3x", "-4d2"}, {"-1234", "%.4x", "-04d2"}, {"-1234", "%.5x", "-004d2"}, {"-1234", "%.6x", "-0004d2"}, {"1234", "%8.3x", " 4d2"}, {"1234", "%8.4x", " 04d2"}, {"1234", "%8.5x", " 004d2"}, {"1234", "%8.6x", " 0004d2"}, {"-1234", "%8.3x", " -4d2"}, {"-1234", "%8.4x", " -04d2"}, {"-1234", "%8.5x", " -004d2"}, {"-1234", "%8.6x", " -0004d2"}, {"1234", "%+8.3x", " +4d2"}, {"1234", "%+8.4x", " +04d2"}, {"1234", "%+8.5x", " +004d2"}, {"1234", "%+8.6x", " +0004d2"}, {"-1234", "%+8.3x", " -4d2"}, {"-1234", "%+8.4x", " -04d2"}, {"-1234", "%+8.5x", " -004d2"}, {"-1234", "%+8.6x", " -0004d2"}, {"1234", "% 8.3x", " 4d2"}, {"1234", "% 8.4x", " 04d2"}, {"1234", "% 8.5x", " 004d2"}, {"1234", "% 8.6x", " 0004d2"}, {"1234", "% 8.7x", " 00004d2"}, {"1234", "% 8.8x", " 000004d2"}, {"-1234", "% 8.3x", " -4d2"}, {"-1234", "% 8.4x", " -04d2"}, {"-1234", "% 8.5x", " -004d2"}, {"-1234", "% 8.6x", " -0004d2"}, {"-1234", "% 8.7x", "-00004d2"}, {"-1234", "% 8.8x", "-000004d2"}, {"1234", "%-8.3d", "1234 "}, {"1234", "%-8.4d", "1234 "}, {"1234", "%-8.5d", "01234 "}, {"1234", "%-8.6d", "001234 "}, {"1234", "%-8.7d", "0001234 "}, {"1234", "%-8.8d", "00001234"}, {"-1234", "%-8.3d", "-1234 "}, {"-1234", "%-8.4d", "-1234 "}, {"-1234", "%-8.5d", "-01234 "}, {"-1234", "%-8.6d", "-001234 "}, {"-1234", "%-8.7d", "-0001234"}, {"-1234", "%-8.8d", "-00001234"}, {"16777215", "%b", "111111111111111111111111"}, // 2**24 - 1 {"0", "%.d", ""}, {"0", "%.0d", ""}, {"0", "%3.d", ""}, } func TestFormat(t *testing.T) { for i, test := range formatTests { var x *Int if test.input != "" { var ok bool x, ok = new(Int).SetString(test.input, 0) if !ok { t.Errorf("#%d failed reading input %s", i, test.input) } } output := fmt.Sprintf(test.format, x) if output != test.output { t.Errorf("#%d got %q; want %q, {%q, %q, %q}", i, output, test.output, test.input, test.format, test.output) } } } var scanTests = []struct { input string format string output string remaining int }{ {"1010", "%b", "10", 0}, {"0b1010", "%v", "10", 0}, {"12", "%o", "10", 0}, {"012", "%v", "10", 0}, {"10", "%d", "10", 0}, {"10", "%v", "10", 0}, {"a", "%x", "10", 0}, {"0xa", "%v", "10", 0}, {"A", "%X", "10", 0}, {"-A", "%X", "-10", 0}, {"+0b1011001", "%v", "89", 0}, {"0xA", "%v", "10", 0}, {"0 ", "%v", "0", 1}, {"2+3", "%v", "2", 2}, {"0XABC 12", "%v", "2748", 3}, } func TestScan(t *testing.T) { var buf bytes.Buffer for i, test := range scanTests { x := new(Int) buf.Reset() buf.WriteString(test.input) if _, err := fmt.Fscanf(&buf, test.format, x); err != nil { t.Errorf("#%d error: %s", i, err) } if x.String() != test.output { t.Errorf("#%d got %s; want %s", i, x.String(), test.output) } if buf.Len() != test.remaining { t.Errorf("#%d got %d bytes remaining; want %d", i, buf.Len(), test.remaining) } } }