Source file src/math/big/intconv_test.go

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

View as plain text