Home | History | Annotate | Download | only in strconv
      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 
      5 package strconv_test
      6 
      7 import (
      8 	"errors"
      9 	"fmt"
     10 	"reflect"
     11 	. "strconv"
     12 	"testing"
     13 )
     14 
     15 type parseUint64Test struct {
     16 	in  string
     17 	out uint64
     18 	err error
     19 }
     20 
     21 var parseUint64Tests = []parseUint64Test{
     22 	{"", 0, ErrSyntax},
     23 	{"0", 0, nil},
     24 	{"1", 1, nil},
     25 	{"12345", 12345, nil},
     26 	{"012345", 12345, nil},
     27 	{"12345x", 0, ErrSyntax},
     28 	{"98765432100", 98765432100, nil},
     29 	{"18446744073709551615", 1<<64 - 1, nil},
     30 	{"18446744073709551616", 1<<64 - 1, ErrRange},
     31 	{"18446744073709551620", 1<<64 - 1, ErrRange},
     32 }
     33 
     34 type parseUint64BaseTest struct {
     35 	in   string
     36 	base int
     37 	out  uint64
     38 	err  error
     39 }
     40 
     41 var parseUint64BaseTests = []parseUint64BaseTest{
     42 	{"", 0, 0, ErrSyntax},
     43 	{"0", 0, 0, nil},
     44 	{"0x", 0, 0, ErrSyntax},
     45 	{"0X", 0, 0, ErrSyntax},
     46 	{"1", 0, 1, nil},
     47 	{"12345", 0, 12345, nil},
     48 	{"012345", 0, 012345, nil},
     49 	{"0x12345", 0, 0x12345, nil},
     50 	{"0X12345", 0, 0x12345, nil},
     51 	{"12345x", 0, 0, ErrSyntax},
     52 	{"0xabcdefg123", 0, 0, ErrSyntax},
     53 	{"123456789abc", 0, 0, ErrSyntax},
     54 	{"98765432100", 0, 98765432100, nil},
     55 	{"18446744073709551615", 0, 1<<64 - 1, nil},
     56 	{"18446744073709551616", 0, 1<<64 - 1, ErrRange},
     57 	{"18446744073709551620", 0, 1<<64 - 1, ErrRange},
     58 	{"0xFFFFFFFFFFFFFFFF", 0, 1<<64 - 1, nil},
     59 	{"0x10000000000000000", 0, 1<<64 - 1, ErrRange},
     60 	{"01777777777777777777777", 0, 1<<64 - 1, nil},
     61 	{"01777777777777777777778", 0, 0, ErrSyntax},
     62 	{"02000000000000000000000", 0, 1<<64 - 1, ErrRange},
     63 	{"0200000000000000000000", 0, 1 << 61, nil},
     64 }
     65 
     66 type parseInt64Test struct {
     67 	in  string
     68 	out int64
     69 	err error
     70 }
     71 
     72 var parseInt64Tests = []parseInt64Test{
     73 	{"", 0, ErrSyntax},
     74 	{"0", 0, nil},
     75 	{"-0", 0, nil},
     76 	{"1", 1, nil},
     77 	{"-1", -1, nil},
     78 	{"12345", 12345, nil},
     79 	{"-12345", -12345, nil},
     80 	{"012345", 12345, nil},
     81 	{"-012345", -12345, nil},
     82 	{"98765432100", 98765432100, nil},
     83 	{"-98765432100", -98765432100, nil},
     84 	{"9223372036854775807", 1<<63 - 1, nil},
     85 	{"-9223372036854775807", -(1<<63 - 1), nil},
     86 	{"9223372036854775808", 1<<63 - 1, ErrRange},
     87 	{"-9223372036854775808", -1 << 63, nil},
     88 	{"9223372036854775809", 1<<63 - 1, ErrRange},
     89 	{"-9223372036854775809", -1 << 63, ErrRange},
     90 }
     91 
     92 type parseInt64BaseTest struct {
     93 	in   string
     94 	base int
     95 	out  int64
     96 	err  error
     97 }
     98 
     99 var parseInt64BaseTests = []parseInt64BaseTest{
    100 	{"", 0, 0, ErrSyntax},
    101 	{"0", 0, 0, nil},
    102 	{"-0", 0, 0, nil},
    103 	{"1", 0, 1, nil},
    104 	{"-1", 0, -1, nil},
    105 	{"12345", 0, 12345, nil},
    106 	{"-12345", 0, -12345, nil},
    107 	{"012345", 0, 012345, nil},
    108 	{"-012345", 0, -012345, nil},
    109 	{"0x12345", 0, 0x12345, nil},
    110 	{"-0X12345", 0, -0x12345, nil},
    111 	{"12345x", 0, 0, ErrSyntax},
    112 	{"-12345x", 0, 0, ErrSyntax},
    113 	{"98765432100", 0, 98765432100, nil},
    114 	{"-98765432100", 0, -98765432100, nil},
    115 	{"9223372036854775807", 0, 1<<63 - 1, nil},
    116 	{"-9223372036854775807", 0, -(1<<63 - 1), nil},
    117 	{"9223372036854775808", 0, 1<<63 - 1, ErrRange},
    118 	{"-9223372036854775808", 0, -1 << 63, nil},
    119 	{"9223372036854775809", 0, 1<<63 - 1, ErrRange},
    120 	{"-9223372036854775809", 0, -1 << 63, ErrRange},
    121 
    122 	// other bases
    123 	{"g", 17, 16, nil},
    124 	{"10", 25, 25, nil},
    125 	{"holycow", 35, (((((17*35+24)*35+21)*35+34)*35+12)*35+24)*35 + 32, nil},
    126 	{"holycow", 36, (((((17*36+24)*36+21)*36+34)*36+12)*36+24)*36 + 32, nil},
    127 
    128 	// base 2
    129 	{"0", 2, 0, nil},
    130 	{"-1", 2, -1, nil},
    131 	{"1010", 2, 10, nil},
    132 	{"1000000000000000", 2, 1 << 15, nil},
    133 	{"111111111111111111111111111111111111111111111111111111111111111", 2, 1<<63 - 1, nil},
    134 	{"1000000000000000000000000000000000000000000000000000000000000000", 2, 1<<63 - 1, ErrRange},
    135 	{"-1000000000000000000000000000000000000000000000000000000000000000", 2, -1 << 63, nil},
    136 	{"-1000000000000000000000000000000000000000000000000000000000000001", 2, -1 << 63, ErrRange},
    137 
    138 	// base 8
    139 	{"-10", 8, -8, nil},
    140 	{"57635436545", 8, 057635436545, nil},
    141 	{"100000000", 8, 1 << 24, nil},
    142 
    143 	// base 16
    144 	{"10", 16, 16, nil},
    145 	{"-123456789abcdef", 16, -0x123456789abcdef, nil},
    146 	{"7fffffffffffffff", 16, 1<<63 - 1, nil},
    147 }
    148 
    149 type parseUint32Test struct {
    150 	in  string
    151 	out uint32
    152 	err error
    153 }
    154 
    155 var parseUint32Tests = []parseUint32Test{
    156 	{"", 0, ErrSyntax},
    157 	{"0", 0, nil},
    158 	{"1", 1, nil},
    159 	{"12345", 12345, nil},
    160 	{"012345", 12345, nil},
    161 	{"12345x", 0, ErrSyntax},
    162 	{"987654321", 987654321, nil},
    163 	{"4294967295", 1<<32 - 1, nil},
    164 	{"4294967296", 1<<32 - 1, ErrRange},
    165 }
    166 
    167 type parseInt32Test struct {
    168 	in  string
    169 	out int32
    170 	err error
    171 }
    172 
    173 var parseInt32Tests = []parseInt32Test{
    174 	{"", 0, ErrSyntax},
    175 	{"0", 0, nil},
    176 	{"-0", 0, nil},
    177 	{"1", 1, nil},
    178 	{"-1", -1, nil},
    179 	{"12345", 12345, nil},
    180 	{"-12345", -12345, nil},
    181 	{"012345", 12345, nil},
    182 	{"-012345", -12345, nil},
    183 	{"12345x", 0, ErrSyntax},
    184 	{"-12345x", 0, ErrSyntax},
    185 	{"987654321", 987654321, nil},
    186 	{"-987654321", -987654321, nil},
    187 	{"2147483647", 1<<31 - 1, nil},
    188 	{"-2147483647", -(1<<31 - 1), nil},
    189 	{"2147483648", 1<<31 - 1, ErrRange},
    190 	{"-2147483648", -1 << 31, nil},
    191 	{"2147483649", 1<<31 - 1, ErrRange},
    192 	{"-2147483649", -1 << 31, ErrRange},
    193 }
    194 
    195 type numErrorTest struct {
    196 	num, want string
    197 }
    198 
    199 var numErrorTests = []numErrorTest{
    200 	{"0", `strconv.ParseFloat: parsing "0": failed`},
    201 	{"`", "strconv.ParseFloat: parsing \"`\": failed"},
    202 	{"1\x00.2", `strconv.ParseFloat: parsing "1\x00.2": failed`},
    203 }
    204 
    205 func init() {
    206 	// The parse routines return NumErrors wrapping
    207 	// the error and the string. Convert the tables above.
    208 	for i := range parseUint64Tests {
    209 		test := &parseUint64Tests[i]
    210 		if test.err != nil {
    211 			test.err = &NumError{"ParseUint", test.in, test.err}
    212 		}
    213 	}
    214 	for i := range parseUint64BaseTests {
    215 		test := &parseUint64BaseTests[i]
    216 		if test.err != nil {
    217 			test.err = &NumError{"ParseUint", test.in, test.err}
    218 		}
    219 	}
    220 	for i := range parseInt64Tests {
    221 		test := &parseInt64Tests[i]
    222 		if test.err != nil {
    223 			test.err = &NumError{"ParseInt", test.in, test.err}
    224 		}
    225 	}
    226 	for i := range parseInt64BaseTests {
    227 		test := &parseInt64BaseTests[i]
    228 		if test.err != nil {
    229 			test.err = &NumError{"ParseInt", test.in, test.err}
    230 		}
    231 	}
    232 	for i := range parseUint32Tests {
    233 		test := &parseUint32Tests[i]
    234 		if test.err != nil {
    235 			test.err = &NumError{"ParseUint", test.in, test.err}
    236 		}
    237 	}
    238 	for i := range parseInt32Tests {
    239 		test := &parseInt32Tests[i]
    240 		if test.err != nil {
    241 			test.err = &NumError{"ParseInt", test.in, test.err}
    242 		}
    243 	}
    244 }
    245 
    246 func TestParseUint32(t *testing.T) {
    247 	for i := range parseUint32Tests {
    248 		test := &parseUint32Tests[i]
    249 		out, err := ParseUint(test.in, 10, 32)
    250 		if uint64(test.out) != out || !reflect.DeepEqual(test.err, err) {
    251 			t.Errorf("ParseUint(%q, 10, 32) = %v, %v want %v, %v",
    252 				test.in, out, err, test.out, test.err)
    253 		}
    254 	}
    255 }
    256 
    257 func TestParseUint64(t *testing.T) {
    258 	for i := range parseUint64Tests {
    259 		test := &parseUint64Tests[i]
    260 		out, err := ParseUint(test.in, 10, 64)
    261 		if test.out != out || !reflect.DeepEqual(test.err, err) {
    262 			t.Errorf("ParseUint(%q, 10, 64) = %v, %v want %v, %v",
    263 				test.in, out, err, test.out, test.err)
    264 		}
    265 	}
    266 }
    267 
    268 func TestParseUint64Base(t *testing.T) {
    269 	for i := range parseUint64BaseTests {
    270 		test := &parseUint64BaseTests[i]
    271 		out, err := ParseUint(test.in, test.base, 64)
    272 		if test.out != out || !reflect.DeepEqual(test.err, err) {
    273 			t.Errorf("ParseUint(%q, %v, 64) = %v, %v want %v, %v",
    274 				test.in, test.base, out, err, test.out, test.err)
    275 		}
    276 	}
    277 }
    278 
    279 func TestParseInt32(t *testing.T) {
    280 	for i := range parseInt32Tests {
    281 		test := &parseInt32Tests[i]
    282 		out, err := ParseInt(test.in, 10, 32)
    283 		if int64(test.out) != out || !reflect.DeepEqual(test.err, err) {
    284 			t.Errorf("ParseInt(%q, 10 ,32) = %v, %v want %v, %v",
    285 				test.in, out, err, test.out, test.err)
    286 		}
    287 	}
    288 }
    289 
    290 func TestParseInt64(t *testing.T) {
    291 	for i := range parseInt64Tests {
    292 		test := &parseInt64Tests[i]
    293 		out, err := ParseInt(test.in, 10, 64)
    294 		if test.out != out || !reflect.DeepEqual(test.err, err) {
    295 			t.Errorf("ParseInt(%q, 10, 64) = %v, %v want %v, %v",
    296 				test.in, out, err, test.out, test.err)
    297 		}
    298 	}
    299 }
    300 
    301 func TestParseInt64Base(t *testing.T) {
    302 	for i := range parseInt64BaseTests {
    303 		test := &parseInt64BaseTests[i]
    304 		out, err := ParseInt(test.in, test.base, 64)
    305 		if test.out != out || !reflect.DeepEqual(test.err, err) {
    306 			t.Errorf("ParseInt(%q, %v, 64) = %v, %v want %v, %v",
    307 				test.in, test.base, out, err, test.out, test.err)
    308 		}
    309 	}
    310 }
    311 
    312 func TestParseUint(t *testing.T) {
    313 	switch IntSize {
    314 	case 32:
    315 		for i := range parseUint32Tests {
    316 			test := &parseUint32Tests[i]
    317 			out, err := ParseUint(test.in, 10, 0)
    318 			if uint64(test.out) != out || !reflect.DeepEqual(test.err, err) {
    319 				t.Errorf("ParseUint(%q, 10, 0) = %v, %v want %v, %v",
    320 					test.in, out, err, test.out, test.err)
    321 			}
    322 		}
    323 	case 64:
    324 		for i := range parseUint64Tests {
    325 			test := &parseUint64Tests[i]
    326 			out, err := ParseUint(test.in, 10, 0)
    327 			if test.out != out || !reflect.DeepEqual(test.err, err) {
    328 				t.Errorf("ParseUint(%q, 10, 0) = %v, %v want %v, %v",
    329 					test.in, out, err, test.out, test.err)
    330 			}
    331 		}
    332 	}
    333 }
    334 
    335 func TestParseInt(t *testing.T) {
    336 	switch IntSize {
    337 	case 32:
    338 		for i := range parseInt32Tests {
    339 			test := &parseInt32Tests[i]
    340 			out, err := ParseInt(test.in, 10, 0)
    341 			if int64(test.out) != out || !reflect.DeepEqual(test.err, err) {
    342 				t.Errorf("ParseInt(%q, 10, 0) = %v, %v want %v, %v",
    343 					test.in, out, err, test.out, test.err)
    344 			}
    345 		}
    346 	case 64:
    347 		for i := range parseInt64Tests {
    348 			test := &parseInt64Tests[i]
    349 			out, err := ParseInt(test.in, 10, 0)
    350 			if test.out != out || !reflect.DeepEqual(test.err, err) {
    351 				t.Errorf("ParseInt(%q, 10, 0) = %v, %v want %v, %v",
    352 					test.in, out, err, test.out, test.err)
    353 			}
    354 		}
    355 	}
    356 }
    357 
    358 func TestAtoi(t *testing.T) {
    359 	switch IntSize {
    360 	case 32:
    361 		for i := range parseInt32Tests {
    362 			test := &parseInt32Tests[i]
    363 			out, err := Atoi(test.in)
    364 			var testErr error
    365 			if test.err != nil {
    366 				testErr = &NumError{"Atoi", test.in, test.err.(*NumError).Err}
    367 			}
    368 			if int(test.out) != out || !reflect.DeepEqual(testErr, err) {
    369 				t.Errorf("Atoi(%q) = %v, %v want %v, %v",
    370 					test.in, out, err, test.out, testErr)
    371 			}
    372 		}
    373 	case 64:
    374 		for i := range parseInt64Tests {
    375 			test := &parseInt64Tests[i]
    376 			out, err := Atoi(test.in)
    377 			var testErr error
    378 			if test.err != nil {
    379 				testErr = &NumError{"Atoi", test.in, test.err.(*NumError).Err}
    380 			}
    381 			if test.out != int64(out) || !reflect.DeepEqual(testErr, err) {
    382 				t.Errorf("Atoi(%q) = %v, %v want %v, %v",
    383 					test.in, out, err, test.out, testErr)
    384 			}
    385 		}
    386 	}
    387 }
    388 
    389 func bitSizeErrStub(name string, bitSize int) error {
    390 	return BitSizeError(name, "0", bitSize)
    391 }
    392 
    393 func baseErrStub(name string, base int) error {
    394 	return BaseError(name, "0", base)
    395 }
    396 
    397 func noErrStub(name string, arg int) error {
    398 	return nil
    399 }
    400 
    401 type parseErrorTest struct {
    402 	arg     int
    403 	errStub func(name string, arg int) error
    404 }
    405 
    406 var parseBitSizeTests = []parseErrorTest{
    407 	{-1, bitSizeErrStub},
    408 	{0, noErrStub},
    409 	{64, noErrStub},
    410 	{65, bitSizeErrStub},
    411 }
    412 
    413 var parseBaseTests = []parseErrorTest{
    414 	{-1, baseErrStub},
    415 	{0, noErrStub},
    416 	{1, baseErrStub},
    417 	{2, noErrStub},
    418 	{36, noErrStub},
    419 	{37, baseErrStub},
    420 }
    421 
    422 func TestParseIntBitSize(t *testing.T) {
    423 	for i := range parseBitSizeTests {
    424 		test := &parseBitSizeTests[i]
    425 		testErr := test.errStub("ParseInt", test.arg)
    426 		_, err := ParseInt("0", 0, test.arg)
    427 		if !reflect.DeepEqual(testErr, err) {
    428 			t.Errorf("ParseInt(\"0\", 0, %v) = 0, %v want 0, %v",
    429 				test.arg, err, testErr)
    430 		}
    431 	}
    432 }
    433 
    434 func TestParseUintBitSize(t *testing.T) {
    435 	for i := range parseBitSizeTests {
    436 		test := &parseBitSizeTests[i]
    437 		testErr := test.errStub("ParseUint", test.arg)
    438 		_, err := ParseUint("0", 0, test.arg)
    439 		if !reflect.DeepEqual(testErr, err) {
    440 			t.Errorf("ParseUint(\"0\", 0, %v) = 0, %v want 0, %v",
    441 				test.arg, err, testErr)
    442 		}
    443 	}
    444 }
    445 
    446 func TestParseIntBase(t *testing.T) {
    447 	for i := range parseBaseTests {
    448 		test := &parseBaseTests[i]
    449 		testErr := test.errStub("ParseInt", test.arg)
    450 		_, err := ParseInt("0", test.arg, 0)
    451 		if !reflect.DeepEqual(testErr, err) {
    452 			t.Errorf("ParseInt(\"0\", %v, 0) = 0, %v want 0, %v",
    453 				test.arg, err, testErr)
    454 		}
    455 	}
    456 }
    457 
    458 func TestParseUintBase(t *testing.T) {
    459 	for i := range parseBaseTests {
    460 		test := &parseBaseTests[i]
    461 		testErr := test.errStub("ParseUint", test.arg)
    462 		_, err := ParseUint("0", test.arg, 0)
    463 		if !reflect.DeepEqual(testErr, err) {
    464 			t.Errorf("ParseUint(\"0\", %v, 0) = 0, %v want 0, %v",
    465 				test.arg, err, testErr)
    466 		}
    467 	}
    468 }
    469 
    470 func TestNumError(t *testing.T) {
    471 	for _, test := range numErrorTests {
    472 		err := &NumError{
    473 			Func: "ParseFloat",
    474 			Num:  test.num,
    475 			Err:  errors.New("failed"),
    476 		}
    477 		if got := err.Error(); got != test.want {
    478 			t.Errorf(`(&NumError{"ParseFloat", %q, "failed"}).Error() = %v, want %v`, test.num, got, test.want)
    479 		}
    480 	}
    481 }
    482 
    483 func BenchmarkParseInt(b *testing.B) {
    484 	b.Run("Pos", func(b *testing.B) {
    485 		benchmarkParseInt(b, 1)
    486 	})
    487 	b.Run("Neg", func(b *testing.B) {
    488 		benchmarkParseInt(b, -1)
    489 	})
    490 }
    491 
    492 type benchCase struct {
    493 	name string
    494 	num  int64
    495 }
    496 
    497 func benchmarkParseInt(b *testing.B, neg int) {
    498 	cases := []benchCase{
    499 		{"7bit", 1<<7 - 1},
    500 		{"26bit", 1<<26 - 1},
    501 		{"31bit", 1<<31 - 1},
    502 		{"56bit", 1<<56 - 1},
    503 		{"63bit", 1<<63 - 1},
    504 	}
    505 	for _, cs := range cases {
    506 		b.Run(cs.name, func(b *testing.B) {
    507 			s := fmt.Sprintf("%d", cs.num*int64(neg))
    508 			for i := 0; i < b.N; i++ {
    509 				out, _ := ParseInt(s, 10, 64)
    510 				BenchSink += int(out)
    511 			}
    512 		})
    513 	}
    514 }
    515 
    516 func BenchmarkAtoi(b *testing.B) {
    517 	b.Run("Pos", func(b *testing.B) {
    518 		benchmarkAtoi(b, 1)
    519 	})
    520 	b.Run("Neg", func(b *testing.B) {
    521 		benchmarkAtoi(b, -1)
    522 	})
    523 }
    524 
    525 func benchmarkAtoi(b *testing.B, neg int) {
    526 	cases := []benchCase{
    527 		{"7bit", 1<<7 - 1},
    528 		{"26bit", 1<<26 - 1},
    529 		{"31bit", 1<<31 - 1},
    530 	}
    531 	if IntSize == 64 {
    532 		cases = append(cases, []benchCase{
    533 			{"56bit", 1<<56 - 1},
    534 			{"63bit", 1<<63 - 1},
    535 		}...)
    536 	}
    537 	for _, cs := range cases {
    538 		b.Run(cs.name, func(b *testing.B) {
    539 			s := fmt.Sprintf("%d", cs.num*int64(neg))
    540 			for i := 0; i < b.N; i++ {
    541 				out, _ := Atoi(s)
    542 				BenchSink += out
    543 			}
    544 		})
    545 	}
    546 }
    547