From 621e49bb465f500cc46d47e39e828cf76d6381d7 Mon Sep 17 00:00:00 2001 From: Dimitri Sokolyuk Date: Tue, 24 Jul 2018 14:35:44 +0200 Subject: update vendor --- .../x/text/internal/number/decimal_test.go | 329 +++++++++++++++++++++ 1 file changed, 329 insertions(+) create mode 100644 vendor/golang.org/x/text/internal/number/decimal_test.go (limited to 'vendor/golang.org/x/text/internal/number/decimal_test.go') diff --git a/vendor/golang.org/x/text/internal/number/decimal_test.go b/vendor/golang.org/x/text/internal/number/decimal_test.go new file mode 100644 index 0000000..97c7e25 --- /dev/null +++ b/vendor/golang.org/x/text/internal/number/decimal_test.go @@ -0,0 +1,329 @@ +// Copyright 2017 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 number + +import ( + "fmt" + "math" + "strconv" + "strings" + "testing" +) + +func mkfloat(num string) float64 { + u, _ := strconv.ParseUint(num, 10, 32) + return float64(u) +} + +// mkdec creates a decimal from a string. All ASCII digits are converted to +// digits in the decimal. The dot is used to indicate the scale by which the +// digits are shifted. Numbers may have an additional exponent or be the special +// value NaN, Inf, or -Inf. +func mkdec(num string) (d Decimal) { + var r RoundingContext + d.Convert(r, dec(num)) + return +} + +type dec string + +func (s dec) Convert(d *Decimal, _ RoundingContext) { + num := string(s) + if num[0] == '-' { + d.Neg = true + num = num[1:] + } + switch num { + case "NaN": + d.NaN = true + return + case "Inf": + d.Inf = true + return + } + if p := strings.IndexAny(num, "eE"); p != -1 { + i64, err := strconv.ParseInt(num[p+1:], 10, 32) + if err != nil { + panic(err) + } + d.Exp = int32(i64) + num = num[:p] + } + if p := strings.IndexByte(num, '.'); p != -1 { + d.Exp += int32(p) + num = num[:p] + num[p+1:] + } else { + d.Exp += int32(len(num)) + } + d.Digits = []byte(num) + for i := range d.Digits { + d.Digits[i] -= '0' + } + *d = d.normalize() +} + +func byteNum(s string) []byte { + b := make([]byte, len(s)) + for i := 0; i < len(s); i++ { + if c := s[i]; '0' <= c && c <= '9' { + b[i] = s[i] - '0' + } else { + b[i] = s[i] - 'a' + 10 + } + } + return b +} + +func strNum(s string) string { + return string(byteNum(s)) +} + +func TestDecimalString(t *testing.T) { + for _, test := range []struct { + x Decimal + want string + }{ + {want: "0"}, + {Decimal{digits: digits{Digits: nil, Exp: 1000}}, "0"}, // exponent of 1000 is ignored + {Decimal{digits: digits{Digits: byteNum("12345"), Exp: 0}}, "0.12345"}, + {Decimal{digits: digits{Digits: byteNum("12345"), Exp: -3}}, "0.00012345"}, + {Decimal{digits: digits{Digits: byteNum("12345"), Exp: +3}}, "123.45"}, + {Decimal{digits: digits{Digits: byteNum("12345"), Exp: +10}}, "1234500000"}, + } { + if got := test.x.String(); got != test.want { + t.Errorf("%v == %q; want %q", test.x, got, test.want) + } + } +} + +func TestRounding(t *testing.T) { + testCases := []struct { + x string + n int + // modes is the result for modes. Signs are left out of the result. + // The results are stored in the following order: + // zero, negInf + // nearZero, nearEven, nearAway + // away, posInf + modes [numModes]string + }{ + {"0", 1, [numModes]string{ + "0", "0", + "0", "0", "0", + "0", "0"}}, + {"1", 1, [numModes]string{ + "1", "1", + "1", "1", "1", + "1", "1"}}, + {"5", 1, [numModes]string{ + "5", "5", + "5", "5", "5", + "5", "5"}}, + {"15", 1, [numModes]string{ + "10", "10", + "10", "20", "20", + "20", "20"}}, + {"45", 1, [numModes]string{ + "40", "40", + "40", "40", "50", + "50", "50"}}, + {"95", 1, [numModes]string{ + "90", "90", + "90", "100", "100", + "100", "100"}}, + + {"12344999", 4, [numModes]string{ + "12340000", "12340000", + "12340000", "12340000", "12340000", + "12350000", "12350000"}}, + {"12345000", 4, [numModes]string{ + "12340000", "12340000", + "12340000", "12340000", "12350000", + "12350000", "12350000"}}, + {"12345001", 4, [numModes]string{ + "12340000", "12340000", + "12350000", "12350000", "12350000", + "12350000", "12350000"}}, + {"12345100", 4, [numModes]string{ + "12340000", "12340000", + "12350000", "12350000", "12350000", + "12350000", "12350000"}}, + {"23454999", 4, [numModes]string{ + "23450000", "23450000", + "23450000", "23450000", "23450000", + "23460000", "23460000"}}, + {"23455000", 4, [numModes]string{ + "23450000", "23450000", + "23450000", "23460000", "23460000", + "23460000", "23460000"}}, + {"23455001", 4, [numModes]string{ + "23450000", "23450000", + "23460000", "23460000", "23460000", + "23460000", "23460000"}}, + {"23455100", 4, [numModes]string{ + "23450000", "23450000", + "23460000", "23460000", "23460000", + "23460000", "23460000"}}, + + {"99994999", 4, [numModes]string{ + "99990000", "99990000", + "99990000", "99990000", "99990000", + "100000000", "100000000"}}, + {"99995000", 4, [numModes]string{ + "99990000", "99990000", + "99990000", "100000000", "100000000", + "100000000", "100000000"}}, + {"99999999", 4, [numModes]string{ + "99990000", "99990000", + "100000000", "100000000", "100000000", + "100000000", "100000000"}}, + + {"12994999", 4, [numModes]string{ + "12990000", "12990000", + "12990000", "12990000", "12990000", + "13000000", "13000000"}}, + {"12995000", 4, [numModes]string{ + "12990000", "12990000", + "12990000", "13000000", "13000000", + "13000000", "13000000"}}, + {"12999999", 4, [numModes]string{ + "12990000", "12990000", + "13000000", "13000000", "13000000", + "13000000", "13000000"}}, + } + modes := []RoundingMode{ + ToZero, ToNegativeInf, + ToNearestZero, ToNearestEven, ToNearestAway, + AwayFromZero, ToPositiveInf, + } + for _, tc := range testCases { + // Create negative counterpart tests: the sign is reversed and + // ToPositiveInf and ToNegativeInf swapped. + negModes := tc.modes + negModes[1], negModes[6] = negModes[6], negModes[1] + for i, res := range negModes { + negModes[i] = "-" + res + } + for i, m := range modes { + t.Run(fmt.Sprintf("x:%s/n:%d/%s", tc.x, tc.n, m), func(t *testing.T) { + d := mkdec(tc.x) + d.round(m, tc.n) + if got := d.String(); got != tc.modes[i] { + t.Errorf("pos decimal: got %q; want %q", d.String(), tc.modes[i]) + } + + mult := math.Pow(10, float64(len(tc.x)-tc.n)) + f := mkfloat(tc.x) + f = m.roundFloat(f/mult) * mult + if got := fmt.Sprintf("%.0f", f); got != tc.modes[i] { + t.Errorf("pos float: got %q; want %q", got, tc.modes[i]) + } + + // Test the negative case. This is the same as the positive + // case, but with ToPositiveInf and ToNegativeInf swapped. + d = mkdec(tc.x) + d.Neg = true + d.round(m, tc.n) + if got, want := d.String(), negModes[i]; got != want { + t.Errorf("neg decimal: got %q; want %q", d.String(), want) + } + + f = -mkfloat(tc.x) + f = m.roundFloat(f/mult) * mult + if got := fmt.Sprintf("%.0f", f); got != negModes[i] { + t.Errorf("neg float: got %q; want %q", got, negModes[i]) + } + }) + } + } +} + +func TestConvert(t *testing.T) { + scale2 := RoundingContext{} + scale2.SetScale(2) + scale2away := RoundingContext{Mode: AwayFromZero} + scale2away.SetScale(2) + inc0_05 := RoundingContext{Increment: 5, IncrementScale: 2} + inc0_05.SetScale(2) + inc50 := RoundingContext{Increment: 50} + prec3 := RoundingContext{} + prec3.SetPrecision(3) + roundShift := RoundingContext{DigitShift: 2, MaxFractionDigits: 2} + testCases := []struct { + x interface{} + rc RoundingContext + out string + }{ + {-0.001, scale2, "-0.00"}, + {0.1234, prec3, "0.123"}, + {1234.0, prec3, "1230"}, + {1.2345e10, prec3, "12300000000"}, + + {int8(-34), scale2, "-34"}, + {int16(-234), scale2, "-234"}, + {int32(-234), scale2, "-234"}, + {int64(-234), scale2, "-234"}, + {int(-234), scale2, "-234"}, + {uint8(234), scale2, "234"}, + {uint16(234), scale2, "234"}, + {uint32(234), scale2, "234"}, + {uint64(234), scale2, "234"}, + {uint(234), scale2, "234"}, + {-1e9, scale2, "-1000000000.00"}, + // The following two causes this result to have a lot of digits: + // 1) 0.234 cannot be accurately represented as a float64, and + // 2) as strconv does not support the rounding AwayFromZero, Convert + // leaves the rounding to caller. + {0.234, scale2away, + "0.2340000000000000135447209004269097931683063507080078125"}, + + {0.0249, inc0_05, "0.00"}, + {0.025, inc0_05, "0.00"}, + {0.0251, inc0_05, "0.05"}, + {0.03, inc0_05, "0.05"}, + {0.049, inc0_05, "0.05"}, + {0.05, inc0_05, "0.05"}, + {0.051, inc0_05, "0.05"}, + {0.0749, inc0_05, "0.05"}, + {0.075, inc0_05, "0.10"}, + {0.0751, inc0_05, "0.10"}, + {324, inc50, "300"}, + {325, inc50, "300"}, + {326, inc50, "350"}, + {349, inc50, "350"}, + {350, inc50, "350"}, + {351, inc50, "350"}, + {374, inc50, "350"}, + {375, inc50, "400"}, + {376, inc50, "400"}, + + // Here the scale is 2, but the digits get shifted left. As we use + // AppendFloat to do the rounding an exta 0 gets added. + {0.123, roundShift, "0.1230"}, + + {converter(3), scale2, "100"}, + + {math.Inf(1), inc50, "Inf"}, + {math.Inf(-1), inc50, "-Inf"}, + {math.NaN(), inc50, "NaN"}, + {"clearly not a number", scale2, "NaN"}, + } + for _, tc := range testCases { + var d Decimal + t.Run(fmt.Sprintf("%T:%v-%v", tc.x, tc.x, tc.rc), func(t *testing.T) { + d.Convert(tc.rc, tc.x) + if got := d.String(); got != tc.out { + t.Errorf("got %q; want %q", got, tc.out) + } + }) + } +} + +type converter int + +func (c converter) Convert(d *Decimal, r RoundingContext) { + d.Digits = append(d.Digits, 1, 0, 0) + d.Exp = 3 +} -- cgit v1.2.3