From 42f28ab8e374137fe3f5d25424489d879d4724f8 Mon Sep 17 00:00:00 2001 From: Christopher Speller Date: Wed, 21 Jun 2017 19:06:17 -0700 Subject: Updating server dependancies (#6712) --- vendor/golang.org/x/text/collate/build/builder.go | 1 - vendor/golang.org/x/text/internal/catmsg/catmsg.go | 3 +- .../golang.org/x/text/internal/number/decimal.go | 430 +++++ .../x/text/internal/number/decimal_test.go | 294 +++ vendor/golang.org/x/text/internal/number/format.go | 321 ++++ .../x/text/internal/number/format_test.go | 363 ++++ vendor/golang.org/x/text/internal/number/number.go | 9 + .../x/text/internal/number/number_test.go | 24 +- .../golang.org/x/text/internal/number/pattern.go | 28 +- .../x/text/internal/number/pattern_test.go | 61 +- .../x/text/internal/number/roundingmode_string.go | 16 + vendor/golang.org/x/text/internal/number/tables.go | 4 +- vendor/golang.org/x/text/message/catalog.go | 103 +- .../golang.org/x/text/message/catalog/catalog.go | 292 +++ .../x/text/message/catalog/catalog_test.go | 194 ++ vendor/golang.org/x/text/message/catalog/dict.go | 90 + vendor/golang.org/x/text/message/catalog_test.go | 98 - vendor/golang.org/x/text/message/fmt_test.go | 1871 ++++++++++++++++++++ vendor/golang.org/x/text/message/format.go | 532 ++++++ vendor/golang.org/x/text/message/message.go | 176 +- vendor/golang.org/x/text/message/message_test.go | 41 +- vendor/golang.org/x/text/message/print.go | 972 ++++++++++ .../x/text/secure/precis/enforce_test.go | 2 + vendor/golang.org/x/text/secure/precis/profile.go | 48 +- 24 files changed, 5622 insertions(+), 351 deletions(-) create mode 100644 vendor/golang.org/x/text/internal/number/decimal.go create mode 100644 vendor/golang.org/x/text/internal/number/decimal_test.go create mode 100755 vendor/golang.org/x/text/internal/number/format.go create mode 100755 vendor/golang.org/x/text/internal/number/format_test.go create mode 100644 vendor/golang.org/x/text/internal/number/roundingmode_string.go create mode 100644 vendor/golang.org/x/text/message/catalog/catalog.go create mode 100644 vendor/golang.org/x/text/message/catalog/catalog_test.go create mode 100644 vendor/golang.org/x/text/message/catalog/dict.go delete mode 100644 vendor/golang.org/x/text/message/catalog_test.go create mode 100755 vendor/golang.org/x/text/message/fmt_test.go create mode 100644 vendor/golang.org/x/text/message/format.go create mode 100644 vendor/golang.org/x/text/message/print.go (limited to 'vendor/golang.org/x/text') diff --git a/vendor/golang.org/x/text/collate/build/builder.go b/vendor/golang.org/x/text/collate/build/builder.go index 8b5391dc6..11042841b 100644 --- a/vendor/golang.org/x/text/collate/build/builder.go +++ b/vendor/golang.org/x/text/collate/build/builder.go @@ -472,7 +472,6 @@ func (b *Builder) build() (*table, error) { } // Build builds the root Collator. -// TODO: return Weighter instead func (b *Builder) Build() (colltab.Weighter, error) { table, err := b.build() if err != nil { diff --git a/vendor/golang.org/x/text/internal/catmsg/catmsg.go b/vendor/golang.org/x/text/internal/catmsg/catmsg.go index 1013b43ec..74c039f05 100644 --- a/vendor/golang.org/x/text/internal/catmsg/catmsg.go +++ b/vendor/golang.org/x/text/internal/catmsg/catmsg.go @@ -41,9 +41,8 @@ // message.Set(language.English, "You are %d minute(s) late.", // catalog.Var("minutes", plural.Select(1, "one", "minute")), // catalog.String("You are %[1]d ${minutes} late.")) - -// p := message.NewPrinter(language.English) // +// p := message.NewPrinter(language.English) // p.Printf("You are %d minute(s) late.", 5) // always 5 minutes late. // // To evaluate the Printf, package message wraps the arguments in a Renderer diff --git a/vendor/golang.org/x/text/internal/number/decimal.go b/vendor/golang.org/x/text/internal/number/decimal.go new file mode 100644 index 000000000..4e42ec785 --- /dev/null +++ b/vendor/golang.org/x/text/internal/number/decimal.go @@ -0,0 +1,430 @@ +// 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. + +//go:generate stringer -type RoundingMode + +package number + +import ( + "math" + "strconv" +) + +// RoundingMode determines how a number is rounded to the desired precision. +type RoundingMode byte + +const ( + ToNearestEven RoundingMode = iota // towards the nearest integer, or towards an even number if equidistant. + ToNearestZero // towards the nearest integer, or towards zero if equidistant. + ToNearestAway // towards the nearest integer, or away from zero if equidistant. + ToPositiveInf // towards infinity + ToNegativeInf // towards negative infinity + ToZero // towards zero + AwayFromZero // away from zero + numModes +) + +// A RoundingContext indicates how a number should be converted to digits. +type RoundingContext struct { + Mode RoundingMode + Increment int32 // if > 0, round to Increment * 10^-Scale + + Precision int32 // maximum number of significant digits. + Scale int32 // maximum number of decimals after the dot. +} + +// A Decimal represents floating point number represented in digits of the base +// in which a number is to be displayed. Digits represents a number [0, 1.0), +// and the absolute value represented by Decimal is Digits * 10^Exp. +// Leading and trailing zeros may be omitted and Exp may point outside a valid +// position in Digits. +// +// Examples: +// Number Decimal +// 12345 Digits: [1, 2, 3, 4, 5], Exp: 5 +// 12.345 Digits: [1, 2, 3, 4, 5], Exp: 2 +// 12000 Digits: [1, 2], Exp: 5 +// 0.00123 Digits: [1, 2, 3], Exp: -2 +type Decimal struct { + Digits []byte // mantissa digits, big-endian + Exp int32 // exponent + Neg bool + Inf bool // Takes precedence over Digits and Exp. + NaN bool // Takes precedence over Inf. + + buf [10]byte +} + +// normalize retuns a new Decimal with leading and trailing zeros removed. +func (d *Decimal) normalize() (n Decimal) { + n = *d + b := n.Digits + // Strip leading zeros. Resulting number of digits is significant digits. + for len(b) > 0 && b[0] == 0 { + b = b[1:] + n.Exp-- + } + // Strip trailing zeros + for len(b) > 0 && b[len(b)-1] == 0 { + b = b[:len(b)-1] + } + if len(b) == 0 { + n.Exp = 0 + } + n.Digits = b + return n +} + +func (d *Decimal) clear() { + b := d.Digits + if b == nil { + b = d.buf[:0] + } + *d = Decimal{} + d.Digits = b[:0] +} + +func (x *Decimal) String() string { + if x.NaN { + return "NaN" + } + var buf []byte + if x.Neg { + buf = append(buf, '-') + } + if x.Inf { + buf = append(buf, "Inf"...) + return string(buf) + } + if len(x.Digits) == 0 { + return "0" + } + switch { + case x.Exp <= 0: + // 0.00ddd + buf = append(buf, "0."...) + buf = appendZeros(buf, -int(x.Exp)) + buf = appendDigits(buf, x.Digits) + + case /* 0 < */ int(x.Exp) < len(x.Digits): + // dd.ddd + buf = appendDigits(buf, x.Digits[:x.Exp]) + buf = append(buf, '.') + buf = appendDigits(buf, x.Digits[x.Exp:]) + + default: // len(x.Digits) <= x.Exp + // ddd00 + buf = appendDigits(buf, x.Digits) + buf = appendZeros(buf, int(x.Exp)-len(x.Digits)) + } + return string(buf) +} + +func appendDigits(buf []byte, digits []byte) []byte { + for _, c := range digits { + buf = append(buf, c+'0') + } + return buf +} + +// appendZeros appends n 0 digits to buf and returns buf. +func appendZeros(buf []byte, n int) []byte { + for ; n > 0; n-- { + buf = append(buf, '0') + } + return buf +} + +func (d *Decimal) round(mode RoundingMode, n int) { + if n >= len(d.Digits) { + return + } + // Make rounding decision: The result mantissa is truncated ("rounded down") + // by default. Decide if we need to increment, or "round up", the (unsigned) + // mantissa. + inc := false + switch mode { + case ToNegativeInf: + inc = d.Neg + case ToPositiveInf: + inc = !d.Neg + case ToZero: + // nothing to do + case AwayFromZero: + inc = true + case ToNearestEven: + inc = d.Digits[n] > 5 || d.Digits[n] == 5 && + (len(d.Digits) > n+1 || n == 0 || d.Digits[n-1]&1 != 0) + case ToNearestAway: + inc = d.Digits[n] >= 5 + case ToNearestZero: + inc = d.Digits[n] > 5 || d.Digits[n] == 5 && len(d.Digits) > n+1 + default: + panic("unreachable") + } + if inc { + d.roundUp(n) + } else { + d.roundDown(n) + } +} + +// roundFloat rounds a floating point number. +func (r RoundingMode) roundFloat(x float64) float64 { + // Make rounding decision: The result mantissa is truncated ("rounded down") + // by default. Decide if we need to increment, or "round up", the (unsigned) + // mantissa. + abs := x + if x < 0 { + abs = -x + } + i, f := math.Modf(abs) + if f == 0.0 { + return x + } + inc := false + switch r { + case ToNegativeInf: + inc = x < 0 + case ToPositiveInf: + inc = x >= 0 + case ToZero: + // nothing to do + case AwayFromZero: + inc = true + case ToNearestEven: + // TODO: check overflow + inc = f > 0.5 || f == 0.5 && int64(i)&1 != 0 + case ToNearestAway: + inc = f >= 0.5 + case ToNearestZero: + inc = f > 0.5 + default: + panic("unreachable") + } + if inc { + i += 1 + } + if abs != x { + i = -i + } + return i +} + +func (x *Decimal) roundUp(n int) { + if n < 0 || n >= len(x.Digits) { + return // nothing to do + } + // find first digit < 9 + for n > 0 && x.Digits[n-1] >= 9 { + n-- + } + + if n == 0 { + // all digits are 9s => round up to 1 and update exponent + x.Digits[0] = 1 // ok since len(x.Digits) > n + x.Digits = x.Digits[:1] + x.Exp++ + return + } + x.Digits[n-1]++ + x.Digits = x.Digits[:n] + // x already trimmed +} + +func (x *Decimal) roundDown(n int) { + if n < 0 || n >= len(x.Digits) { + return // nothing to do + } + x.Digits = x.Digits[:n] + trim(x) +} + +// trim cuts off any trailing zeros from x's mantissa; +// they are meaningless for the value of x. +func trim(x *Decimal) { + i := len(x.Digits) + for i > 0 && x.Digits[i-1] == 0 { + i-- + } + x.Digits = x.Digits[:i] + if i == 0 { + x.Exp = 0 + } +} + +// A Converter converts a number into decimals according to the given rounding +// criteria. +type Converter interface { + Convert(d *Decimal, r *RoundingContext) +} + +const ( + signed = true + unsigned = false +) + +// Convert converts the given number to the decimal representation using the +// supplied RoundingContext. +func (d *Decimal) Convert(r *RoundingContext, number interface{}) { + switch f := number.(type) { + case Converter: + d.clear() + f.Convert(d, r) + case float32: + d.convertFloat64(r, float64(f), 32) + case float64: + d.convertFloat64(r, f, 64) + case int: + d.convertInt(r, signed, uint64(f)) + case int8: + d.convertInt(r, signed, uint64(f)) + case int16: + d.convertInt(r, signed, uint64(f)) + case int32: + d.convertInt(r, signed, uint64(f)) + case int64: + d.convertInt(r, signed, uint64(f)) + case uint: + d.convertInt(r, unsigned, uint64(f)) + case uint8: + d.convertInt(r, unsigned, uint64(f)) + case uint16: + d.convertInt(r, unsigned, uint64(f)) + case uint32: + d.convertInt(r, unsigned, uint64(f)) + case uint64: + d.convertInt(r, unsigned, f) + + // TODO: + // case string: if produced by strconv, allows for easy arbitrary pos. + // case reflect.Value: + // case big.Float + // case big.Int + // case big.Rat? + // catch underlyings using reflect or will this already be done by the + // message package? + } +} + +func (d *Decimal) convertInt(r *RoundingContext, signed bool, x uint64) { + if r.Increment > 0 { + // TODO: if uint64 is too large, fall back to float64 + if signed { + d.convertFloat64(r, float64(int64(x)), 64) + } else { + d.convertFloat64(r, float64(x), 64) + } + return + } + d.clear() + if signed && int64(x) < 0 { + x = uint64(-int64(x)) + d.Neg = true + } + d.fillIntDigits(x) + d.Exp = int32(len(d.Digits)) +} + +func (d *Decimal) convertFloat64(r *RoundingContext, x float64, size int) { + d.clear() + if math.IsNaN(x) { + d.NaN = true + return + } + abs := x + if x < 0 { + d.Neg = true + abs = -x + } + if math.IsInf(abs, 1) { + d.Inf = true + return + } + // Simple case: decimal notation + if r.Scale > 0 || r.Increment > 0 && r.Scale == 0 { + if int(r.Scale) > len(scales) { + x *= math.Pow(10, float64(r.Scale)) + } else { + x *= scales[r.Scale] + } + if r.Increment > 0 { + inc := float64(r.Increment) + x /= float64(inc) + x = r.Mode.roundFloat(x) + x *= inc + } else { + x = r.Mode.roundFloat(x) + } + d.fillIntDigits(uint64(math.Abs(x))) + d.Exp = int32(len(d.Digits)) - r.Scale + return + } + + // Nasty case (for non-decimal notation). + // Asides from being inefficient, this result is also wrong as it will + // apply ToNearestEven rounding regardless of the user setting. + // TODO: expose functionality in strconv so we can avoid this hack. + // Something like this would work: + // AppendDigits(dst []byte, x float64, base, size, prec int) (digits []byte, exp, accuracy int) + + prec := int(r.Precision) + if prec > 0 { + prec-- + } + b := strconv.AppendFloat(d.Digits, abs, 'e', prec, size) + i := 0 + k := 0 + // No need to check i < len(b) as we always have an 'e'. + for { + if c := b[i]; '0' <= c && c <= '9' { + b[k] = c - '0' + k++ + } else if c != '.' { + break + } + i++ + } + d.Digits = b[:k] + i += len("e") + pSign := i + exp := 0 + for i++; i < len(b); i++ { + exp *= 10 + exp += int(b[i] - '0') + } + if b[pSign] == '-' { + exp = -exp + } + d.Exp = int32(exp) + 1 +} + +func (d *Decimal) fillIntDigits(x uint64) { + const maxUintDigits = 10 + if cap(d.Digits) < maxUintDigits { + d.Digits = d.buf[:] + } else { + d.Digits = d.buf[:maxUintDigits] + } + i := 0 + for ; x > 0; x /= 10 { + d.Digits[i] = byte(x % 10) + i++ + } + d.Digits = d.Digits[:i] + for p := 0; p < i; p++ { + i-- + d.Digits[p], d.Digits[i] = d.Digits[i], d.Digits[p] + } +} + +var scales [70]float64 + +func init() { + x := 1.0 + for i := range scales { + scales[i] = x + x *= 10 + } +} 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 000000000..b99fedc40 --- /dev/null +++ b/vendor/golang.org/x/text/internal/number/decimal_test.go @@ -0,0 +1,294 @@ +// 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) { + 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' + } + return 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: nil, Exp: 1000}, "0"}, // exponent of 1000 is ignored + {Decimal{Digits: byteNum("12345"), Exp: 0}, "0.12345"}, + {Decimal{Digits: byteNum("12345"), Exp: -3}, "0.00012345"}, + {Decimal{Digits: byteNum("12345"), Exp: +3}, "123.45"}, + {Decimal{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 { + if res != "0" { + negModes[i] = "-" + res + } + } + + for i, m := range modes { + t.Run(fmt.Sprintf("v:%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) + } + + if f = mkfloat(tc.x); f != 0 { + f = -f // avoid creating -0.0 + } + 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{Scale: 2} + scale2away := &RoundingContext{Scale: 2, Mode: AwayFromZero} + inc0_05 := &RoundingContext{Increment: 5, Scale: 2} + inc50 := &RoundingContext{Increment: 50} + prec3 := &RoundingContext{Precision: 3} + testCases := []struct { + x interface{} + rc *RoundingContext + out string + }{ + {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"}, + {0.234, scale2, "0.23"}, + {0.234, scale2away, "0.24"}, + {0.1234, prec3, "0.123"}, + {1234.0, prec3, "1230"}, + {1.2345e10, prec3, "12300000000"}, + + {0.03, inc0_05, "0.05"}, + {0.025, inc0_05, "0"}, + {0.075, inc0_05, "0.10"}, + {325, inc50, "300"}, + {375, inc50, "400"}, + + {converter(3), scale2, "100"}, + + {math.Inf(1), inc50, "Inf"}, + {math.Inf(-1), inc50, "-Inf"}, + {math.NaN(), inc50, "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 +} diff --git a/vendor/golang.org/x/text/internal/number/format.go b/vendor/golang.org/x/text/internal/number/format.go new file mode 100755 index 000000000..84903fad8 --- /dev/null +++ b/vendor/golang.org/x/text/internal/number/format.go @@ -0,0 +1,321 @@ +// 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 ( + "strconv" + + "golang.org/x/text/language" +) + +// TODO: +// - public (but internal) API for creating formatters +// - split out the logic that computes the visible digits from the rest of the +// formatting code (needed for plural). +// - grouping of fractions +// - reuse percent pattern for permille +// - padding + +// Formatter contains all the information needed to render a number. +type Formatter struct { + *Pattern + Info + RoundingContext + f func(dst []byte, f *Formatter, d *Decimal) []byte +} + +func lookupFormat(t language.Tag, tagToIndex []uint8) *Pattern { + for ; ; t = t.Parent() { + if ci, ok := language.CompactIndex(t); ok { + return &formats[tagToIndex[ci]] + } + } +} + +func (f *Formatter) Format(dst []byte, d *Decimal) []byte { + return f.f(dst, f, d) +} + +func appendDecimal(dst []byte, f *Formatter, d *Decimal) []byte { + if dst, ok := f.renderSpecial(dst, d); ok { + return dst + } + n := d.normalize() + if maxSig := int(f.MaxSignificantDigits); maxSig > 0 { + n.round(ToZero, maxSig) + } + digits := n.Digits + exp := n.Exp + + // Split in integer and fraction part. + var intDigits, fracDigits []byte + var numInt, numFrac int + if exp > 0 { + numInt = int(exp) + if int(exp) >= len(digits) { // ddddd | ddddd00 + intDigits = digits + } else { // ddd.dd + intDigits = digits[:exp] + fracDigits = digits[exp:] + numFrac = len(fracDigits) + } + } else { + fracDigits = digits + numFrac = -int(exp) + len(digits) + } + // Cap integer digits. Remove *most-significant* digits. + if f.MaxIntegerDigits > 0 && numInt > int(f.MaxIntegerDigits) { + offset := numInt - int(f.MaxIntegerDigits) + if offset > len(intDigits) { + numInt = 0 + intDigits = nil + } else { + numInt = int(f.MaxIntegerDigits) + intDigits = intDigits[offset:] + // for keeping track of significant digits + digits = digits[offset:] + } + // Strip leading zeros. Resulting number of digits is significant digits. + for len(intDigits) > 0 && intDigits[0] == 0 { + intDigits = intDigits[1:] + digits = digits[1:] + numInt-- + } + } + if f.MaxSignificantDigits == 0 && int(f.MaxFractionDigits) < numFrac { + if extra := numFrac - int(f.MaxFractionDigits); extra > len(fracDigits) { + numFrac = 0 + fracDigits = nil + } else { + numFrac = int(f.MaxFractionDigits) + fracDigits = fracDigits[:len(fracDigits)-extra] + } + } + + neg := d.Neg && numInt+numFrac > 0 + affix, suffix := f.getAffixes(neg) + dst = appendAffix(dst, f, affix, neg) + savedLen := len(dst) + + minInt := int(f.MinIntegerDigits) + if minInt == 0 && f.MinSignificantDigits > 0 { + minInt = 1 + } + // add leading zeros + for i := numInt; i < minInt; i++ { + dst = f.AppendDigit(dst, 0) + if f.needsSep(minInt - i) { + dst = append(dst, f.Symbol(SymGroup)...) + } + } + i := 0 + for ; i < len(intDigits); i++ { + dst = f.AppendDigit(dst, intDigits[i]) + if f.needsSep(numInt - i) { + dst = append(dst, f.Symbol(SymGroup)...) + } + } + for ; i < numInt; i++ { + dst = f.AppendDigit(dst, 0) + if f.needsSep(numInt - i) { + dst = append(dst, f.Symbol(SymGroup)...) + } + } + + trailZero := int(f.MinFractionDigits) - numFrac + if d := int(f.MinSignificantDigits) - len(digits); d > 0 && d > trailZero { + trailZero = d + } + if numFrac > 0 || trailZero > 0 || f.Flags&AlwaysDecimalSeparator != 0 { + dst = append(dst, f.Symbol(SymDecimal)...) + } + // Add leading zeros + for i := numFrac - len(fracDigits); i > 0; i-- { + dst = f.AppendDigit(dst, 0) + } + i = 0 + for ; i < len(fracDigits); i++ { + dst = f.AppendDigit(dst, fracDigits[i]) + } + for ; trailZero > 0; trailZero-- { + dst = f.AppendDigit(dst, 0) + } + // Ensure that at least one digit is written no matter what. This makes + // things more robust, even though a pattern should always require at least + // one fraction or integer digit. + if len(dst) == savedLen { + dst = f.AppendDigit(dst, 0) + } + return appendAffix(dst, f, suffix, neg) +} + +func appendScientific(dst []byte, f *Formatter, d *Decimal) []byte { + if dst, ok := f.renderSpecial(dst, d); ok { + return dst + } + // Significant digits are transformed by parser for scientific notation and + // do not need to be handled here. + maxInt, numInt := int(f.MaxIntegerDigits), int(f.MinIntegerDigits) + if numInt == 0 { + numInt = 1 + } + maxSig := int(f.MaxFractionDigits) + numInt + minSig := int(f.MinFractionDigits) + numInt + n := d.normalize() + if maxSig > 0 { + n.round(ToZero, maxSig) + } + digits := n.Digits + exp := n.Exp + + // If a maximum number of integers is specified, the minimum must be 1 + // and the exponent is grouped by this number (e.g. for engineering) + if len(digits) == 0 { + exp = 0 + } else if maxInt > numInt { + // Correct the exponent to reflect a single integer digit. + exp-- + numInt = 1 + // engineering + // 0.01234 ([12345]e-1) -> 1.2345e-2 12.345e-3 + // 12345 ([12345]e+5) -> 1.2345e4 12.345e3 + d := int(exp) % maxInt + if d < 0 { + d += maxInt + } + exp -= int32(d) + numInt += d + } else { + exp -= int32(numInt) + } + var intDigits, fracDigits []byte + if numInt <= len(digits) { + intDigits = digits[:numInt] + fracDigits = digits[numInt:] + } else { + intDigits = digits + } + neg := d.Neg && len(digits) > 0 + affix, suffix := f.getAffixes(neg) + dst = appendAffix(dst, f, affix, neg) + savedLen := len(dst) + + i := 0 + for ; i < len(intDigits); i++ { + dst = f.AppendDigit(dst, intDigits[i]) + if f.needsSep(numInt - i) { + dst = append(dst, f.Symbol(SymGroup)...) + } + } + for ; i < numInt; i++ { + dst = f.AppendDigit(dst, 0) + if f.needsSep(numInt - i) { + dst = append(dst, f.Symbol(SymGroup)...) + } + } + + trailZero := minSig - numInt - len(fracDigits) + if len(fracDigits) > 0 || trailZero > 0 || f.Flags&AlwaysDecimalSeparator != 0 { + dst = append(dst, f.Symbol(SymDecimal)...) + } + i = 0 + for ; i < len(fracDigits); i++ { + dst = f.AppendDigit(dst, fracDigits[i]) + } + for ; trailZero > 0; trailZero-- { + dst = f.AppendDigit(dst, 0) + } + // Ensure that at least one digit is written no matter what. This makes + // things more robust, even though a pattern should always require at least + // one fraction or integer digit. + if len(dst) == savedLen { + dst = f.AppendDigit(dst, 0) + } + + // exp + dst = append(dst, f.Symbol(SymExponential)...) + switch { + case exp < 0: + dst = append(dst, f.Symbol(SymMinusSign)...) + exp = -exp + case f.Flags&AlwaysExpSign != 0: + dst = append(dst, f.Symbol(SymPlusSign)...) + } + buf := [12]byte{} + b := strconv.AppendUint(buf[:0], uint64(exp), 10) + for i := len(b); i < int(f.MinExponentDigits); i++ { + dst = f.AppendDigit(dst, 0) + } + for _, c := range b { + dst = f.AppendDigit(dst, c-'0') + } + return appendAffix(dst, f, suffix, neg) +} + +func (f *Formatter) getAffixes(neg bool) (affix, suffix string) { + str := f.Affix + if str != "" { + if f.NegOffset > 0 { + if neg { + str = str[f.NegOffset:] + } else { + str = str[:f.NegOffset] + } + } + sufStart := 1 + str[0] + affix = str[1:sufStart] + suffix = str[sufStart+1:] + } else if neg { + affix = "-" + } + return affix, suffix +} + +func (f *Formatter) renderSpecial(dst []byte, d *Decimal) (b []byte, ok bool) { + if d.NaN { + return fmtNaN(dst, f), true + } + if d.Inf { + return fmtInfinite(dst, f, d), true + } + return dst, false +} + +func fmtNaN(dst []byte, f *Formatter) []byte { + return append(dst, f.Symbol(SymNan)...) +} + +func fmtInfinite(dst []byte, f *Formatter, d *Decimal) []byte { + if d.Neg { + dst = append(dst, f.Symbol(SymMinusSign)...) + } + return append(dst, f.Symbol(SymInfinity)...) +} + +func appendAffix(dst []byte, f *Formatter, affix string, neg bool) []byte { + quoting := false + escaping := false + for _, r := range affix { + switch { + case escaping: + // escaping occurs both inside and outside of quotes + dst = append(dst, string(r)...) + escaping = false + case r == '\\': + escaping = true + case r == '\'': + quoting = !quoting + case !quoting && (r == '-' || r == '+'): + if neg { + dst = append(dst, f.Symbol(SymMinusSign)...) + } else { + dst = append(dst, f.Symbol(SymPlusSign)...) + } + default: + dst = append(dst, string(r)...) + } + } + return dst +} diff --git a/vendor/golang.org/x/text/internal/number/format_test.go b/vendor/golang.org/x/text/internal/number/format_test.go new file mode 100755 index 000000000..355a33a70 --- /dev/null +++ b/vendor/golang.org/x/text/internal/number/format_test.go @@ -0,0 +1,363 @@ +// 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" + "log" + "strings" + "testing" + + "golang.org/x/text/language" +) + +func TestAppendDecimal(t *testing.T) { + type pairs map[string]string // alternates with decimal input and result + + testCases := []struct { + pattern string + // We want to be able to test some forms of patterns that cannot be + // represented as a string. + pat *Pattern + + test pairs + }{{ + pattern: "0", + test: pairs{ + "0": "0", + "1": "1", + "-1": "-1", + ".00": "0", + "10.": "10", + "12": "12", + "1.2": "1", + "NaN": "NaN", + "-Inf": "-∞", + }, + }, { + pattern: "+0", + test: pairs{ + "0": "+0", + "1": "+1", + "-1": "-1", + ".00": "+0", + "10.": "+10", + "12": "+12", + "1.2": "+1", + "NaN": "NaN", + "-Inf": "-∞", + }, + }, { + pattern: "0 +", + test: pairs{ + "0": "0 +", + "1": "1 +", + "-1": "1 -", + ".00": "0 +", + }, + }, { + pattern: "0;0-", + test: pairs{ + "-1": "1-", + }, + }, { + pattern: "0000", + test: pairs{ + "0": "0000", + "1": "0001", + "12": "0012", + "12345": "12345", + }, + }, { + pattern: ".0", + test: pairs{ + "0": ".0", + "1": "1.0", + "1.2": "1.2", + "1.2345": "1.2", + }, + }, { + pattern: "#.0", + test: pairs{ + "0": ".0", + }, + }, { + pattern: "#.0#", + test: pairs{ + "0": ".0", + "1": "1.0", + }, + }, { + pattern: "0.0#", + test: pairs{ + "0": "0.0", + }, + }, { + pattern: "#0.###", + test: pairs{ + "0": "0", + "1": "1", + "1.2": "1.2", + "1.2345": "1.234", // rounding should have been done earlier + "1234.5": "1234.5", + "1234.567": "1234.567", + }, + }, { + pattern: "#0.######", + test: pairs{ + "0": "0", + "1234.5678": "1234.5678", + "0.123456789": "0.123456", + "NaN": "NaN", + "Inf": "∞", + }, + + // Test separators. + }, { + pattern: "#,#.00", + test: pairs{ + "100": "1,0,0.00", + }, + }, { + pattern: "#,0.##", + test: pairs{ + "10": "1,0", + }, + }, { + pattern: "#,0", + test: pairs{ + "10": "1,0", + }, + }, { + pattern: "#,##,#.00", + test: pairs{ + "1000": "1,00,0.00", + }, + }, { + pattern: "#,##0.###", + test: pairs{ + "0": "0", + "1234.5678": "1,234.567", + "0.123456789": "0.123", + }, + }, { + pattern: "#,##,##0.###", + test: pairs{ + "0": "0", + "123456789012": "1,23,45,67,89,012", + "0.123456789": "0.123", + }, + + // Support for ill-formed patterns. + }, { + pattern: "#", + test: pairs{ + ".00": "0", + "0": "0", + "1": "1", + "10.": "10", + }, + }, { + pattern: ".#", + test: pairs{ + "0": "0", + "1": "1", + "1.2": "1.2", + "1.2345": "1.2", + }, + }, { + pattern: "#,#.##", + test: pairs{ + "10": "1,0", + }, + }, { + pattern: "#,#", + test: pairs{ + "10": "1,0", + }, + + // Special patterns + }, { + pattern: "#,max_int=2", + pat: &Pattern{ + MaxIntegerDigits: 2, + }, + test: pairs{ + "2017": "17", + }, + }, { + pattern: "0,max_int=2", + pat: &Pattern{ + MaxIntegerDigits: 2, + MinIntegerDigits: 1, + }, + test: pairs{ + "2000": "0", + "2001": "1", + "2017": "17", + }, + }, { + pattern: "00,max_int=2", + pat: &Pattern{ + MaxIntegerDigits: 2, + MinIntegerDigits: 2, + }, + test: pairs{ + "2000": "00", + "2001": "01", + "2017": "17", + }, + }, { + pattern: "@@@@,max_int=2", + pat: &Pattern{ + MaxIntegerDigits: 2, + MinSignificantDigits: 4, + }, + test: pairs{ + "2017": "17.00", + "2000": "0.000", + "2001": "1.000", + }, + + // Significant digits + }, { + pattern: "@@##", + test: pairs{ + "1": "1.0", + "0.1": "0.10", + "123": "123", + "1234": "1234", + "12345": "12340", + }, + }, { + pattern: "@@@@", + test: pairs{ + "1": "1.000", + ".1": "0.1000", + ".001": "0.001000", + "123": "123.0", + "1234": "1234", + "12345": "12340", // rounding down + "NaN": "NaN", + "-Inf": "-∞", + }, + + // TODO: rounding + // {"@@@@": "23456": "23460"}, // rounding up + // TODO: padding + + // Scientific and Engineering notation + }, { + pattern: "#E0", + test: pairs{ + "0": "0E0", + "1": "1E0", + "123.456": "1E2", + }, + }, { + pattern: "#E+0", + test: pairs{ + "0": "0E+0", + "1000": "1E+3", + "1E100": "1E+100", + "1E-100": "1E-100", + "NaN": "NaN", + "-Inf": "-∞", + }, + }, { + pattern: "##0E00", + test: pairs{ + "100": "100E00", + "12345": "10E03", + "123.456": "100E00", + }, + }, { + pattern: "##0.###E00", + test: pairs{ + "100": "100E00", + "12345": "12.34E03", + "123.456": "123.4E00", + }, + }, { + pattern: "##0.000E00", + test: pairs{ + "100": "100.0E00", + "12345": "12.34E03", + "123.456": "123.4E00", + }, + }} + + // TODO: + // "@@E0", + // "@###E00", + // "0.0%", + // "0.0‰", + // "#,##0.00¤", + // "#,##0.00 ¤;(#,##0.00 ¤)", + // // padding + // "*x#", + // "#*x", + // "*xpre#suf", + // "pre*x#suf", + // "pre#*xsuf", + // "pre#suf*x", + for _, tc := range testCases { + pat := tc.pat + if pat == nil { + var err error + if pat, err = ParsePattern(tc.pattern); err != nil { + log.Fatal(err) + } + } + f := &Formatter{ + pat, + InfoFromTag(language.English), + RoundingContext{}, + appendDecimal, + } + if strings.IndexByte(tc.pattern, 'E') != -1 { + f.f = appendScientific + } + for dec, want := range tc.test { + buf := make([]byte, 100) + t.Run(tc.pattern+"/"+dec, func(t *testing.T) { + dec := mkdec(dec) + buf = f.Format(buf[:0], &dec) + if got := string(buf); got != want { + t.Errorf("\n got %q\nwant %q", got, want) + } + }) + } + } +} + +func TestLocales(t *testing.T) { + testCases := []struct { + tag language.Tag + num string + want string + }{ + {language.Make("en"), "123456.78", "123,456.78"}, + {language.Make("de"), "123456.78", "123.456,78"}, + {language.Make("de-CH"), "123456.78", "123'456.78"}, + {language.Make("fr"), "123456.78", "123 456,78"}, + {language.Make("bn"), "123456.78", "১,২৩,৪৫৬.৭৮"}, + } + for _, tc := range testCases { + t.Run(fmt.Sprint(tc.tag, "/", tc.num), func(t *testing.T) { + f := &Formatter{ + lookupFormat(tc.tag, tagToDecimal), + InfoFromTag(tc.tag), + RoundingContext{}, + appendDecimal, + } + d := mkdec(tc.num) + b := f.Format(nil, &d) + if got := string(b); got != tc.want { + t.Errorf("got %q; want %q", got, tc.want) + } + }) + } +} diff --git a/vendor/golang.org/x/text/internal/number/number.go b/vendor/golang.org/x/text/internal/number/number.go index 34f4477d0..ea341c796 100644 --- a/vendor/golang.org/x/text/internal/number/number.go +++ b/vendor/golang.org/x/text/internal/number/number.go @@ -121,6 +121,15 @@ func (n Info) WriteDigit(dst []byte, asciiDigit rune) int { return int(n.system.digitSize) } +// AppendDigit appends the UTF-8 sequence for n corresponding to the given digit +// to dst and reports the number of bytes written. dst must be large enough to +// hold the rune (can be up to utf8.UTFMax bytes). +func (n Info) AppendDigit(dst []byte, digit byte) []byte { + dst = append(dst, n.system.zero[:n.system.digitSize]...) + dst[len(dst)-1] += digit + return dst +} + // Digit returns the digit for the numbering system for the corresponding ASCII // value. For example, ni.Digit('3') could return '三'. Note that the argument // is the rune constant '3', which equals 51, not the integer constant 3. diff --git a/vendor/golang.org/x/text/internal/number/number_test.go b/vendor/golang.org/x/text/internal/number/number_test.go index fc04887c4..3eb533914 100644 --- a/vendor/golang.org/x/text/internal/number/number_test.go +++ b/vendor/golang.org/x/text/internal/number/number_test.go @@ -5,6 +5,7 @@ package number import ( + "fmt" "testing" "golang.org/x/text/internal/testtext" @@ -51,13 +52,22 @@ func TestInfo(t *testing.T) { {"en-u-nu-roman", SymPlusSign, "+", '9'}, } for _, tc := range testCases { - info := InfoFromTag(language.MustParse(tc.lang)) - if got := info.Symbol(tc.sym); got != tc.wantSym { - t.Errorf("%s:%v:sym: got %q; want %q", tc.lang, tc.sym, got, tc.wantSym) - } - if got := info.Digit('9'); got != tc.wantNine { - t.Errorf("%s:%v:nine: got %q; want %q", tc.lang, tc.sym, got, tc.wantNine) - } + t.Run(fmt.Sprintf("%s:%v", tc.lang, tc.sym), func(t *testing.T) { + info := InfoFromTag(language.MustParse(tc.lang)) + if got := info.Symbol(tc.sym); got != tc.wantSym { + t.Errorf("sym: got %q; want %q", got, tc.wantSym) + } + if got := info.Digit('9'); got != tc.wantNine { + t.Errorf("Digit(9): got %+q; want %+q", got, tc.wantNine) + } + var buf [4]byte + if got := string(buf[:info.WriteDigit(buf[:], '9')]); got != string(tc.wantNine) { + t.Errorf("WriteDigit(9): got %+q; want %+q", got, tc.wantNine) + } + if got := string(info.AppendDigit([]byte{}, 9)); got != string(tc.wantNine) { + t.Errorf("AppendDigit(9): got %+q; want %+q", got, tc.wantNine) + } + }) } } diff --git a/vendor/golang.org/x/text/internal/number/pattern.go b/vendor/golang.org/x/text/internal/number/pattern.go index 018cf02d5..5610c6026 100644 --- a/vendor/golang.org/x/text/internal/number/pattern.go +++ b/vendor/golang.org/x/text/internal/number/pattern.go @@ -65,7 +65,27 @@ type Pattern struct { MinExponentDigits uint8 } -// A PatternFlag is a bit mask for the flag field of a Format. +func (f *Pattern) needsSep(pos int) bool { + p := pos - 1 + size := int(f.GroupingSize[0]) + if size == 0 || p == 0 { + return false + } + if p == size { + return true + } + if p -= size; p < 0 { + return false + } + // TODO: make second groupingsize the same as first if 0 so that we can + // avoid this check. + if x := int(f.GroupingSize[1]); x != 0 { + size = x + } + return p%size == 0 +} + +// A PatternFlag is a bit mask for the flag field of a Pattern. type PatternFlag uint8 const ( @@ -104,7 +124,8 @@ func (p *parser) setError(err error) { } func (p *parser) updateGrouping() { - if p.hasGroup && p.groupingCount < 255 { + if p.hasGroup && + 0 < p.groupingCount && p.groupingCount < 255 { p.GroupingSize[1] = p.GroupingSize[0] p.GroupingSize[0] = uint8(p.groupingCount) } @@ -163,6 +184,7 @@ func (p *parser) parseSubPattern(s string) string { s = p.parsePad(s, PadAfterPrefix) s = p.parse(p.number, s) + p.updateGrouping() s = p.parsePad(s, PadBeforeSuffix) s = p.parseAffix(s) @@ -294,6 +316,8 @@ func (p *parser) integer(r rune) state { next = p.exponent case '.': next = p.fraction + case ',': + next = p.integer } p.updateGrouping() return next diff --git a/vendor/golang.org/x/text/internal/number/pattern_test.go b/vendor/golang.org/x/text/internal/number/pattern_test.go index 810b5a855..6adeaf7cc 100644 --- a/vendor/golang.org/x/text/internal/number/pattern_test.go +++ b/vendor/golang.org/x/text/internal/number/pattern_test.go @@ -25,6 +25,20 @@ var testCases = []struct { FormatWidth: 1, MinIntegerDigits: 1, }, +}, { + "+0", + &Pattern{ + Affix: "\x01+\x00", + FormatWidth: 2, + MinIntegerDigits: 1, + }, +}, { + "0+", + &Pattern{ + Affix: "\x00\x01+", + FormatWidth: 2, + MinIntegerDigits: 1, + }, }, { "0000", &Pattern{ @@ -51,6 +65,22 @@ var testCases = []struct { MinIntegerDigits: 1, MaxFractionDigits: 6, }, +}, { + "#,0", + &Pattern{ + FormatWidth: 3, + GroupingSize: [2]uint8{1, 0}, + MinIntegerDigits: 1, + }, +}, { + "#,0.00", + &Pattern{ + FormatWidth: 6, + GroupingSize: [2]uint8{1, 0}, + MinIntegerDigits: 1, + MinFractionDigits: 2, + MaxFractionDigits: 2, + }, }, { "#,##0.###", &Pattern{ @@ -176,7 +206,7 @@ var testCases = []struct { MaxFractionDigits: 3, }, }, { - // Rounding increments + // Rounding increment "1.05", &Pattern{ RoundIncrement: 105, @@ -185,6 +215,17 @@ var testCases = []struct { MinFractionDigits: 2, MaxFractionDigits: 2, }, +}, { + // Rounding increment with grouping + "1,05", + &Pattern{ + RoundIncrement: 105, + FormatWidth: 4, + GroupingSize: [2]uint8{2, 0}, + MinIntegerDigits: 3, + MinFractionDigits: 0, + MaxFractionDigits: 0, + }, }, { "0.0%", &Pattern{ @@ -282,19 +323,21 @@ var testCases = []struct { func TestParsePattern(t *testing.T) { for i, tc := range testCases { - f, err := ParsePattern(tc.pat) - if !reflect.DeepEqual(f, tc.want) { - t.Errorf("%d:%s:\ngot %#v;\nwant %#v", i, tc.pat, f, tc.want) - } - if got, want := err != nil, tc.want == nil; got != want { - t.Errorf("%d:%s:error: got %v; want %v", i, tc.pat, err, want) - } + t.Run(tc.pat, func(t *testing.T) { + f, err := ParsePattern(tc.pat) + if !reflect.DeepEqual(f, tc.want) { + t.Errorf("%d:%s:\ngot %#v;\nwant %#v", i, tc.pat, f, tc.want) + } + if got, want := err != nil, tc.want == nil; got != want { + t.Errorf("%d:%s:error: got %v; want %v", i, tc.pat, err, want) + } + }) } } func TestPatternSize(t *testing.T) { if sz := unsafe.Sizeof(Pattern{}); sz > 48 { - t.Errorf("got %d; want 48", sz) + t.Errorf("got %d; want <= 48", sz) } } diff --git a/vendor/golang.org/x/text/internal/number/roundingmode_string.go b/vendor/golang.org/x/text/internal/number/roundingmode_string.go new file mode 100644 index 000000000..f264ea549 --- /dev/null +++ b/vendor/golang.org/x/text/internal/number/roundingmode_string.go @@ -0,0 +1,16 @@ +// Code generated by "stringer -type RoundingMode"; DO NOT EDIT. + +package number + +import "fmt" + +const _RoundingMode_name = "ToNearestEvenToNearestZeroToNearestAwayToPositiveInfToNegativeInfToZeroAwayFromZeronumModes" + +var _RoundingMode_index = [...]uint8{0, 13, 26, 39, 52, 65, 71, 83, 91} + +func (i RoundingMode) String() string { + if i >= RoundingMode(len(_RoundingMode_index)-1) { + return fmt.Sprintf("RoundingMode(%d)", i) + } + return _RoundingMode_name[_RoundingMode_index[i]:_RoundingMode_index[i+1]] +} diff --git a/vendor/golang.org/x/text/internal/number/tables.go b/vendor/golang.org/x/text/internal/number/tables.go index 5c799b433..10baa0a1d 100644 --- a/vendor/golang.org/x/text/internal/number/tables.go +++ b/vendor/golang.org/x/text/internal/number/tables.go @@ -1037,7 +1037,7 @@ var formats = []Pattern{Pattern{Affix: "", RoundIncrement: 0x0, PadRune: 0, FormatWidth: 0x7, - GroupingSize: [2]uint8{0x0, + GroupingSize: [2]uint8{0x3, 0x0}, Flags: 0x0, MinIntegerDigits: 0x1, @@ -1105,7 +1105,7 @@ var formats = []Pattern{Pattern{Affix: "", RoundIncrement: 0x0, PadRune: 0, FormatWidth: 0x6, - GroupingSize: [2]uint8{0x0, + GroupingSize: [2]uint8{0x3, 0x0}, Flags: 0x0, MinIntegerDigits: 0x1, diff --git a/vendor/golang.org/x/text/message/catalog.go b/vendor/golang.org/x/text/message/catalog.go index 41c31f4c6..2f65b4bbc 100644 --- a/vendor/golang.org/x/text/message/catalog.go +++ b/vendor/golang.org/x/text/message/catalog.go @@ -8,106 +8,21 @@ package message // Documentation and method names will reflect this by using the exported name. import ( - "sync" - - "golang.org/x/text/internal" - "golang.org/x/text/internal/format" "golang.org/x/text/language" + "golang.org/x/text/message/catalog" ) // DefaultCatalog is used by SetString. -var DefaultCatalog *Catalog = newCatalog() - -// SetString calls SetString on the default Catalog. -func SetString(tag language.Tag, key string, msg string) error { - return DefaultCatalog.SetString(tag, key, msg) -} - -// TODO: -// // SetSelect is a shorthand for DefaultCatalog.SetSelect. -// func SetSelect(tag language.Tag, key string, s ...format.Statement) error { -// return DefaultCatalog.SetSelect(tag, key, s...) -// } - -type msgMap map[string]format.Statement +var DefaultCatalog *catalog.Catalog = defaultCatalog -// A Catalog holds translations for messages for supported languages. -type Catalog struct { - index map[language.Tag]msgMap +var defaultCatalog = catalog.New() - mutex sync.Mutex // For locking all operations. -} - -// Printer creates a Printer that uses c. -func (c *Catalog) Printer(tag language.Tag) *Printer { - // TODO: pre-create indexes for tag lookup. - return &Printer{ - tag: tag, - cat: c, - } -} - -// NewCatalog returns a new Catalog. If a message is not present in a Catalog, -// the fallback Catalogs will be used in order as an alternative source. -func newCatalog(fallback ...*Catalog) *Catalog { - // TODO: implement fallback. - return &Catalog{ - index: map[language.Tag]msgMap{}, - } -} - -// Languages returns a slice of all languages for which the Catalog contains -// variants. -func (c *Catalog) Languages() []language.Tag { - c.mutex.Lock() - defer c.mutex.Unlock() - - tags := []language.Tag{} - for t, _ := range c.index { - tags = append(tags, t) - } - internal.SortTags(tags) - return tags -} - -// SetString sets the translation for the given language and key. -func (c *Catalog) SetString(tag language.Tag, key string, msg string) error { - return c.set(tag, key, format.String(msg)) -} - -func (c *Catalog) get(tag language.Tag, key string) (msg string, ok bool) { - c.mutex.Lock() - defer c.mutex.Unlock() - - for ; ; tag = tag.Parent() { - if msgs, ok := c.index[tag]; ok { - if statement, ok := msgs[key]; ok { - // TODO: use type switches when we implement selecting. - msg := string(statement.(format.String)) - return msg, true - } - } - if tag == language.Und { - break - } - } - return "", false +// SetString calls SetString on the initial default Catalog. +func SetString(tag language.Tag, key string, msg string) error { + return defaultCatalog.SetString(tag, key, msg) } -func (c *Catalog) set(tag language.Tag, key string, s ...format.Statement) error { - if len(s) != 1 { - // TODO: handle errors properly when we process statement sequences. - panic("statement sequence should be of length 1") - } - - c.mutex.Lock() - defer c.mutex.Unlock() - - m := c.index[tag] - if m == nil { - m = map[string]format.Statement{} - c.index[tag] = m - } - m[key] = s[0] - return nil +// Set calls Set on the initial default Catalog. +func Set(tag language.Tag, key string, msg ...catalog.Message) error { + return defaultCatalog.Set(tag, key, msg...) } diff --git a/vendor/golang.org/x/text/message/catalog/catalog.go b/vendor/golang.org/x/text/message/catalog/catalog.go new file mode 100644 index 000000000..957444c10 --- /dev/null +++ b/vendor/golang.org/x/text/message/catalog/catalog.go @@ -0,0 +1,292 @@ +// 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 catalog defines collections of translated format strings. +// +// This package mostly defines types for populating catalogs with messages. The +// catmsg package contains further definitions for creating custom message and +// dictionary types as well as packages that use Catalogs. +// +// Package catalog defines various interfaces: Dictionary, Loader, and Message. +// A Dictionary maintains a set of translations of format strings for a single +// language. The Loader interface defines a source of dictionaries. A +// translation of a format string is represented by a Message. +// +// +// Catalogs +// +// A Catalog defines a programmatic interface for setting message translations. +// It maintains a set of per-language dictionaries with translations for a set +// of keys. For message translation to function properly, a translation should +// be defined for each key for each supported language. A dictionary may be +// underspecified, though, if there is a parent language that already defines +// the key. For example, a Dictionary for "en-GB" could leave out entries that +// are identical to those in a dictionary for "en". +// +// +// Messages +// +// A Message is a format string which varies on the value of substitution +// variables. For instance, to indicate the number of results one could want "no +// results" if there are none, "1 result" if there is 1, and "%d results" for +// any other number. Catalog is agnostic to the kind of format strings that are +// used: for instance, messages can follow either the printf-style substitution +// from package fmt or use templates. +// +// A Message does not substitute arguments in the format string. This job is +// reserved for packages that render strings, such as message, that use Catalogs +// to selected string. This separation of concerns allows Catalog to be used to +// store any kind of formatting strings. +// +// +// Selecting messages based on linguistic features of substitution arguments +// +// Messages may vary based on any linguistic features of the argument values. +// The most common one is plural form, but others exist. +// +// Selection messages are provided in packages that provide support for a +// specific linguistic feature. The following snippet uses plural.Select: +// +// catalog.Set(language.English, "You are %d minute(s) late.", +// plural.Select(1, +// "one", "You are 1 minute late.", +// "other", "You are %d minutes late.")) +// +// In this example, a message is stored in the Catalog where one of two messages +// is selected based on the first argument, a number. The first message is +// selected if the argument is singular (identified by the selector "one") and +// the second message is selected in all other cases. The selectors are defined +// by the plural rules defined in CLDR. The selector "other" is special and will +// always match. Each language always defines one of the linguistic categories +// to be "other." For English, singular is "one" and plural is "other". +// +// Selects can be nested. This allows selecting sentences based on features of +// multiple arguments or multiple linguistic properties of a single argument. +// +// +// String interpolation +// +// There is often a lot of commonality between the possible variants of a +// message. For instance, in the example above the word "minute" varies based on +// the plural catogory of the argument, but the rest of the sentence is +// identical. Using interpolation the above message can be rewritten as: +// +// catalog.Set(language.English, "You are %d minute(s) late.", +// catalog.Var("minutes", +// plural.Select(1, "one", "minute", "other", "minutes")), +// catalog.String("You are %[1]d ${minutes} late.")) +// +// Var is defined to return the variable name if the message does not yield a +// match. This allows us to further simplify this snippet to +// +// catalog.Set(language.English, "You are %d minute(s) late.", +// catalog.Var("minutes", plural.Select(1, "one", "minute")), +// catalog.String("You are %d ${minutes} late.")) +// +// Overall this is still only a minor improvement, but things can get a lot more +// unwieldy if more than one linguistic feature is used to determine a message +// variant. Consider the following example: +// +// // argument 1: list of hosts, argument 2: list of guests +// catalog.Set(language.English, "%[1]v invite(s) %[2]v to their party.", +// catalog.Var("their", +// plural.Select(1, +// "one", gender.Select(1, "female", "her", "other", "his"))), +// catalog.Var("invites", plural.Select(1, "one", "invite")) +// catalog.String("%[1]v ${invites} %[2]v to ${their} party.")), +// +// Without variable substitution, this would have to be written as +// +// // argument 1: list of hosts, argument 2: list of guests +// catalog.Set(language.English, "%[1]v invite(s) %[2]v to their party.", +// plural.Select(1, +// "one", gender.Select(1, +// "female", "%[1]v invites %[2]v to her party." +// "other", "%[1]v invites %[2]v to his party."), +// "other", "%[1]v invites %[2]v to their party.") +// +// Not necessarily shorter, but using variables there is less duplication and +// the messages are more maintenance friendly. Moreover, languages may have up +// to six plural forms. This makes the use of variables more welcome. +// +// Different messages using the same inflections can reuse variables by moving +// them to macros. Using macros we can rewrite the message as: +// +// // argument 1: list of hosts, argument 2: list of guests +// catalog.SetString(language.English, "%[1]v invite(s) %[2]v to their party.", +// "%[1]v ${invites(1)} %[2]v to ${their(1)} party.") +// +// Where the following macros were defined separately. +// +// catalog.SetMacro(language.English, "invites", plural.Select(1, "one", "invite")) +// catalog.SetMacro(language.English, "their", plural.Select(1, +// "one", gender.Select(1, "female", "her", "other", "his"))), +// +// Placeholders use parentheses and the arguments to invoke a macro. +// +// +// Looking up messages +// +// Message lookup using Catalogs is typically only done by specialized packages +// and is not something the user should be concerned with. For instance, to +// express the tardiness of a user using the related message we defined earlier, +// the user may use the package message like so: +// +// p := message.NewPrinter(language.English) +// p.Printf("You are %d minute(s) late.", 5) +// +// Which would print: +// You are 5 minutes late. +// +// +// This package is UNDER CONSTRUCTION and its API may change. +package catalog // import "golang.org/x/text/message/catalog" + +// TODO: +// Some way to freeze a catalog. +// - Locking on each lockup turns out to be about 50% of the total running time +// for some of the benchmarks in the message package. +// Consider these: +// - Sequence type to support sequences in user-defined messages. +// - Garbage collection: Remove dictionaries that can no longer be reached +// as other dictionaries have been added that cover all possible keys. + +import ( + "errors" + "fmt" + + "golang.org/x/text/internal/catmsg" + "golang.org/x/text/language" +) + +// A Catalog holds translations for messages for supported languages. +type Catalog struct { + options + + index store + macros store +} + +type options struct{} + +// An Option configures Catalog behavior. +type Option func(*options) + +// TODO: +// // Catalogs specifies one or more sources for a Catalog. +// // Lookups are in order. +// // This can be changed inserting a Catalog used for setting, which implements +// // Loader, used for setting in the chain. +// func Catalogs(d ...Loader) Option { +// return nil +// } +// +// func Delims(start, end string) Option {} +// +// func Dict(tag language.Tag, d ...Dictionary) Option + +// New returns a new Catalog. +func New(opts ...Option) *Catalog { + c := &Catalog{} + for _, o := range opts { + o(&c.options) + } + return c +} + +// Languages returns all languages for which the Catalog contains variants. +func (c *Catalog) Languages() []language.Tag { + return c.index.languages() +} + +// SetString is shorthand for Set(tag, key, String(msg)). +func (c *Catalog) SetString(tag language.Tag, key string, msg string) error { + return c.set(tag, key, &c.index, String(msg)) +} + +// Set sets the translation for the given language and key. +// +// When evaluation this message, the first Message in the sequence to msgs to +// evaluate to a string will be the message returned. +func (c *Catalog) Set(tag language.Tag, key string, msg ...Message) error { + return c.set(tag, key, &c.index, msg...) +} + +// SetMacro defines a Message that may be substituted in another message. +// The arguments to a macro Message are passed as arguments in the +// placeholder the form "${foo(arg1, arg2)}". +func (c *Catalog) SetMacro(tag language.Tag, name string, msg ...Message) error { + return c.set(tag, name, &c.macros, msg...) +} + +// ErrNotFound indicates there was no message for the given key. +var ErrNotFound = errors.New("catalog: message not found") + +// A Message holds a collection of translations for the same phrase that may +// vary based on the values of substitution arguments. +type Message interface { + catmsg.Message +} + +// String specifies a plain message string. It can be used as fallback if no +// other strings match or as a simple standalone message. +// +// It is an error to pass more than one String in a message sequence. +func String(name string) Message { + return catmsg.String(name) +} + +// Var sets a variable that may be substituted in formatting patterns using +// named substitution of the form "${name}". The name argument is used as a +// fallback if the statements do not produce a match. The statement sequence may +// not contain any Var calls. +// +// The name passed to a Var must be unique within message sequence. +func Var(name string, msg ...Message) Message { + return &catmsg.Var{Name: name, Message: firstInSequence(msg)} +} + +// firstInSequence is a message type that prints the first message in the +// sequence that resolves to a match for the given substitution arguments. +type firstInSequence []Message + +func (s firstInSequence) Compile(e *catmsg.Encoder) error { + e.EncodeMessageType(catmsg.First) + err := catmsg.ErrIncomplete + for i, m := range s { + if err == nil { + return fmt.Errorf("catalog: message argument %d is complete and blocks subsequent messages", i-1) + } + err = e.EncodeMessage(m) + } + return err +} + +// Context returns a Context for formatting messages. +// Only one Message may be formatted per context at any given time. +func (c *Catalog) Context(tag language.Tag, r catmsg.Renderer) *Context { + return &Context{ + cat: c, + tag: tag, + dec: catmsg.NewDecoder(tag, r, &dict{&c.macros, tag}), + } +} + +// A Context is used for evaluating Messages. +// Only one Message may be formatted per context at any given time. +type Context struct { + cat *Catalog + tag language.Tag + dec *catmsg.Decoder +} + +// Execute looks up and executes the message with the given key. +// It returns ErrNotFound if no message could be found in the index. +func (c *Context) Execute(key string) error { + data, ok := c.cat.index.lookup(c.tag, key) + if !ok { + return ErrNotFound + } + return c.dec.Execute(data) +} diff --git a/vendor/golang.org/x/text/message/catalog/catalog_test.go b/vendor/golang.org/x/text/message/catalog/catalog_test.go new file mode 100644 index 000000000..97ab4d88a --- /dev/null +++ b/vendor/golang.org/x/text/message/catalog/catalog_test.go @@ -0,0 +1,194 @@ +// 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 catalog + +import ( + "bytes" + "fmt" + "reflect" + "testing" + + "golang.org/x/text/internal" + "golang.org/x/text/internal/catmsg" + "golang.org/x/text/language" +) + +type entry struct { + tag, key string + msg interface{} +} + +var testCases = []struct { + desc string + cat []entry + lookup []entry +}{{ + desc: "empty catalog", + lookup: []entry{ + {"en", "key", ""}, + {"en", "", ""}, + {"nl", "", ""}, + }, +}, { + desc: "one entry", + cat: []entry{ + {"en", "hello", "Hello!"}, + }, + lookup: []entry{ + {"und", "hello", ""}, + {"nl", "hello", ""}, + {"en", "hello", "Hello!"}, + {"en-US", "hello", "Hello!"}, + {"en-GB", "hello", "Hello!"}, + {"en-oxendict", "hello", "Hello!"}, + {"en-oxendict-u-ms-metric", "hello", "Hello!"}, + }, +}, { + desc: "hierarchical languages", + cat: []entry{ + {"en", "hello", "Hello!"}, + {"en-GB", "hello", "Hellø!"}, + {"en-US", "hello", "Howdy!"}, + {"en", "greetings", "Greetings!"}, + }, + lookup: []entry{ + {"und", "hello", ""}, + {"nl", "hello", ""}, + {"en", "hello", "Hello!"}, + {"en-US", "hello", "Howdy!"}, + {"en-GB", "hello", "Hellø!"}, + {"en-oxendict", "hello", "Hello!"}, + {"en-US-oxendict-u-ms-metric", "hello", "Howdy!"}, + + {"und", "greetings", ""}, + {"nl", "greetings", ""}, + {"en", "greetings", "Greetings!"}, + {"en-US", "greetings", "Greetings!"}, + {"en-GB", "greetings", "Greetings!"}, + {"en-oxendict", "greetings", "Greetings!"}, + {"en-US-oxendict-u-ms-metric", "greetings", "Greetings!"}, + }, +}, { + desc: "variables", + cat: []entry{ + {"en", "hello %s", []Message{ + Var("person", String("Jane")), + String("Hello ${person}!"), + }}, + {"en", "hello error", []Message{ + Var("person", String("Jane")), + noMatchMessage{}, // trigger sequence path. + String("Hello ${person."), + }}, + {"en", "fallback to var value", []Message{ + Var("you", noMatchMessage{}, noMatchMessage{}), + String("Hello ${you}."), + }}, + {"en", "scopes", []Message{ + Var("person1", String("Mark")), + Var("person2", String("Jane")), + Var("couple", + Var("person1", String("Joe")), + String("${person1} and ${person2}")), + String("Hello ${couple}."), + }}, + {"en", "missing var", String("Hello ${missing}.")}, + }, + lookup: []entry{ + {"en", "hello %s", "Hello Jane!"}, + {"en", "hello error", "Hello $!(MISSINGBRACE)"}, + {"en", "fallback to var value", "Hello you."}, + {"en", "scopes", "Hello Joe and Jane."}, + {"en", "missing var", "Hello missing."}, + }, +}, { + desc: "macros", + cat: []entry{ + {"en", "macro1", String("Hello ${macro1(1)}.")}, + {"en", "macro2", String("Hello ${ macro1(2) }!")}, + {"en", "macroWS", String("Hello ${ macro1( 2 ) }!")}, + {"en", "missing", String("Hello ${ missing(1 }.")}, + {"en", "badnum", String("Hello ${ badnum(1b) }.")}, + {"en", "undefined", String("Hello ${ undefined(1) }.")}, + {"en", "macroU", String("Hello ${ macroU(2) }!")}, + }, + lookup: []entry{ + {"en", "macro1", "Hello Joe."}, + {"en", "macro2", "Hello Joe!"}, + {"en-US", "macroWS", "Hello Joe!"}, + {"en-NL", "missing", "Hello $!(MISSINGPAREN)."}, + {"en", "badnum", "Hello $!(BADNUM)."}, + {"en", "undefined", "Hello undefined."}, + {"en", "macroU", "Hello macroU!"}, + }}} + +func initCat(entries []entry) (*Catalog, []language.Tag) { + tags := []language.Tag{} + cat := New() + for _, e := range entries { + tag := language.MustParse(e.tag) + tags = append(tags, tag) + switch msg := e.msg.(type) { + case string: + cat.SetString(tag, e.key, msg) + case Message: + cat.Set(tag, e.key, msg) + case []Message: + cat.Set(tag, e.key, msg...) + } + } + return cat, internal.UniqueTags(tags) +} + +func TestCatalog(t *testing.T) { + for _, tc := range testCases { + t.Run(fmt.Sprintf("%s", tc.desc), func(t *testing.T) { + cat, wantTags := initCat(tc.cat) + cat.SetMacro(language.English, "macro1", String("Joe")) + cat.SetMacro(language.Und, "macro2", String("${macro1(1)}")) + cat.SetMacro(language.English, "macroU", noMatchMessage{}) + + if got := cat.Languages(); !reflect.DeepEqual(got, wantTags) { + t.Errorf("%s:Languages: got %v; want %v", tc.desc, got, wantTags) + } + + for _, e := range tc.lookup { + t.Run(fmt.Sprintf("%s/%s", e.tag, e.key), func(t *testing.T) { + tag := language.MustParse(e.tag) + buf := testRenderer{} + ctx := cat.Context(tag, &buf) + want := e.msg.(string) + err := ctx.Execute(e.key) + gotFound := err != ErrNotFound + wantFound := want != "" + if gotFound != wantFound { + t.Fatalf("err: got %v (%v); want %v", gotFound, err, wantFound) + } + if got := buf.buf.String(); got != want { + t.Errorf("Lookup:\ngot %q\nwant %q", got, want) + } + }) + } + }) + } +} + +type testRenderer struct { + buf bytes.Buffer +} + +func (f *testRenderer) Arg(i int) interface{} { return nil } +func (f *testRenderer) Render(s string) { f.buf.WriteString(s) } + +var msgNoMatch = catmsg.Register("no match", func(d *catmsg.Decoder) bool { + return false // no match +}) + +type noMatchMessage struct{} + +func (noMatchMessage) Compile(e *catmsg.Encoder) error { + e.EncodeMessageType(msgNoMatch) + return catmsg.ErrIncomplete +} diff --git a/vendor/golang.org/x/text/message/catalog/dict.go b/vendor/golang.org/x/text/message/catalog/dict.go new file mode 100644 index 000000000..1810fabc6 --- /dev/null +++ b/vendor/golang.org/x/text/message/catalog/dict.go @@ -0,0 +1,90 @@ +// 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 catalog + +import ( + "sync" + + "golang.org/x/text/internal" + "golang.org/x/text/internal/catmsg" + "golang.org/x/text/language" +) + +// TODO: +// Dictionary returns a Dictionary that returns the first Message, using the +// given language tag, that matches: +// 1. the last one registered by one of the Set methods +// 2. returned by one of the Loaders +// 3. repeat from 1. using the parent language +// This approach allows messages to be underspecified. +// func (c *Catalog) Dictionary(tag language.Tag) (Dictionary, error) { +// // TODO: verify dictionary exists. +// return &dict{&c.index, tag}, nil +// } + +type dict struct { + s *store + tag language.Tag // TODO: make compact tag. +} + +func (d *dict) Lookup(key string) (data string, ok bool) { + return d.s.lookup(d.tag, key) +} + +func (c *Catalog) set(tag language.Tag, key string, s *store, msg ...Message) error { + data, err := catmsg.Compile(tag, &dict{&c.macros, tag}, firstInSequence(msg)) + + s.mutex.Lock() + defer s.mutex.Unlock() + + m := s.index[tag] + if m == nil { + m = msgMap{} + if s.index == nil { + s.index = map[language.Tag]msgMap{} + } + s.index[tag] = m + } + + m[key] = data + return err +} + +type store struct { + mutex sync.RWMutex + index map[language.Tag]msgMap +} + +type msgMap map[string]string + +func (s *store) lookup(tag language.Tag, key string) (data string, ok bool) { + s.mutex.RLock() + defer s.mutex.RUnlock() + + for ; ; tag = tag.Parent() { + if msgs, ok := s.index[tag]; ok { + if msg, ok := msgs[key]; ok { + return msg, true + } + } + if tag == language.Und { + break + } + } + return "", false +} + +// Languages returns all languages for which the store contains variants. +func (s *store) languages() []language.Tag { + s.mutex.RLock() + defer s.mutex.RUnlock() + + tags := make([]language.Tag, 0, len(s.index)) + for t := range s.index { + tags = append(tags, t) + } + internal.SortTags(tags) + return tags +} diff --git a/vendor/golang.org/x/text/message/catalog_test.go b/vendor/golang.org/x/text/message/catalog_test.go deleted file mode 100644 index 3b693c956..000000000 --- a/vendor/golang.org/x/text/message/catalog_test.go +++ /dev/null @@ -1,98 +0,0 @@ -// 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 message - -import ( - "reflect" - "testing" - - "golang.org/x/text/internal" - "golang.org/x/text/language" -) - -type entry struct{ tag, key, msg string } - -var testCases = []struct { - desc string - cat []entry - lookup []entry -}{{ - desc: "empty catalog", - lookup: []entry{ - {"en", "key", ""}, - {"en", "", ""}, - {"nl", "", ""}, - }, -}, { - desc: "one entry", - cat: []entry{ - {"en", "hello", "Hello!"}, - }, - lookup: []entry{ - {"und", "hello", ""}, - {"nl", "hello", ""}, - {"en", "hello", "Hello!"}, - {"en-US", "hello", "Hello!"}, - {"en-GB", "hello", "Hello!"}, - {"en-oxendict", "hello", "Hello!"}, - {"en-oxendict-u-ms-metric", "hello", "Hello!"}, - }, -}, { - desc: "hierarchical languages", - cat: []entry{ - {"en", "hello", "Hello!"}, - {"en-GB", "hello", "Hellø!"}, - {"en-US", "hello", "Howdy!"}, - {"en", "greetings", "Greetings!"}, - }, - lookup: []entry{ - {"und", "hello", ""}, - {"nl", "hello", ""}, - {"en", "hello", "Hello!"}, - {"en-US", "hello", "Howdy!"}, - {"en-GB", "hello", "Hellø!"}, - {"en-oxendict", "hello", "Hello!"}, - {"en-US-oxendict-u-ms-metric", "hello", "Howdy!"}, - - {"und", "greetings", ""}, - {"nl", "greetings", ""}, - {"en", "greetings", "Greetings!"}, - {"en-US", "greetings", "Greetings!"}, - {"en-GB", "greetings", "Greetings!"}, - {"en-oxendict", "greetings", "Greetings!"}, - {"en-US-oxendict-u-ms-metric", "greetings", "Greetings!"}, - }, -}} - -func initCat(entries []entry) (*Catalog, []language.Tag) { - tags := []language.Tag{} - cat := newCatalog() - for _, e := range entries { - tag := language.MustParse(e.tag) - tags = append(tags, tag) - cat.SetString(tag, e.key, e.msg) - } - return cat, internal.UniqueTags(tags) -} - -func TestCatalog(t *testing.T) { - for _, tc := range testCases { - cat, wantTags := initCat(tc.cat) - - // languages - if got := cat.Languages(); !reflect.DeepEqual(got, wantTags) { - t.Errorf("%s:Languages: got %v; want %v", tc.desc, got, wantTags) - } - - // Lookup - for _, e := range tc.lookup { - tag := language.MustParse(e.tag) - msg, ok := cat.get(tag, e.key) - if okWant := e.msg != ""; ok != okWant || msg != e.msg { - t.Errorf("%s:Lookup(%s, %s) = %s, %v; want %s, %v", tc.desc, tag, e.key, msg, ok, e.msg, okWant) - } - } - } -} diff --git a/vendor/golang.org/x/text/message/fmt_test.go b/vendor/golang.org/x/text/message/fmt_test.go new file mode 100755 index 000000000..d02808a92 --- /dev/null +++ b/vendor/golang.org/x/text/message/fmt_test.go @@ -0,0 +1,1871 @@ +// 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 message + +import ( + "bytes" + "fmt" + "io" + "math" + "reflect" + "runtime" + "strings" + "testing" + "time" + + "golang.org/x/text/language" +) + +type ( + renamedBool bool + renamedInt int + renamedInt8 int8 + renamedInt16 int16 + renamedInt32 int32 + renamedInt64 int64 + renamedUint uint + renamedUint8 uint8 + renamedUint16 uint16 + renamedUint32 uint32 + renamedUint64 uint64 + renamedUintptr uintptr + renamedString string + renamedBytes []byte + renamedFloat32 float32 + renamedFloat64 float64 + renamedComplex64 complex64 + renamedComplex128 complex128 +) + +func TestFmtInterface(t *testing.T) { + p := NewPrinter(language.Und) + var i1 interface{} + i1 = "abc" + s := p.Sprintf("%s", i1) + if s != "abc" { + t.Errorf(`Sprintf("%%s", empty("abc")) = %q want %q`, s, "abc") + } +} + +var ( + NaN = math.NaN() + posInf = math.Inf(1) + negInf = math.Inf(-1) + + intVar = 0 + + array = [5]int{1, 2, 3, 4, 5} + iarray = [4]interface{}{1, "hello", 2.5, nil} + slice = array[:] + islice = iarray[:] +) + +type A struct { + i int + j uint + s string + x []int +} + +type I int + +func (i I) String() string { + p := NewPrinter(language.Und) + return p.Sprintf("<%d>", int(i)) +} + +type B struct { + I I + j int +} + +type C struct { + i int + B +} + +type F int + +func (f F) Format(s fmt.State, c rune) { + p := NewPrinter(language.Und) + p.Fprintf(s, "<%c=F(%d)>", c, int(f)) +} + +type G int + +func (g G) GoString() string { + p := NewPrinter(language.Und) + return p.Sprintf("GoString(%d)", int(g)) +} + +type S struct { + F F // a struct field that Formats + G G // a struct field that GoStrings +} + +type SI struct { + I interface{} +} + +// P is a type with a String method with pointer receiver for testing %p. +type P int + +var pValue P + +func (p *P) String() string { + return "String(p)" +} + +var barray = [5]renamedUint8{1, 2, 3, 4, 5} +var bslice = barray[:] + +type byteStringer byte + +func (byteStringer) String() string { + return "X" +} + +var byteStringerSlice = []byteStringer{'h', 'e', 'l', 'l', 'o'} + +type byteFormatter byte + +func (byteFormatter) Format(f fmt.State, _ rune) { + p := NewPrinter(language.Und) + p.Fprint(f, "X") +} + +var byteFormatterSlice = []byteFormatter{'h', 'e', 'l', 'l', 'o'} + +var fmtTests = []struct { + fmt string + val interface{} + out string +}{ + // The behavior of the following tests differs from that of the fmt package. + + // Unlike with the fmt package, it is okay to have extra arguments for + // strings without format parameters. This is because it is impossible to + // distinguish between reordered or ordered format strings in this case. + // (For reordered format strings it is okay to not use arguments.) + {"", nil, ""}, + {"", 2, ""}, + {"no args", "hello", "no args"}, + + {"%017091901790959340919092959340919017929593813360", 0, "%!(NOVERB)"}, + {"%184467440737095516170v", 0, "%!(NOVERB)"}, + // Extra argument errors should format without flags set. + {"%010.2", "12345", "%!(NOVERB)"}, + + // All following tests are identical to that of the fmt package. + {"%d", 12345, "12345"}, + {"%v", 12345, "12345"}, + {"%t", true, "true"}, + + // basic string + {"%s", "abc", "abc"}, + {"%q", "abc", `"abc"`}, + {"%x", "abc", "616263"}, + {"%x", "\xff\xf0\x0f\xff", "fff00fff"}, + {"%X", "\xff\xf0\x0f\xff", "FFF00FFF"}, + {"%x", "", ""}, + {"% x", "", ""}, + {"%#x", "", ""}, + {"%# x", "", ""}, + {"%x", "xyz", "78797a"}, + {"%X", "xyz", "78797A"}, + {"% x", "xyz", "78 79 7a"}, + {"% X", "xyz", "78 79 7A"}, + {"%#x", "xyz", "0x78797a"}, + {"%#X", "xyz", "0X78797A"}, + {"%# x", "xyz", "0x78 0x79 0x7a"}, + {"%# X", "xyz", "0X78 0X79 0X7A"}, + + // basic bytes + {"%s", []byte("abc"), "abc"}, + {"%s", [3]byte{'a', 'b', 'c'}, "abc"}, + {"%s", &[3]byte{'a', 'b', 'c'}, "&abc"}, + {"%q", []byte("abc"), `"abc"`}, + {"%x", []byte("abc"), "616263"}, + {"%x", []byte("\xff\xf0\x0f\xff"), "fff00fff"}, + {"%X", []byte("\xff\xf0\x0f\xff"), "FFF00FFF"}, + {"%x", []byte(""), ""}, + {"% x", []byte(""), ""}, + {"%#x", []byte(""), ""}, + {"%# x", []byte(""), ""}, + {"%x", []byte("xyz"), "78797a"}, + {"%X", []byte("xyz"), "78797A"}, + {"% x", []byte("xyz"), "78 79 7a"}, + {"% X", []byte("xyz"), "78 79 7A"}, + {"%#x", []byte("xyz"), "0x78797a"}, + {"%#X", []byte("xyz"), "0X78797A"}, + {"%# x", []byte("xyz"), "0x78 0x79 0x7a"}, + {"%# X", []byte("xyz"), "0X78 0X79 0X7A"}, + + // escaped strings + {"%q", "", `""`}, + {"%#q", "", "``"}, + {"%q", "\"", `"\""`}, + {"%#q", "\"", "`\"`"}, + {"%q", "`", `"` + "`" + `"`}, + {"%#q", "`", `"` + "`" + `"`}, + {"%q", "\n", `"\n"`}, + {"%#q", "\n", `"\n"`}, + {"%q", `\n`, `"\\n"`}, + {"%#q", `\n`, "`\\n`"}, + {"%q", "abc", `"abc"`}, + {"%#q", "abc", "`abc`"}, + {"%q", "日本語", `"日本語"`}, + {"%+q", "日本語", `"\u65e5\u672c\u8a9e"`}, + {"%#q", "日本語", "`日本語`"}, + {"%#+q", "日本語", "`日本語`"}, + {"%q", "\a\b\f\n\r\t\v\"\\", `"\a\b\f\n\r\t\v\"\\"`}, + {"%+q", "\a\b\f\n\r\t\v\"\\", `"\a\b\f\n\r\t\v\"\\"`}, + {"%#q", "\a\b\f\n\r\t\v\"\\", `"\a\b\f\n\r\t\v\"\\"`}, + {"%#+q", "\a\b\f\n\r\t\v\"\\", `"\a\b\f\n\r\t\v\"\\"`}, + {"%q", "☺", `"☺"`}, + {"% q", "☺", `"☺"`}, // The space modifier should have no effect. + {"%+q", "☺", `"\u263a"`}, + {"%#q", "☺", "`☺`"}, + {"%#+q", "☺", "`☺`"}, + {"%10q", "⌘", ` "⌘"`}, + {"%+10q", "⌘", ` "\u2318"`}, + {"%-10q", "⌘", `"⌘" `}, + {"%+-10q", "⌘", `"\u2318" `}, + {"%010q", "⌘", `0000000"⌘"`}, + {"%+010q", "⌘", `00"\u2318"`}, + {"%-010q", "⌘", `"⌘" `}, // 0 has no effect when - is present. + {"%+-010q", "⌘", `"\u2318" `}, + {"%#8q", "\n", ` "\n"`}, + {"%#+8q", "\r", ` "\r"`}, + {"%#-8q", "\t", "` ` "}, + {"%#+-8q", "\b", `"\b" `}, + {"%q", "abc\xffdef", `"abc\xffdef"`}, + {"%+q", "abc\xffdef", `"abc\xffdef"`}, + {"%#q", "abc\xffdef", `"abc\xffdef"`}, + {"%#+q", "abc\xffdef", `"abc\xffdef"`}, + // Runes that are not printable. + {"%q", "\U0010ffff", `"\U0010ffff"`}, + {"%+q", "\U0010ffff", `"\U0010ffff"`}, + {"%#q", "\U0010ffff", "`􏿿`"}, + {"%#+q", "\U0010ffff", "`􏿿`"}, + // Runes that are not valid. + {"%q", string(0x110000), `"�"`}, + {"%+q", string(0x110000), `"\ufffd"`}, + {"%#q", string(0x110000), "`�`"}, + {"%#+q", string(0x110000), "`�`"}, + + // characters + {"%c", uint('x'), "x"}, + {"%c", 0xe4, "ä"}, + {"%c", 0x672c, "本"}, + {"%c", '日', "日"}, + {"%.0c", '⌘', "⌘"}, // Specifying precision should have no effect. + {"%3c", '⌘', " ⌘"}, + {"%-3c", '⌘', "⌘ "}, + // Runes that are not printable. + {"%c", '\U00000e00', "\u0e00"}, + {"%c", '\U0010ffff', "\U0010ffff"}, + // Runes that are not valid. + {"%c", -1, "�"}, + {"%c", 0xDC80, "�"}, + {"%c", rune(0x110000), "�"}, + {"%c", int64(0xFFFFFFFFF), "�"}, + {"%c", uint64(0xFFFFFFFFF), "�"}, + + // escaped characters + {"%q", uint(0), `'\x00'`}, + {"%+q", uint(0), `'\x00'`}, + {"%q", '"', `'"'`}, + {"%+q", '"', `'"'`}, + {"%q", '\'', `'\''`}, + {"%+q", '\'', `'\''`}, + {"%q", '`', "'`'"}, + {"%+q", '`', "'`'"}, + {"%q", 'x', `'x'`}, + {"%+q", 'x', `'x'`}, + {"%q", 'ÿ', `'ÿ'`}, + {"%+q", 'ÿ', `'\u00ff'`}, + {"%q", '\n', `'\n'`}, + {"%+q", '\n', `'\n'`}, + {"%q", '☺', `'☺'`}, + {"%+q", '☺', `'\u263a'`}, + {"% q", '☺', `'☺'`}, // The space modifier should have no effect. + {"%.0q", '☺', `'☺'`}, // Specifying precision should have no effect. + {"%10q", '⌘', ` '⌘'`}, + {"%+10q", '⌘', ` '\u2318'`}, + {"%-10q", '⌘', `'⌘' `}, + {"%+-10q", '⌘', `'\u2318' `}, + {"%010q", '⌘', `0000000'⌘'`}, + {"%+010q", '⌘', `00'\u2318'`}, + {"%-010q", '⌘', `'⌘' `}, // 0 has no effect when - is present. + {"%+-010q", '⌘', `'\u2318' `}, + // Runes that are not printable. + {"%q", '\U00000e00', `'\u0e00'`}, + {"%q", '\U0010ffff', `'\U0010ffff'`}, + // Runes that are not valid. + {"%q", int32(-1), "%!q(int32=-1)"}, + {"%q", 0xDC80, `'�'`}, + {"%q", rune(0x110000), "%!q(int32=1114112)"}, + {"%q", int64(0xFFFFFFFFF), "%!q(int64=68719476735)"}, + {"%q", uint64(0xFFFFFFFFF), "%!q(uint64=68719476735)"}, + + // width + {"%5s", "abc", " abc"}, + {"%2s", "\u263a", " ☺"}, + {"%-5s", "abc", "abc "}, + {"%-8q", "abc", `"abc" `}, + {"%05s", "abc", "00abc"}, + {"%08q", "abc", `000"abc"`}, + {"%5s", "abcdefghijklmnopqrstuvwxyz", "abcdefghijklmnopqrstuvwxyz"}, + {"%.5s", "abcdefghijklmnopqrstuvwxyz", "abcde"}, + {"%.0s", "日本語日本語", ""}, + {"%.5s", "日本語日本語", "日本語日本"}, + {"%.10s", "日本語日本語", "日本語日本語"}, + {"%.5s", []byte("日本語日本語"), "日本語日本"}, + {"%.5q", "abcdefghijklmnopqrstuvwxyz", `"abcde"`}, + {"%.5x", "abcdefghijklmnopqrstuvwxyz", "6162636465"}, + {"%.5q", []byte("abcdefghijklmnopqrstuvwxyz"), `"abcde"`}, + {"%.5x", []byte("abcdefghijklmnopqrstuvwxyz"), "6162636465"}, + {"%.3q", "日本語日本語", `"日本語"`}, + {"%.3q", []byte("日本語日本語"), `"日本語"`}, + {"%.1q", "日本語", `"日"`}, + {"%.1q", []byte("日本語"), `"日"`}, + {"%.1x", "日本語", "e6"}, + {"%.1X", []byte("日本語"), "E6"}, + {"%10.1q", "日本語日本語", ` "日"`}, + {"%10v", nil, " "}, + {"%-10v", nil, " "}, + + // integers + {"%d", uint(12345), "12345"}, + {"%d", int(-12345), "-12345"}, + {"%d", ^uint8(0), "255"}, + {"%d", ^uint16(0), "65535"}, + {"%d", ^uint32(0), "4294967295"}, + {"%d", ^uint64(0), "18446744073709551615"}, + {"%d", int8(-1 << 7), "-128"}, + {"%d", int16(-1 << 15), "-32768"}, + {"%d", int32(-1 << 31), "-2147483648"}, + {"%d", int64(-1 << 63), "-9223372036854775808"}, + {"%.d", 0, ""}, + {"%.0d", 0, ""}, + {"%6.0d", 0, " "}, + {"%06.0d", 0, " "}, + {"% d", 12345, " 12345"}, + {"%+d", 12345, "+12345"}, + {"%+d", -12345, "-12345"}, + {"%b", 7, "111"}, + {"%b", -6, "-110"}, + {"%b", ^uint32(0), "11111111111111111111111111111111"}, + {"%b", ^uint64(0), "1111111111111111111111111111111111111111111111111111111111111111"}, + {"%b", int64(-1 << 63), zeroFill("-1", 63, "")}, + {"%o", 01234, "1234"}, + {"%#o", 01234, "01234"}, + {"%o", ^uint32(0), "37777777777"}, + {"%o", ^uint64(0), "1777777777777777777777"}, + {"%#X", 0, "0X0"}, + {"%x", 0x12abcdef, "12abcdef"}, + {"%X", 0x12abcdef, "12ABCDEF"}, + {"%x", ^uint32(0), "ffffffff"}, + {"%X", ^uint64(0), "FFFFFFFFFFFFFFFF"}, + {"%.20b", 7, "00000000000000000111"}, + {"%10d", 12345, " 12345"}, + {"%10d", -12345, " -12345"}, + {"%+10d", 12345, " +12345"}, + {"%010d", 12345, "0000012345"}, + {"%010d", -12345, "-000012345"}, + {"%20.8d", 1234, " 00001234"}, + {"%20.8d", -1234, " -00001234"}, + {"%020.8d", 1234, " 00001234"}, + {"%020.8d", -1234, " -00001234"}, + {"%-20.8d", 1234, "00001234 "}, + {"%-20.8d", -1234, "-00001234 "}, + {"%-#20.8x", 0x1234abc, "0x01234abc "}, + {"%-#20.8X", 0x1234abc, "0X01234ABC "}, + {"%-#20.8o", 01234, "00001234 "}, + + // Test correct f.intbuf overflow checks. + {"%068d", 1, zeroFill("", 68, "1")}, + {"%068d", -1, zeroFill("-", 67, "1")}, + {"%#.68x", 42, zeroFill("0x", 68, "2a")}, + {"%.68d", -42, zeroFill("-", 68, "42")}, + {"%+.68d", 42, zeroFill("+", 68, "42")}, + {"% .68d", 42, zeroFill(" ", 68, "42")}, + {"% +.68d", 42, zeroFill("+", 68, "42")}, + + // unicode format + {"%U", 0, "U+0000"}, + {"%U", -1, "U+FFFFFFFFFFFFFFFF"}, + {"%U", '\n', `U+000A`}, + {"%#U", '\n', `U+000A`}, + {"%+U", 'x', `U+0078`}, // Plus flag should have no effect. + {"%# U", 'x', `U+0078 'x'`}, // Space flag should have no effect. + {"%#.2U", 'x', `U+0078 'x'`}, // Precisions below 4 should print 4 digits. + {"%U", '\u263a', `U+263A`}, + {"%#U", '\u263a', `U+263A '☺'`}, + {"%U", '\U0001D6C2', `U+1D6C2`}, + {"%#U", '\U0001D6C2', `U+1D6C2 '𝛂'`}, + {"%#14.6U", '⌘', " U+002318 '⌘'"}, + {"%#-14.6U", '⌘', "U+002318 '⌘' "}, + {"%#014.6U", '⌘', " U+002318 '⌘'"}, + {"%#-014.6U", '⌘', "U+002318 '⌘' "}, + {"%.68U", uint(42), zeroFill("U+", 68, "2A")}, + {"%#.68U", '日', zeroFill("U+", 68, "65E5") + " '日'"}, + + // floats + {"%+.3e", 0.0, "+0.000e+00"}, + {"%+.3e", 1.0, "+1.000e+00"}, + {"%+.3f", -1.0, "-1.000"}, + {"%+.3F", -1.0, "-1.000"}, + {"%+.3F", float32(-1.0), "-1.000"}, + {"%+07.2f", 1.0, "+001.00"}, + {"%+07.2f", -1.0, "-001.00"}, + {"%-07.2f", 1.0, "1.00 "}, + {"%-07.2f", -1.0, "-1.00 "}, + {"%+-07.2f", 1.0, "+1.00 "}, + {"%+-07.2f", -1.0, "-1.00 "}, + {"%-+07.2f", 1.0, "+1.00 "}, + {"%-+07.2f", -1.0, "-1.00 "}, + {"%+10.2f", +1.0, " +1.00"}, + {"%+10.2f", -1.0, " -1.00"}, + {"% .3E", -1.0, "-1.000E+00"}, + {"% .3e", 1.0, " 1.000e+00"}, + {"%+.3g", 0.0, "+0"}, + {"%+.3g", 1.0, "+1"}, + {"%+.3g", -1.0, "-1"}, + {"% .3g", -1.0, "-1"}, + {"% .3g", 1.0, " 1"}, + {"%b", float32(1.0), "8388608p-23"}, + {"%b", 1.0, "4503599627370496p-52"}, + // Test sharp flag used with floats. + {"%#g", 1e-323, "1.00000e-323"}, + {"%#g", -1.0, "-1.00000"}, + {"%#g", 1.1, "1.10000"}, + {"%#g", 123456.0, "123456."}, + {"%#g", 1234567.0, "1.234567e+06"}, + {"%#g", 1230000.0, "1.23000e+06"}, + {"%#g", 1000000.0, "1.00000e+06"}, + {"%#.0f", 1.0, "1."}, + {"%#.0e", 1.0, "1.e+00"}, + {"%#.0g", 1.0, "1."}, + {"%#.0g", 1100000.0, "1.e+06"}, + {"%#.4f", 1.0, "1.0000"}, + {"%#.4e", 1.0, "1.0000e+00"}, + {"%#.4g", 1.0, "1.000"}, + {"%#.4g", 100000.0, "1.000e+05"}, + {"%#.0f", 123.0, "123."}, + {"%#.0e", 123.0, "1.e+02"}, + {"%#.0g", 123.0, "1.e+02"}, + {"%#.4f", 123.0, "123.0000"}, + {"%#.4e", 123.0, "1.2300e+02"}, + {"%#.4g", 123.0, "123.0"}, + {"%#.4g", 123000.0, "1.230e+05"}, + {"%#9.4g", 1.0, " 1.000"}, + // The sharp flag has no effect for binary float format. + {"%#b", 1.0, "4503599627370496p-52"}, + // Precision has no effect for binary float format. + {"%.4b", float32(1.0), "8388608p-23"}, + {"%.4b", -1.0, "-4503599627370496p-52"}, + // Test correct f.intbuf boundary checks. + {"%.68f", 1.0, zeroFill("1.", 68, "")}, + {"%.68f", -1.0, zeroFill("-1.", 68, "")}, + // float infinites and NaNs + {"%f", posInf, "+Inf"}, + {"%.1f", negInf, "-Inf"}, + {"% f", NaN, " NaN"}, + {"%20f", posInf, " +Inf"}, + {"% 20F", posInf, " Inf"}, + {"% 20e", negInf, " -Inf"}, + {"%+20E", negInf, " -Inf"}, + {"% +20g", negInf, " -Inf"}, + {"%+-20G", posInf, "+Inf "}, + {"%20e", NaN, " NaN"}, + {"% +20E", NaN, " +NaN"}, + {"% -20g", NaN, " NaN "}, + {"%+-20G", NaN, "+NaN "}, + // Zero padding does not apply to infinities and NaN. + {"%+020e", posInf, " +Inf"}, + {"%-020f", negInf, "-Inf "}, + {"%-020E", NaN, "NaN "}, + + // complex values + {"%.f", 0i, "(0+0i)"}, + {"% .f", 0i, "( 0+0i)"}, + {"%+.f", 0i, "(+0+0i)"}, + {"% +.f", 0i, "(+0+0i)"}, + {"%+.3e", 0i, "(+0.000e+00+0.000e+00i)"}, + {"%+.3f", 0i, "(+0.000+0.000i)"}, + {"%+.3g", 0i, "(+0+0i)"}, + {"%+.3e", 1 + 2i, "(+1.000e+00+2.000e+00i)"}, + {"%+.3f", 1 + 2i, "(+1.000+2.000i)"}, + {"%+.3g", 1 + 2i, "(+1+2i)"}, + {"%.3e", 0i, "(0.000e+00+0.000e+00i)"}, + {"%.3f", 0i, "(0.000+0.000i)"}, + {"%.3F", 0i, "(0.000+0.000i)"}, + {"%.3F", complex64(0i), "(0.000+0.000i)"}, + {"%.3g", 0i, "(0+0i)"}, + {"%.3e", 1 + 2i, "(1.000e+00+2.000e+00i)"}, + {"%.3f", 1 + 2i, "(1.000+2.000i)"}, + {"%.3g", 1 + 2i, "(1+2i)"}, + {"%.3e", -1 - 2i, "(-1.000e+00-2.000e+00i)"}, + {"%.3f", -1 - 2i, "(-1.000-2.000i)"}, + {"%.3g", -1 - 2i, "(-1-2i)"}, + {"% .3E", -1 - 2i, "(-1.000E+00-2.000E+00i)"}, + {"%+.3g", 1 + 2i, "(+1+2i)"}, + {"%+.3g", complex64(1 + 2i), "(+1+2i)"}, + {"%#g", 1 + 2i, "(1.00000+2.00000i)"}, + {"%#g", 123456 + 789012i, "(123456.+789012.i)"}, + {"%#g", 1e-10i, "(0.00000+1.00000e-10i)"}, + {"%#g", -1e10 - 1.11e100i, "(-1.00000e+10-1.11000e+100i)"}, + {"%#.0f", 1.23 + 1.0i, "(1.+1.i)"}, + {"%#.0e", 1.23 + 1.0i, "(1.e+00+1.e+00i)"}, + {"%#.0g", 1.23 + 1.0i, "(1.+1.i)"}, + {"%#.0g", 0 + 100000i, "(0.+1.e+05i)"}, + {"%#.0g", 1230000 + 0i, "(1.e+06+0.i)"}, + {"%#.4f", 1 + 1.23i, "(1.0000+1.2300i)"}, + {"%#.4e", 123 + 1i, "(1.2300e+02+1.0000e+00i)"}, + {"%#.4g", 123 + 1.23i, "(123.0+1.230i)"}, + {"%#12.5g", 0 + 100000i, "( 0.0000 +1.0000e+05i)"}, + {"%#12.5g", 1230000 - 0i, "( 1.2300e+06 +0.0000i)"}, + {"%b", 1 + 2i, "(4503599627370496p-52+4503599627370496p-51i)"}, + {"%b", complex64(1 + 2i), "(8388608p-23+8388608p-22i)"}, + // The sharp flag has no effect for binary complex format. + {"%#b", 1 + 2i, "(4503599627370496p-52+4503599627370496p-51i)"}, + // Precision has no effect for binary complex format. + {"%.4b", 1 + 2i, "(4503599627370496p-52+4503599627370496p-51i)"}, + {"%.4b", complex64(1 + 2i), "(8388608p-23+8388608p-22i)"}, + // complex infinites and NaNs + {"%f", complex(posInf, posInf), "(+Inf+Infi)"}, + {"%f", complex(negInf, negInf), "(-Inf-Infi)"}, + {"%f", complex(NaN, NaN), "(NaN+NaNi)"}, + {"%.1f", complex(posInf, posInf), "(+Inf+Infi)"}, + {"% f", complex(posInf, posInf), "( Inf+Infi)"}, + {"% f", complex(negInf, negInf), "(-Inf-Infi)"}, + {"% f", complex(NaN, NaN), "( NaN+NaNi)"}, + {"%8e", complex(posInf, posInf), "( +Inf +Infi)"}, + {"% 8E", complex(posInf, posInf), "( Inf +Infi)"}, + {"%+8f", complex(negInf, negInf), "( -Inf -Infi)"}, + {"% +8g", complex(negInf, negInf), "( -Inf -Infi)"}, + {"% -8G", complex(NaN, NaN), "( NaN +NaN i)"}, + {"%+-8b", complex(NaN, NaN), "(+NaN +NaN i)"}, + // Zero padding does not apply to infinities and NaN. + {"%08f", complex(posInf, posInf), "( +Inf +Infi)"}, + {"%-08g", complex(negInf, negInf), "(-Inf -Inf i)"}, + {"%-08G", complex(NaN, NaN), "(NaN +NaN i)"}, + + // old test/fmt_test.go + {"%e", 1.0, "1.000000e+00"}, + {"%e", 1234.5678e3, "1.234568e+06"}, + {"%e", 1234.5678e-8, "1.234568e-05"}, + {"%e", -7.0, "-7.000000e+00"}, + {"%e", -1e-9, "-1.000000e-09"}, + {"%f", 1234.5678e3, "1234567.800000"}, + {"%f", 1234.5678e-8, "0.000012"}, + {"%f", -7.0, "-7.000000"}, + {"%f", -1e-9, "-0.000000"}, + {"%g", 1234.5678e3, "1.2345678e+06"}, + {"%g", float32(1234.5678e3), "1.2345678e+06"}, + {"%g", 1234.5678e-8, "1.2345678e-05"}, + {"%g", -7.0, "-7"}, + {"%g", -1e-9, "-1e-09"}, + {"%g", float32(-1e-9), "-1e-09"}, + {"%E", 1.0, "1.000000E+00"}, + {"%E", 1234.5678e3, "1.234568E+06"}, + {"%E", 1234.5678e-8, "1.234568E-05"}, + {"%E", -7.0, "-7.000000E+00"}, + {"%E", -1e-9, "-1.000000E-09"}, + {"%G", 1234.5678e3, "1.2345678E+06"}, + {"%G", float32(1234.5678e3), "1.2345678E+06"}, + {"%G", 1234.5678e-8, "1.2345678E-05"}, + {"%G", -7.0, "-7"}, + {"%G", -1e-9, "-1E-09"}, + {"%G", float32(-1e-9), "-1E-09"}, + {"%20.5s", "qwertyuiop", " qwert"}, + {"%.5s", "qwertyuiop", "qwert"}, + {"%-20.5s", "qwertyuiop", "qwert "}, + {"%20c", 'x', " x"}, + {"%-20c", 'x', "x "}, + {"%20.6e", 1.2345e3, " 1.234500e+03"}, + {"%20.6e", 1.2345e-3, " 1.234500e-03"}, + {"%20e", 1.2345e3, " 1.234500e+03"}, + {"%20e", 1.2345e-3, " 1.234500e-03"}, + {"%20.8e", 1.2345e3, " 1.23450000e+03"}, + {"%20f", 1.23456789e3, " 1234.567890"}, + {"%20f", 1.23456789e-3, " 0.001235"}, + {"%20f", 12345678901.23456789, " 12345678901.234568"}, + {"%-20f", 1.23456789e3, "1234.567890 "}, + {"%20.8f", 1.23456789e3, " 1234.56789000"}, + {"%20.8f", 1.23456789e-3, " 0.00123457"}, + {"%g", 1.23456789e3, "1234.56789"}, + {"%g", 1.23456789e-3, "0.00123456789"}, + {"%g", 1.23456789e20, "1.23456789e+20"}, + + // arrays + {"%v", array, "[1 2 3 4 5]"}, + {"%v", iarray, "[1 hello 2.5 ]"}, + {"%v", barray, "[1 2 3 4 5]"}, + {"%v", &array, "&[1 2 3 4 5]"}, + {"%v", &iarray, "&[1 hello 2.5 ]"}, + {"%v", &barray, "&[1 2 3 4 5]"}, + + // slices + {"%v", slice, "[1 2 3 4 5]"}, + {"%v", islice, "[1 hello 2.5 ]"}, + {"%v", bslice, "[1 2 3 4 5]"}, + {"%v", &slice, "&[1 2 3 4 5]"}, + {"%v", &islice, "&[1 hello 2.5 ]"}, + {"%v", &bslice, "&[1 2 3 4 5]"}, + + // byte arrays and slices with %b,%c,%d,%o,%U and %v + {"%b", [3]byte{65, 66, 67}, "[1000001 1000010 1000011]"}, + {"%c", [3]byte{65, 66, 67}, "[A B C]"}, + {"%d", [3]byte{65, 66, 67}, "[65 66 67]"}, + {"%o", [3]byte{65, 66, 67}, "[101 102 103]"}, + {"%U", [3]byte{65, 66, 67}, "[U+0041 U+0042 U+0043]"}, + {"%v", [3]byte{65, 66, 67}, "[65 66 67]"}, + {"%v", [1]byte{123}, "[123]"}, + {"%012v", []byte{}, "[]"}, + {"%#012v", []byte{}, "[]byte{}"}, + {"%6v", []byte{1, 11, 111}, "[ 1 11 111]"}, + {"%06v", []byte{1, 11, 111}, "[000001 000011 000111]"}, + {"%-6v", []byte{1, 11, 111}, "[1 11 111 ]"}, + {"%-06v", []byte{1, 11, 111}, "[1 11 111 ]"}, + {"%#v", []byte{1, 11, 111}, "[]byte{0x1, 0xb, 0x6f}"}, + {"%#6v", []byte{1, 11, 111}, "[]byte{ 0x1, 0xb, 0x6f}"}, + {"%#06v", []byte{1, 11, 111}, "[]byte{0x000001, 0x00000b, 0x00006f}"}, + {"%#-6v", []byte{1, 11, 111}, "[]byte{0x1 , 0xb , 0x6f }"}, + {"%#-06v", []byte{1, 11, 111}, "[]byte{0x1 , 0xb , 0x6f }"}, + // f.space should and f.plus should not have an effect with %v. + {"% v", []byte{1, 11, 111}, "[ 1 11 111]"}, + {"%+v", [3]byte{1, 11, 111}, "[1 11 111]"}, + {"%# -6v", []byte{1, 11, 111}, "[]byte{ 0x1 , 0xb , 0x6f }"}, + {"%#+-6v", [3]byte{1, 11, 111}, "[3]uint8{0x1 , 0xb , 0x6f }"}, + // f.space and f.plus should have an effect with %d. + {"% d", []byte{1, 11, 111}, "[ 1 11 111]"}, + {"%+d", [3]byte{1, 11, 111}, "[+1 +11 +111]"}, + {"%# -6d", []byte{1, 11, 111}, "[ 1 11 111 ]"}, + {"%#+-6d", [3]byte{1, 11, 111}, "[+1 +11 +111 ]"}, + + // floates with %v + {"%v", 1.2345678, "1.2345678"}, + {"%v", float32(1.2345678), "1.2345678"}, + + // complexes with %v + {"%v", 1 + 2i, "(1+2i)"}, + {"%v", complex64(1 + 2i), "(1+2i)"}, + + // structs + {"%v", A{1, 2, "a", []int{1, 2}}, `{1 2 a [1 2]}`}, + {"%+v", A{1, 2, "a", []int{1, 2}}, `{i:1 j:2 s:a x:[1 2]}`}, + + // +v on structs with Stringable items + {"%+v", B{1, 2}, `{I:<1> j:2}`}, + {"%+v", C{1, B{2, 3}}, `{i:1 B:{I:<2> j:3}}`}, + + // other formats on Stringable items + {"%s", I(23), `<23>`}, + {"%q", I(23), `"<23>"`}, + {"%x", I(23), `3c32333e`}, + {"%#x", I(23), `0x3c32333e`}, + {"%# x", I(23), `0x3c 0x32 0x33 0x3e`}, + // Stringer applies only to string formats. + {"%d", I(23), `23`}, + // Stringer applies to the extracted value. + {"%s", reflect.ValueOf(I(23)), `<23>`}, + + // go syntax + {"%#v", A{1, 2, "a", []int{1, 2}}, `message.A{i:1, j:0x2, s:"a", x:[]int{1, 2}}`}, + {"%#v", new(byte), "(*uint8)(0xPTR)"}, + {"%#v", TestFmtInterface, "(func(*testing.T))(0xPTR)"}, + {"%#v", make(chan int), "(chan int)(0xPTR)"}, + {"%#v", uint64(1<<64 - 1), "0xffffffffffffffff"}, + {"%#v", 1000000000, "1000000000"}, + {"%#v", map[string]int{"a": 1}, `map[string]int{"a":1}`}, + {"%#v", map[string]B{"a": {1, 2}}, `map[string]message.B{"a":message.B{I:1, j:2}}`}, + {"%#v", []string{"a", "b"}, `[]string{"a", "b"}`}, + {"%#v", SI{}, `message.SI{I:interface {}(nil)}`}, + {"%#v", []int(nil), `[]int(nil)`}, + {"%#v", []int{}, `[]int{}`}, + {"%#v", array, `[5]int{1, 2, 3, 4, 5}`}, + {"%#v", &array, `&[5]int{1, 2, 3, 4, 5}`}, + {"%#v", iarray, `[4]interface {}{1, "hello", 2.5, interface {}(nil)}`}, + {"%#v", &iarray, `&[4]interface {}{1, "hello", 2.5, interface {}(nil)}`}, + {"%#v", map[int]byte(nil), `map[int]uint8(nil)`}, + {"%#v", map[int]byte{}, `map[int]uint8{}`}, + {"%#v", "foo", `"foo"`}, + {"%#v", barray, `[5]message.renamedUint8{0x1, 0x2, 0x3, 0x4, 0x5}`}, + {"%#v", bslice, `[]message.renamedUint8{0x1, 0x2, 0x3, 0x4, 0x5}`}, + {"%#v", []int32(nil), "[]int32(nil)"}, + {"%#v", 1.2345678, "1.2345678"}, + {"%#v", float32(1.2345678), "1.2345678"}, + // Only print []byte and []uint8 as type []byte if they appear at the top level. + {"%#v", []byte(nil), "[]byte(nil)"}, + {"%#v", []uint8(nil), "[]byte(nil)"}, + {"%#v", []byte{}, "[]byte{}"}, + {"%#v", []uint8{}, "[]byte{}"}, + {"%#v", reflect.ValueOf([]byte{}), "[]uint8{}"}, + {"%#v", reflect.ValueOf([]uint8{}), "[]uint8{}"}, + {"%#v", &[]byte{}, "&[]uint8{}"}, + {"%#v", &[]byte{}, "&[]uint8{}"}, + {"%#v", [3]byte{}, "[3]uint8{0x0, 0x0, 0x0}"}, + {"%#v", [3]uint8{}, "[3]uint8{0x0, 0x0, 0x0}"}, + + // slices with other formats + {"%#x", []int{1, 2, 15}, `[0x1 0x2 0xf]`}, + {"%x", []int{1, 2, 15}, `[1 2 f]`}, + {"%d", []int{1, 2, 15}, `[1 2 15]`}, + {"%d", []byte{1, 2, 15}, `[1 2 15]`}, + {"%q", []string{"a", "b"}, `["a" "b"]`}, + {"% 02x", []byte{1}, "01"}, + {"% 02x", []byte{1, 2, 3}, "01 02 03"}, + + // Padding with byte slices. + {"%2x", []byte{}, " "}, + {"%#2x", []byte{}, " "}, + {"% 02x", []byte{}, "00"}, + {"%# 02x", []byte{}, "00"}, + {"%-2x", []byte{}, " "}, + {"%-02x", []byte{}, " "}, + {"%8x", []byte{0xab}, " ab"}, + {"% 8x", []byte{0xab}, " ab"}, + {"%#8x", []byte{0xab}, " 0xab"}, + {"%# 8x", []byte{0xab}, " 0xab"}, + {"%08x", []byte{0xab}, "000000ab"}, + {"% 08x", []byte{0xab}, "000000ab"}, + {"%#08x", []byte{0xab}, "00000xab"}, + {"%# 08x", []byte{0xab}, "00000xab"}, + {"%10x", []byte{0xab, 0xcd}, " abcd"}, + {"% 10x", []byte{0xab, 0xcd}, " ab cd"}, + {"%#10x", []byte{0xab, 0xcd}, " 0xabcd"}, + {"%# 10x", []byte{0xab, 0xcd}, " 0xab 0xcd"}, + {"%010x", []byte{0xab, 0xcd}, "000000abcd"}, + {"% 010x", []byte{0xab, 0xcd}, "00000ab cd"}, + {"%#010x", []byte{0xab, 0xcd}, "00000xabcd"}, + {"%# 010x", []byte{0xab, 0xcd}, "00xab 0xcd"}, + {"%-10X", []byte{0xab}, "AB "}, + {"% -010X", []byte{0xab}, "AB "}, + {"%#-10X", []byte{0xab, 0xcd}, "0XABCD "}, + {"%# -010X", []byte{0xab, 0xcd}, "0XAB 0XCD "}, + // Same for strings + {"%2x", "", " "}, + {"%#2x", "", " "}, + {"% 02x", "", "00"}, + {"%# 02x", "", "00"}, + {"%-2x", "", " "}, + {"%-02x", "", " "}, + {"%8x", "\xab", " ab"}, + {"% 8x", "\xab", " ab"}, + {"%#8x", "\xab", " 0xab"}, + {"%# 8x", "\xab", " 0xab"}, + {"%08x", "\xab", "000000ab"}, + {"% 08x", "\xab", "000000ab"}, + {"%#08x", "\xab", "00000xab"}, + {"%# 08x", "\xab", "00000xab"}, + {"%10x", "\xab\xcd", " abcd"}, + {"% 10x", "\xab\xcd", " ab cd"}, + {"%#10x", "\xab\xcd", " 0xabcd"}, + {"%# 10x", "\xab\xcd", " 0xab 0xcd"}, + {"%010x", "\xab\xcd", "000000abcd"}, + {"% 010x", "\xab\xcd", "00000ab cd"}, + {"%#010x", "\xab\xcd", "00000xabcd"}, + {"%# 010x", "\xab\xcd", "00xab 0xcd"}, + {"%-10X", "\xab", "AB "}, + {"% -010X", "\xab", "AB "}, + {"%#-10X", "\xab\xcd", "0XABCD "}, + {"%# -010X", "\xab\xcd", "0XAB 0XCD "}, + + // renamings + {"%v", renamedBool(true), "true"}, + {"%d", renamedBool(true), "%!d(message.renamedBool=true)"}, + {"%o", renamedInt(8), "10"}, + {"%d", renamedInt8(-9), "-9"}, + {"%v", renamedInt16(10), "10"}, + {"%v", renamedInt32(-11), "-11"}, + {"%X", renamedInt64(255), "FF"}, + {"%v", renamedUint(13), "13"}, + {"%o", renamedUint8(14), "16"}, + {"%X", renamedUint16(15), "F"}, + {"%d", renamedUint32(16), "16"}, + {"%X", renamedUint64(17), "11"}, + {"%o", renamedUintptr(18), "22"}, + {"%x", renamedString("thing"), "7468696e67"}, + {"%d", renamedBytes([]byte{1, 2, 15}), `[1 2 15]`}, + {"%q", renamedBytes([]byte("hello")), `"hello"`}, + {"%x", []renamedUint8{'h', 'e', 'l', 'l', 'o'}, "68656c6c6f"}, + {"%X", []renamedUint8{'h', 'e', 'l', 'l', 'o'}, "68656C6C6F"}, + {"%s", []renamedUint8{'h', 'e', 'l', 'l', 'o'}, "hello"}, + {"%q", []renamedUint8{'h', 'e', 'l', 'l', 'o'}, `"hello"`}, + {"%v", renamedFloat32(22), "22"}, + {"%v", renamedFloat64(33), "33"}, + {"%v", renamedComplex64(3 + 4i), "(3+4i)"}, + {"%v", renamedComplex128(4 - 3i), "(4-3i)"}, + + // Formatter + {"%x", F(1), ""}, + {"%x", G(2), "2"}, + {"%+v", S{F(4), G(5)}, "{F: G:5}"}, + + // GoStringer + {"%#v", G(6), "GoString(6)"}, + {"%#v", S{F(7), G(8)}, "message.S{F:, G:GoString(8)}"}, + + // %T + {"%T", byte(0), "uint8"}, + {"%T", reflect.ValueOf(nil), "reflect.Value"}, + {"%T", (4 - 3i), "complex128"}, + {"%T", renamedComplex128(4 - 3i), "message.renamedComplex128"}, + {"%T", intVar, "int"}, + {"%6T", &intVar, " *int"}, + {"%10T", nil, " "}, + {"%-10T", nil, " "}, + + // %p with pointers + {"%p", (*int)(nil), "0x0"}, + {"%#p", (*int)(nil), "0"}, + {"%p", &intVar, "0xPTR"}, + {"%#p", &intVar, "PTR"}, + {"%p", &array, "0xPTR"}, + {"%p", &slice, "0xPTR"}, + {"%8.2p", (*int)(nil), " 0x00"}, + {"%-20.16p", &intVar, "0xPTR "}, + // %p on non-pointers + {"%p", make(chan int), "0xPTR"}, + {"%p", make(map[int]int), "0xPTR"}, + {"%p", func() {}, "0xPTR"}, + {"%p", 27, "%!p(int=27)"}, // not a pointer at all + {"%p", nil, "%!p()"}, // nil on its own has no type ... + {"%#p", nil, "%!p()"}, // ... and hence is not a pointer type. + // pointers with specified base + {"%b", &intVar, "PTR_b"}, + {"%d", &intVar, "PTR_d"}, + {"%o", &intVar, "PTR_o"}, + {"%x", &intVar, "PTR_x"}, + {"%X", &intVar, "PTR_X"}, + // %v on pointers + {"%v", nil, ""}, + {"%#v", nil, ""}, + {"%v", (*int)(nil), ""}, + {"%#v", (*int)(nil), "(*int)(nil)"}, + {"%v", &intVar, "0xPTR"}, + {"%#v", &intVar, "(*int)(0xPTR)"}, + {"%8.2v", (*int)(nil), " "}, + {"%-20.16v", &intVar, "0xPTR "}, + // string method on pointer + {"%s", &pValue, "String(p)"}, // String method... + {"%p", &pValue, "0xPTR"}, // ... is not called with %p. + + // %d on Stringer should give integer if possible + {"%s", time.Time{}.Month(), "January"}, + {"%d", time.Time{}.Month(), "1"}, + + // erroneous things + {"%s %", "hello", "hello %!(NOVERB)"}, + {"%s %.2", "hello", "hello %!(NOVERB)"}, + + // The "" show up because maps are printed by + // first obtaining a list of keys and then looking up + // each key. Since NaNs can be map keys but cannot + // be fetched directly, the lookup fails and returns a + // zero reflect.Value, which formats as . + // This test is just to check that it shows the two NaNs at all. + {"%v", map[float64]int{NaN: 1, NaN: 2}, "map[NaN: NaN:]"}, + + // Comparison of padding rules with C printf. + /* + C program: + #include + + char *format[] = { + "[%.2f]", + "[% .2f]", + "[%+.2f]", + "[%7.2f]", + "[% 7.2f]", + "[%+7.2f]", + "[% +7.2f]", + "[%07.2f]", + "[% 07.2f]", + "[%+07.2f]", + "[% +07.2f]" + }; + + int main(void) { + int i; + for(i = 0; i < 11; i++) { + printf("%s: ", format[i]); + printf(format[i], 1.0); + printf(" "); + printf(format[i], -1.0); + printf("\n"); + } + } + + Output: + [%.2f]: [1.00] [-1.00] + [% .2f]: [ 1.00] [-1.00] + [%+.2f]: [+1.00] [-1.00] + [%7.2f]: [ 1.00] [ -1.00] + [% 7.2f]: [ 1.00] [ -1.00] + [%+7.2f]: [ +1.00] [ -1.00] + [% +7.2f]: [ +1.00] [ -1.00] + [%07.2f]: [0001.00] [-001.00] + [% 07.2f]: [ 001.00] [-001.00] + [%+07.2f]: [+001.00] [-001.00] + [% +07.2f]: [+001.00] [-001.00] + + */ + {"%.2f", 1.0, "1.00"}, + {"%.2f", -1.0, "-1.00"}, + {"% .2f", 1.0, " 1.00"}, + {"% .2f", -1.0, "-1.00"}, + {"%+.2f", 1.0, "+1.00"}, + {"%+.2f", -1.0, "-1.00"}, + {"%7.2f", 1.0, " 1.00"}, + {"%7.2f", -1.0, " -1.00"}, + {"% 7.2f", 1.0, " 1.00"}, + {"% 7.2f", -1.0, " -1.00"}, + {"%+7.2f", 1.0, " +1.00"}, + {"%+7.2f", -1.0, " -1.00"}, + {"% +7.2f", 1.0, " +1.00"}, + {"% +7.2f", -1.0, " -1.00"}, + {"%07.2f", 1.0, "0001.00"}, + {"%07.2f", -1.0, "-001.00"}, + {"% 07.2f", 1.0, " 001.00"}, + {"% 07.2f", -1.0, "-001.00"}, + {"%+07.2f", 1.0, "+001.00"}, + {"%+07.2f", -1.0, "-001.00"}, + {"% +07.2f", 1.0, "+001.00"}, + {"% +07.2f", -1.0, "-001.00"}, + + // Complex numbers: exhaustively tested in TestComplexFormatting. + {"%7.2f", 1 + 2i, "( 1.00 +2.00i)"}, + {"%+07.2f", -1 - 2i, "(-001.00-002.00i)"}, + + // Use spaces instead of zero if padding to the right. + {"%0-5s", "abc", "abc "}, + {"%-05.1f", 1.0, "1.0 "}, + + // float and complex formatting should not change the padding width + // for other elements. See issue 14642. + {"%06v", []interface{}{+10.0, 10}, "[000010 000010]"}, + {"%06v", []interface{}{-10.0, 10}, "[-00010 000010]"}, + {"%06v", []interface{}{+10.0 + 10i, 10}, "[(000010+00010i) 000010]"}, + {"%06v", []interface{}{-10.0 + 10i, 10}, "[(-00010+00010i) 000010]"}, + + // integer formatting should not alter padding for other elements. + {"%03.6v", []interface{}{1, 2.0, "x"}, "[000001 002 00x]"}, + {"%03.0v", []interface{}{0, 2.0, "x"}, "[ 002 000]"}, + + // Complex fmt used to leave the plus flag set for future entries in the array + // causing +2+0i and +3+0i instead of 2+0i and 3+0i. + {"%v", []complex64{1, 2, 3}, "[(1+0i) (2+0i) (3+0i)]"}, + {"%v", []complex128{1, 2, 3}, "[(1+0i) (2+0i) (3+0i)]"}, + + // Incomplete format specification caused crash. + {"%.", 3, "%!.(int=3)"}, + + // Padding for complex numbers. Has been bad, then fixed, then bad again. + {"%+10.2f", +104.66 + 440.51i, "( +104.66 +440.51i)"}, + {"%+10.2f", -104.66 + 440.51i, "( -104.66 +440.51i)"}, + {"%+10.2f", +104.66 - 440.51i, "( +104.66 -440.51i)"}, + {"%+10.2f", -104.66 - 440.51i, "( -104.66 -440.51i)"}, + {"%+010.2f", +104.66 + 440.51i, "(+000104.66+000440.51i)"}, + {"%+010.2f", -104.66 + 440.51i, "(-000104.66+000440.51i)"}, + {"%+010.2f", +104.66 - 440.51i, "(+000104.66-000440.51i)"}, + {"%+010.2f", -104.66 - 440.51i, "(-000104.66-000440.51i)"}, + + // []T where type T is a byte with a Stringer method. + {"%v", byteStringerSlice, "[X X X X X]"}, + {"%s", byteStringerSlice, "hello"}, + {"%q", byteStringerSlice, "\"hello\""}, + {"%x", byteStringerSlice, "68656c6c6f"}, + {"%X", byteStringerSlice, "68656C6C6F"}, + {"%#v", byteStringerSlice, "[]message.byteStringer{0x68, 0x65, 0x6c, 0x6c, 0x6f}"}, + + // And the same for Formatter. + {"%v", byteFormatterSlice, "[X X X X X]"}, + {"%s", byteFormatterSlice, "hello"}, + {"%q", byteFormatterSlice, "\"hello\""}, + {"%x", byteFormatterSlice, "68656c6c6f"}, + {"%X", byteFormatterSlice, "68656C6C6F"}, + // This next case seems wrong, but the docs say the Formatter wins here. + {"%#v", byteFormatterSlice, "[]message.byteFormatter{X, X, X, X, X}"}, + + // reflect.Value handled specially in Go 1.5, making it possible to + // see inside non-exported fields (which cannot be accessed with Interface()). + // Issue 8965. + {"%v", reflect.ValueOf(A{}).Field(0).String(), ""}, // Equivalent to the old way. + {"%v", reflect.ValueOf(A{}).Field(0), "0"}, // Sees inside the field. + + // verbs apply to the extracted value too. + {"%s", reflect.ValueOf("hello"), "hello"}, + {"%q", reflect.ValueOf("hello"), `"hello"`}, + {"%#04x", reflect.ValueOf(256), "0x0100"}, + + // invalid reflect.Value doesn't crash. + {"%v", reflect.Value{}, ""}, + {"%v", &reflect.Value{}, ""}, + {"%v", SI{reflect.Value{}}, "{}"}, + + // Tests to check that not supported verbs generate an error string. + {"%☠", nil, "%!☠()"}, + {"%☠", interface{}(nil), "%!☠()"}, + {"%☠", int(0), "%!☠(int=0)"}, + {"%☠", uint(0), "%!☠(uint=0)"}, + {"%☠", []byte{0, 1}, "[%!☠(uint8=0) %!☠(uint8=1)]"}, + {"%☠", []uint8{0, 1}, "[%!☠(uint8=0) %!☠(uint8=1)]"}, + {"%☠", [1]byte{0}, "[%!☠(uint8=0)]"}, + {"%☠", [1]uint8{0}, "[%!☠(uint8=0)]"}, + {"%☠", "hello", "%!☠(string=hello)"}, + {"%☠", 1.2345678, "%!☠(float64=1.2345678)"}, + {"%☠", float32(1.2345678), "%!☠(float32=1.2345678)"}, + {"%☠", 1.2345678 + 1.2345678i, "%!☠(complex128=(1.2345678+1.2345678i))"}, + {"%☠", complex64(1.2345678 + 1.2345678i), "%!☠(complex64=(1.2345678+1.2345678i))"}, + {"%☠", &intVar, "%!☠(*int=0xPTR)"}, + {"%☠", make(chan int), "%!☠(chan int=0xPTR)"}, + {"%☠", func() {}, "%!☠(func()=0xPTR)"}, + {"%☠", reflect.ValueOf(renamedInt(0)), "%!☠(message.renamedInt=0)"}, + {"%☠", SI{renamedInt(0)}, "{%!☠(message.renamedInt=0)}"}, + {"%☠", &[]interface{}{I(1), G(2)}, "&[%!☠(message.I=1) %!☠(message.G=2)]"}, + {"%☠", SI{&[]interface{}{I(1), G(2)}}, "{%!☠(*[]interface {}=&[1 2])}"}, + {"%☠", reflect.Value{}, ""}, + {"%☠", map[float64]int{NaN: 1}, "map[%!☠(float64=NaN):%!☠()]"}, +} + +// zeroFill generates zero-filled strings of the specified width. The length +// of the suffix (but not the prefix) is compensated for in the width calculation. +func zeroFill(prefix string, width int, suffix string) string { + return prefix + strings.Repeat("0", width-len(suffix)) + suffix +} + +func TestSprintf(t *testing.T) { + p := NewPrinter(language.Und) + for _, tt := range fmtTests { + t.Run(fmt.Sprint(tt.fmt, tt.val), func(t *testing.T) { + s := p.Sprintf(tt.fmt, tt.val) + i := strings.Index(tt.out, "PTR") + if i >= 0 && i < len(s) { + var pattern, chars string + switch { + case strings.HasPrefix(tt.out[i:], "PTR_b"): + pattern = "PTR_b" + chars = "01" + case strings.HasPrefix(tt.out[i:], "PTR_o"): + pattern = "PTR_o" + chars = "01234567" + case strings.HasPrefix(tt.out[i:], "PTR_d"): + pattern = "PTR_d" + chars = "0123456789" + case strings.HasPrefix(tt.out[i:], "PTR_x"): + pattern = "PTR_x" + chars = "0123456789abcdef" + case strings.HasPrefix(tt.out[i:], "PTR_X"): + pattern = "PTR_X" + chars = "0123456789ABCDEF" + default: + pattern = "PTR" + chars = "0123456789abcdefABCDEF" + } + p := s[:i] + pattern + for j := i; j < len(s); j++ { + if !strings.ContainsRune(chars, rune(s[j])) { + p += s[j:] + break + } + } + s = p + } + if s != tt.out { + if _, ok := tt.val.(string); ok { + // Don't requote the already-quoted strings. + // It's too confusing to read the errors. + t.Errorf("Sprintf(%q, %q) = <%s> want <%s>", tt.fmt, tt.val, s, tt.out) + } else { + t.Errorf("Sprintf(%q, %v) = %q want %q", tt.fmt, tt.val, s, tt.out) + } + } + }) + } +} + +var f float64 + +// TestComplexFormatting checks that a complex always formats to the same +// thing as if done by hand with two singleton prints. +func TestComplexFormatting(t *testing.T) { + var yesNo = []bool{true, false} + var values = []float64{1, 0, -1, posInf, negInf, NaN} + p := NewPrinter(language.Und) + for _, plus := range yesNo { + for _, zero := range yesNo { + for _, space := range yesNo { + for _, char := range "fFeEgG" { + realFmt := "%" + if zero { + realFmt += "0" + } + if space { + realFmt += " " + } + if plus { + realFmt += "+" + } + realFmt += "10.2" + realFmt += string(char) + // Imaginary part always has a sign, so force + and ignore space. + imagFmt := "%" + if zero { + imagFmt += "0" + } + imagFmt += "+" + imagFmt += "10.2" + imagFmt += string(char) + for _, realValue := range values { + for _, imagValue := range values { + one := p.Sprintf(realFmt, complex(realValue, imagValue)) + two := p.Sprintf("("+realFmt+imagFmt+"i)", realValue, imagValue) + if one != two { + t.Error(f, one, two) + } + } + } + } + } + } + } +} + +type SE []interface{} // slice of empty; notational compactness. + +var reorderTests = []struct { + format string + args SE + out string +}{ + {"%[1]d", SE{1}, "1"}, + {"%[2]d", SE{2, 1}, "1"}, + {"%[2]d %[1]d", SE{1, 2}, "2 1"}, + {"%[2]*[1]d", SE{2, 5}, " 2"}, + {"%6.2f", SE{12.0}, " 12.00"}, // Explicit version of next line. + {"%[3]*.[2]*[1]f", SE{12.0, 2, 6}, " 12.00"}, + {"%[1]*.[2]*[3]f", SE{6, 2, 12.0}, " 12.00"}, + {"%10f", SE{12.0}, " 12.000000"}, + {"%[1]*[3]f", SE{10, 99, 12.0}, " 12.000000"}, + {"%.6f", SE{12.0}, "12.000000"}, // Explicit version of next line. + {"%.[1]*[3]f", SE{6, 99, 12.0}, "12.000000"}, + {"%6.f", SE{12.0}, " 12"}, // // Explicit version of next line; empty precision means zero. + {"%[1]*.[3]f", SE{6, 3, 12.0}, " 12"}, + // An actual use! Print the same arguments twice. + {"%d %d %d %#[1]o %#o %#o", SE{11, 12, 13}, "11 12 13 013 014 015"}, + + // Erroneous cases. + {"%[d", SE{2, 1}, "%!d(BADINDEX)"}, + {"%]d", SE{2, 1}, "%!](int=2)d%!(EXTRA int=1)"}, + {"%[]d", SE{2, 1}, "%!d(BADINDEX)"}, + {"%[-3]d", SE{2, 1}, "%!d(BADINDEX)"}, + {"%[99]d", SE{2, 1}, "%!d(BADINDEX)"}, + {"%[3]", SE{2, 1}, "%!(NOVERB)"}, + {"%[1].2d", SE{5, 6}, "%!d(BADINDEX)"}, + {"%[1]2d", SE{2, 1}, "%!d(BADINDEX)"}, + {"%3.[2]d", SE{7}, "%!d(BADINDEX)"}, + {"%.[2]d", SE{7}, "%!d(BADINDEX)"}, + {"%d %d %d %#[1]o %#o %#o %#o", SE{11, 12, 13}, "11 12 13 013 014 015 %!o(MISSING)"}, + {"%[5]d %[2]d %d", SE{1, 2, 3}, "%!d(BADINDEX) 2 3"}, + {"%d %[3]d %d", SE{1, 2}, "1 %!d(BADINDEX) 2"}, // Erroneous index does not affect sequence. + {"%.[]", SE{}, "%!](BADINDEX)"}, // Issue 10675 + {"%.-3d", SE{42}, "%!-(int=42)3d"}, // TODO: Should this set return better error messages? + // The following messages are interpreted as if there is no substitution, + // in which case it is okay to have extra arguments. This is different + // semantics from the fmt package. + {"%2147483648d", SE{42}, "%!(NOVERB)"}, + {"%-2147483648d", SE{42}, "%!(NOVERB)"}, + {"%.2147483648d", SE{42}, "%!(NOVERB)"}, +} + +func TestReorder(t *testing.T) { + p := NewPrinter(language.Und) + for _, tc := range reorderTests { + t.Run(fmt.Sprint(tc.format, "/", tc.args), func(t *testing.T) { + s := p.Sprintf(tc.format, tc.args...) + if s != tc.out { + t.Errorf("Sprintf(%q, %v) = %q want %q", tc.format, tc.args, s, tc.out) + } + }) + } +} + +func BenchmarkSprintfPadding(b *testing.B) { + b.RunParallel(func(pb *testing.PB) { + p := NewPrinter(language.English) + for pb.Next() { + p.Sprintf("%16f", 1.0) + } + }) +} + +func BenchmarkSprintfEmpty(b *testing.B) { + b.RunParallel(func(pb *testing.PB) { + p := NewPrinter(language.English) + for pb.Next() { + p.Sprintf("") + } + }) +} + +func BenchmarkSprintfString(b *testing.B) { + b.RunParallel(func(pb *testing.PB) { + p := NewPrinter(language.English) + for pb.Next() { + p.Sprintf("%s", "hello") + } + }) +} + +func BenchmarkSprintfTruncateString(b *testing.B) { + b.RunParallel(func(pb *testing.PB) { + p := NewPrinter(language.English) + for pb.Next() { + p.Sprintf("%.3s", "日本語日本語日本語") + } + }) +} + +func BenchmarkSprintfQuoteString(b *testing.B) { + b.RunParallel(func(pb *testing.PB) { + p := NewPrinter(language.English) + for pb.Next() { + p.Sprintf("%q", "日本語日本語日本語") + } + }) +} + +func BenchmarkSprintfInt(b *testing.B) { + b.RunParallel(func(pb *testing.PB) { + p := NewPrinter(language.English) + for pb.Next() { + p.Sprintf("%d", 5) + } + }) +} + +func BenchmarkSprintfIntInt(b *testing.B) { + b.RunParallel(func(pb *testing.PB) { + p := NewPrinter(language.English) + for pb.Next() { + p.Sprintf("%d %d", 5, 6) + } + }) +} + +func BenchmarkSprintfPrefixedInt(b *testing.B) { + b.RunParallel(func(pb *testing.PB) { + p := NewPrinter(language.English) + for pb.Next() { + p.Sprintf("This is some meaningless prefix text that needs to be scanned %d", 6) + } + }) +} + +func BenchmarkSprintfFloat(b *testing.B) { + b.RunParallel(func(pb *testing.PB) { + p := NewPrinter(language.English) + for pb.Next() { + p.Sprintf("%g", 5.23184) + } + }) +} + +func BenchmarkSprintfComplex(b *testing.B) { + b.RunParallel(func(pb *testing.PB) { + p := NewPrinter(language.English) + for pb.Next() { + p.Sprintf("%f", 5.23184+5.23184i) + } + }) +} + +func BenchmarkSprintfBoolean(b *testing.B) { + b.RunParallel(func(pb *testing.PB) { + p := NewPrinter(language.English) + for pb.Next() { + p.Sprintf("%t", true) + } + }) +} + +func BenchmarkSprintfHexString(b *testing.B) { + b.RunParallel(func(pb *testing.PB) { + p := NewPrinter(language.English) + for pb.Next() { + p.Sprintf("% #x", "0123456789abcdef") + } + }) +} + +func BenchmarkSprintfHexBytes(b *testing.B) { + data := []byte("0123456789abcdef") + b.RunParallel(func(pb *testing.PB) { + p := NewPrinter(language.English) + for pb.Next() { + p.Sprintf("% #x", data) + } + }) +} + +func BenchmarkSprintfBytes(b *testing.B) { + data := []byte("0123456789abcdef") + b.RunParallel(func(pb *testing.PB) { + p := NewPrinter(language.English) + for pb.Next() { + p.Sprintf("%v", data) + } + }) +} + +func BenchmarkSprintfStringer(b *testing.B) { + stringer := I(12345) + b.RunParallel(func(pb *testing.PB) { + p := NewPrinter(language.English) + for pb.Next() { + p.Sprintf("%v", stringer) + } + }) +} + +func BenchmarkSprintfStructure(b *testing.B) { + s := &[]interface{}{SI{12345}, map[int]string{0: "hello"}} + b.RunParallel(func(pb *testing.PB) { + p := NewPrinter(language.English) + for pb.Next() { + p.Sprintf("%#v", s) + } + }) +} + +func BenchmarkManyArgs(b *testing.B) { + b.RunParallel(func(pb *testing.PB) { + var buf bytes.Buffer + p := NewPrinter(language.English) + for pb.Next() { + buf.Reset() + p.Fprintf(&buf, "%2d/%2d/%2d %d:%d:%d %s %s\n", 3, 4, 5, 11, 12, 13, "hello", "world") + } + }) +} + +func BenchmarkFprintInt(b *testing.B) { + var buf bytes.Buffer + p := NewPrinter(language.English) + for i := 0; i < b.N; i++ { + buf.Reset() + p.Fprint(&buf, 123456) + } +} + +func BenchmarkFprintfBytes(b *testing.B) { + data := []byte(string("0123456789")) + var buf bytes.Buffer + p := NewPrinter(language.English) + for i := 0; i < b.N; i++ { + buf.Reset() + p.Fprintf(&buf, "%s", data) + } +} + +func BenchmarkFprintIntNoAlloc(b *testing.B) { + var x interface{} = 123456 + var buf bytes.Buffer + p := NewPrinter(language.English) + for i := 0; i < b.N; i++ { + buf.Reset() + p.Fprint(&buf, x) + } +} + +var mallocBuf bytes.Buffer +var mallocPointer *int // A pointer so we know the interface value won't allocate. + +var mallocTest = []struct { + count int + desc string + fn func(p *Printer) +}{ + {0, `Sprintf("")`, func(p *Printer) { p.Sprintf("") }}, + {1, `Sprintf("xxx")`, func(p *Printer) { p.Sprintf("xxx") }}, + {2, `Sprintf("%x")`, func(p *Printer) { p.Sprintf("%x", 7) }}, + {2, `Sprintf("%s")`, func(p *Printer) { p.Sprintf("%s", "hello") }}, + {3, `Sprintf("%x %x")`, func(p *Printer) { p.Sprintf("%x %x", 7, 112) }}, + {2, `Sprintf("%g")`, func(p *Printer) { p.Sprintf("%g", float32(3.14159)) }}, // TODO: Can this be 1? + {1, `Fprintf(buf, "%s")`, func(p *Printer) { mallocBuf.Reset(); p.Fprintf(&mallocBuf, "%s", "hello") }}, + // If the interface value doesn't need to allocate, amortized allocation overhead should be zero. + {0, `Fprintf(buf, "%x %x %x")`, func(p *Printer) { + mallocBuf.Reset() + p.Fprintf(&mallocBuf, "%x %x %x", mallocPointer, mallocPointer, mallocPointer) + }}, +} + +var _ bytes.Buffer + +func TestCountMallocs(t *testing.T) { + switch { + case testing.Short(): + t.Skip("skipping malloc count in short mode") + case runtime.GOMAXPROCS(0) > 1: + t.Skip("skipping; GOMAXPROCS>1") + // TODO: detect race detecter enabled. + // case race.Enabled: + // t.Skip("skipping malloc count under race detector") + } + p := NewPrinter(language.English) + for _, mt := range mallocTest { + mallocs := testing.AllocsPerRun(100, func() { mt.fn(p) }) + if got, max := mallocs, float64(mt.count); got > max { + t.Errorf("%s: got %v allocs, want <=%v", mt.desc, got, max) + } + } +} + +type flagPrinter struct{} + +func (flagPrinter) Format(f fmt.State, c rune) { + s := "%" + for i := 0; i < 128; i++ { + if f.Flag(i) { + s += string(i) + } + } + if w, ok := f.Width(); ok { + s += fmt.Sprintf("%d", w) + } + if p, ok := f.Precision(); ok { + s += fmt.Sprintf(".%d", p) + } + s += string(c) + io.WriteString(f, "["+s+"]") +} + +var flagtests = []struct { + in string + out string +}{ + {"%a", "[%a]"}, + {"%-a", "[%-a]"}, + {"%+a", "[%+a]"}, + {"%#a", "[%#a]"}, + {"% a", "[% a]"}, + {"%0a", "[%0a]"}, + {"%1.2a", "[%1.2a]"}, + {"%-1.2a", "[%-1.2a]"}, + {"%+1.2a", "[%+1.2a]"}, + {"%-+1.2a", "[%+-1.2a]"}, + {"%-+1.2abc", "[%+-1.2a]bc"}, + {"%-1.2abc", "[%-1.2a]bc"}, +} + +func TestFlagParser(t *testing.T) { + var flagprinter flagPrinter + for _, tt := range flagtests { + s := NewPrinter(language.Und).Sprintf(tt.in, &flagprinter) + if s != tt.out { + t.Errorf("Sprintf(%q, &flagprinter) => %q, want %q", tt.in, s, tt.out) + } + } +} + +func TestStructPrinter(t *testing.T) { + type T struct { + a string + b string + c int + } + var s T + s.a = "abc" + s.b = "def" + s.c = 123 + var tests = []struct { + fmt string + out string + }{ + {"%v", "{abc def 123}"}, + {"%+v", "{a:abc b:def c:123}"}, + {"%#v", `message.T{a:"abc", b:"def", c:123}`}, + } + p := NewPrinter(language.Und) + for _, tt := range tests { + out := p.Sprintf(tt.fmt, s) + if out != tt.out { + t.Errorf("Sprintf(%q, s) = %#q, want %#q", tt.fmt, out, tt.out) + } + // The same but with a pointer. + out = p.Sprintf(tt.fmt, &s) + if out != "&"+tt.out { + t.Errorf("Sprintf(%q, &s) = %#q, want %#q", tt.fmt, out, "&"+tt.out) + } + } +} + +func TestSlicePrinter(t *testing.T) { + p := NewPrinter(language.Und) + slice := []int{} + s := p.Sprint(slice) + if s != "[]" { + t.Errorf("empty slice printed as %q not %q", s, "[]") + } + slice = []int{1, 2, 3} + s = p.Sprint(slice) + if s != "[1 2 3]" { + t.Errorf("slice: got %q expected %q", s, "[1 2 3]") + } + s = p.Sprint(&slice) + if s != "&[1 2 3]" { + t.Errorf("&slice: got %q expected %q", s, "&[1 2 3]") + } +} + +// presentInMap checks map printing using substrings so we don't depend on the +// print order. +func presentInMap(s string, a []string, t *testing.T) { + for i := 0; i < len(a); i++ { + loc := strings.Index(s, a[i]) + if loc < 0 { + t.Errorf("map print: expected to find %q in %q", a[i], s) + } + // make sure the match ends here + loc += len(a[i]) + if loc >= len(s) || (s[loc] != ' ' && s[loc] != ']') { + t.Errorf("map print: %q not properly terminated in %q", a[i], s) + } + } +} + +func TestMapPrinter(t *testing.T) { + p := NewPrinter(language.Und) + m0 := make(map[int]string) + s := p.Sprint(m0) + if s != "map[]" { + t.Errorf("empty map printed as %q not %q", s, "map[]") + } + m1 := map[int]string{1: "one", 2: "two", 3: "three"} + a := []string{"1:one", "2:two", "3:three"} + presentInMap(p.Sprintf("%v", m1), a, t) + presentInMap(p.Sprint(m1), a, t) + // Pointer to map prints the same but with initial &. + if !strings.HasPrefix(p.Sprint(&m1), "&") { + t.Errorf("no initial & for address of map") + } + presentInMap(p.Sprintf("%v", &m1), a, t) + presentInMap(p.Sprint(&m1), a, t) +} + +func TestEmptyMap(t *testing.T) { + const emptyMapStr = "map[]" + var m map[string]int + p := NewPrinter(language.Und) + s := p.Sprint(m) + if s != emptyMapStr { + t.Errorf("nil map printed as %q not %q", s, emptyMapStr) + } + m = make(map[string]int) + s = p.Sprint(m) + if s != emptyMapStr { + t.Errorf("empty map printed as %q not %q", s, emptyMapStr) + } +} + +// TestBlank checks that Sprint (and hence Print, Fprint) puts spaces in the +// right places, that is, between arg pairs in which neither is a string. +func TestBlank(t *testing.T) { + p := NewPrinter(language.Und) + got := p.Sprint("<", 1, ">:", 1, 2, 3, "!") + expect := "<1>:1 2 3!" + if got != expect { + t.Errorf("got %q expected %q", got, expect) + } +} + +// TestBlankln checks that Sprintln (and hence Println, Fprintln) puts spaces in +// the right places, that is, between all arg pairs. +func TestBlankln(t *testing.T) { + p := NewPrinter(language.Und) + got := p.Sprintln("<", 1, ">:", 1, 2, 3, "!") + expect := "< 1 >: 1 2 3 !\n" + if got != expect { + t.Errorf("got %q expected %q", got, expect) + } +} + +// TestFormatterPrintln checks Formatter with Sprint, Sprintln, Sprintf. +func TestFormatterPrintln(t *testing.T) { + p := NewPrinter(language.Und) + f := F(1) + expect := "\n" + s := p.Sprint(f, "\n") + if s != expect { + t.Errorf("Sprint wrong with Formatter: expected %q got %q", expect, s) + } + s = p.Sprintln(f) + if s != expect { + t.Errorf("Sprintln wrong with Formatter: expected %q got %q", expect, s) + } + s = p.Sprintf("%v\n", f) + if s != expect { + t.Errorf("Sprintf wrong with Formatter: expected %q got %q", expect, s) + } +} + +func args(a ...interface{}) []interface{} { return a } + +var startests = []struct { + fmt string + in []interface{} + out string +}{ + {"%*d", args(4, 42), " 42"}, + {"%-*d", args(4, 42), "42 "}, + {"%*d", args(-4, 42), "42 "}, + {"%-*d", args(-4, 42), "42 "}, + {"%.*d", args(4, 42), "0042"}, + {"%*.*d", args(8, 4, 42), " 0042"}, + {"%0*d", args(4, 42), "0042"}, + // Some non-int types for width. (Issue 10732). + {"%0*d", args(uint(4), 42), "0042"}, + {"%0*d", args(uint64(4), 42), "0042"}, + {"%0*d", args('\x04', 42), "0042"}, + {"%0*d", args(uintptr(4), 42), "0042"}, + + // erroneous + {"%*d", args(nil, 42), "%!(BADWIDTH)42"}, + {"%*d", args(int(1e7), 42), "%!(BADWIDTH)42"}, + {"%*d", args(int(-1e7), 42), "%!(BADWIDTH)42"}, + {"%.*d", args(nil, 42), "%!(BADPREC)42"}, + {"%.*d", args(-1, 42), "%!(BADPREC)42"}, + {"%.*d", args(int(1e7), 42), "%!(BADPREC)42"}, + {"%.*d", args(uint(1e7), 42), "%!(BADPREC)42"}, + {"%.*d", args(uint64(1<<63), 42), "%!(BADPREC)42"}, // Huge negative (-inf). + {"%.*d", args(uint64(1<<64-1), 42), "%!(BADPREC)42"}, // Small negative (-1). + {"%*d", args(5, "foo"), "%!d(string= foo)"}, + {"%*% %d", args(20, 5), "% 5"}, + {"%*", args(4), "%!(NOVERB)"}, +} + +func TestWidthAndPrecision(t *testing.T) { + p := NewPrinter(language.Und) + for i, tt := range startests { + t.Run(fmt.Sprint(tt.fmt, tt.in), func(t *testing.T) { + s := p.Sprintf(tt.fmt, tt.in...) + if s != tt.out { + t.Errorf("#%d: %q: got %q expected %q", i, tt.fmt, s, tt.out) + } + }) + } +} + +// PanicS is a type that panics in String. +type PanicS struct { + message interface{} +} + +// Value receiver. +func (p PanicS) String() string { + panic(p.message) +} + +// PanicGo is a type that panics in GoString. +type PanicGo struct { + message interface{} +} + +// Value receiver. +func (p PanicGo) GoString() string { + panic(p.message) +} + +// PanicF is a type that panics in Format. +type PanicF struct { + message interface{} +} + +// Value receiver. +func (p PanicF) Format(f fmt.State, c rune) { + panic(p.message) +} + +var panictests = []struct { + desc string + fmt string + in interface{} + out string +}{ + // String + {"String", "%s", (*PanicS)(nil), ""}, // nil pointer special case + {"String", "%s", PanicS{io.ErrUnexpectedEOF}, "%!s(PANIC=unexpected EOF)"}, + {"String", "%s", PanicS{3}, "%!s(PANIC=3)"}, + // GoString + {"GoString", "%#v", (*PanicGo)(nil), ""}, // nil pointer special case + {"GoString", "%#v", PanicGo{io.ErrUnexpectedEOF}, "%!v(PANIC=unexpected EOF)"}, + {"GoString", "%#v", PanicGo{3}, "%!v(PANIC=3)"}, + // Issue 18282. catchPanic should not clear fmtFlags permanently. + {"Issue 18282", "%#v", []interface{}{PanicGo{3}, PanicGo{3}}, "[]interface {}{%!v(PANIC=3), %!v(PANIC=3)}"}, + // Format + {"Format", "%s", (*PanicF)(nil), ""}, // nil pointer special case + {"Format", "%s", PanicF{io.ErrUnexpectedEOF}, "%!s(PANIC=unexpected EOF)"}, + {"Format", "%s", PanicF{3}, "%!s(PANIC=3)"}, +} + +func TestPanics(t *testing.T) { + p := NewPrinter(language.Und) + for i, tt := range panictests { + t.Run(fmt.Sprint(tt.desc, "/", tt.fmt, "/", tt.in), func(t *testing.T) { + s := p.Sprintf(tt.fmt, tt.in) + if s != tt.out { + t.Errorf("%d: %q: got %q expected %q", i, tt.fmt, s, tt.out) + } + }) + } +} + +// recurCount tests that erroneous String routine doesn't cause fatal recursion. +var recurCount = 0 + +type Recur struct { + i int + failed *bool +} + +func (r *Recur) String() string { + p := NewPrinter(language.Und) + if recurCount++; recurCount > 10 { + *r.failed = true + return "FAIL" + } + // This will call badVerb. Before the fix, that would cause us to recur into + // this routine to print %!p(value). Now we don't call the user's method + // during an error. + return p.Sprintf("recur@%p value: %d", r, r.i) +} + +func TestBadVerbRecursion(t *testing.T) { + p := NewPrinter(language.Und) + failed := false + r := &Recur{3, &failed} + p.Sprintf("recur@%p value: %d\n", &r, r.i) + if failed { + t.Error("fail with pointer") + } + failed = false + r = &Recur{4, &failed} + p.Sprintf("recur@%p, value: %d\n", r, r.i) + if failed { + t.Error("fail with value") + } +} + +func TestNilDoesNotBecomeTyped(t *testing.T) { + p := NewPrinter(language.Und) + type A struct{} + type B struct{} + var a *A = nil + var b B = B{} + got := p.Sprintf("%s %s %s %s %s", nil, a, nil, b, nil) // go vet should complain about this line. + const expect = "%!s() %!s(*message.A=) %!s() {} %!s()" + if got != expect { + t.Errorf("expected:\n\t%q\ngot:\n\t%q", expect, got) + } +} + +var formatterFlagTests = []struct { + in string + val interface{} + out string +}{ + // scalar values with the (unused by fmt) 'a' verb. + {"%a", flagPrinter{}, "[%a]"}, + {"%-a", flagPrinter{}, "[%-a]"}, + {"%+a", flagPrinter{}, "[%+a]"}, + {"%#a", flagPrinter{}, "[%#a]"}, + {"% a", flagPrinter{}, "[% a]"}, + {"%0a", flagPrinter{}, "[%0a]"}, + {"%1.2a", flagPrinter{}, "[%1.2a]"}, + {"%-1.2a", flagPrinter{}, "[%-1.2a]"}, + {"%+1.2a", flagPrinter{}, "[%+1.2a]"}, + {"%-+1.2a", flagPrinter{}, "[%+-1.2a]"}, + {"%-+1.2abc", flagPrinter{}, "[%+-1.2a]bc"}, + {"%-1.2abc", flagPrinter{}, "[%-1.2a]bc"}, + + // composite values with the 'a' verb + {"%a", [1]flagPrinter{}, "[[%a]]"}, + {"%-a", [1]flagPrinter{}, "[[%-a]]"}, + {"%+a", [1]flagPrinter{}, "[[%+a]]"}, + {"%#a", [1]flagPrinter{}, "[[%#a]]"}, + {"% a", [1]flagPrinter{}, "[[% a]]"}, + {"%0a", [1]flagPrinter{}, "[[%0a]]"}, + {"%1.2a", [1]flagPrinter{}, "[[%1.2a]]"}, + {"%-1.2a", [1]flagPrinter{}, "[[%-1.2a]]"}, + {"%+1.2a", [1]flagPrinter{}, "[[%+1.2a]]"}, + {"%-+1.2a", [1]flagPrinter{}, "[[%+-1.2a]]"}, + {"%-+1.2abc", [1]flagPrinter{}, "[[%+-1.2a]]bc"}, + {"%-1.2abc", [1]flagPrinter{}, "[[%-1.2a]]bc"}, + + // simple values with the 'v' verb + {"%v", flagPrinter{}, "[%v]"}, + {"%-v", flagPrinter{}, "[%-v]"}, + {"%+v", flagPrinter{}, "[%+v]"}, + {"%#v", flagPrinter{}, "[%#v]"}, + {"% v", flagPrinter{}, "[% v]"}, + {"%0v", flagPrinter{}, "[%0v]"}, + {"%1.2v", flagPrinter{}, "[%1.2v]"}, + {"%-1.2v", flagPrinter{}, "[%-1.2v]"}, + {"%+1.2v", flagPrinter{}, "[%+1.2v]"}, + {"%-+1.2v", flagPrinter{}, "[%+-1.2v]"}, + {"%-+1.2vbc", flagPrinter{}, "[%+-1.2v]bc"}, + {"%-1.2vbc", flagPrinter{}, "[%-1.2v]bc"}, + + // composite values with the 'v' verb. + {"%v", [1]flagPrinter{}, "[[%v]]"}, + {"%-v", [1]flagPrinter{}, "[[%-v]]"}, + {"%+v", [1]flagPrinter{}, "[[%+v]]"}, + {"%#v", [1]flagPrinter{}, "[1]message.flagPrinter{[%#v]}"}, + {"% v", [1]flagPrinter{}, "[[% v]]"}, + {"%0v", [1]flagPrinter{}, "[[%0v]]"}, + {"%1.2v", [1]flagPrinter{}, "[[%1.2v]]"}, + {"%-1.2v", [1]flagPrinter{}, "[[%-1.2v]]"}, + {"%+1.2v", [1]flagPrinter{}, "[[%+1.2v]]"}, + {"%-+1.2v", [1]flagPrinter{}, "[[%+-1.2v]]"}, + {"%-+1.2vbc", [1]flagPrinter{}, "[[%+-1.2v]]bc"}, + {"%-1.2vbc", [1]flagPrinter{}, "[[%-1.2v]]bc"}, +} + +func TestFormatterFlags(t *testing.T) { + p := NewPrinter(language.Und) + for _, tt := range formatterFlagTests { + s := p.Sprintf(tt.in, tt.val) + if s != tt.out { + t.Errorf("Sprintf(%q, %T) = %q, want %q", tt.in, tt.val, s, tt.out) + } + } +} + +func TestParsenum(t *testing.T) { + testCases := []struct { + s string + start, end int + num int + isnum bool + newi int + }{ + {"a123", 0, 4, 0, false, 0}, + {"1234", 1, 1, 0, false, 1}, + {"123a", 0, 4, 123, true, 3}, + {"12a3", 0, 4, 12, true, 2}, + {"1234", 0, 4, 1234, true, 4}, + {"1a234", 1, 3, 0, false, 1}, + } + for _, tt := range testCases { + num, isnum, newi := parsenum(tt.s, tt.start, tt.end) + if num != tt.num || isnum != tt.isnum || newi != tt.newi { + t.Errorf("parsenum(%q, %d, %d) = %d, %v, %d, want %d, %v, %d", tt.s, tt.start, tt.end, num, isnum, newi, tt.num, tt.isnum, tt.newi) + } + } +} diff --git a/vendor/golang.org/x/text/message/format.go b/vendor/golang.org/x/text/message/format.go new file mode 100644 index 000000000..d3340d194 --- /dev/null +++ b/vendor/golang.org/x/text/message/format.go @@ -0,0 +1,532 @@ +// 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 message + +import ( + "bytes" + "strconv" + "unicode/utf8" +) + +const ( + ldigits = "0123456789abcdefx" + udigits = "0123456789ABCDEFX" +) + +const ( + signed = true + unsigned = false +) + +// flags placed in a separate struct for easy clearing. +type fmtFlags struct { + widPresent bool + precPresent bool + minus bool + plus bool + sharp bool + space bool + zero bool + + // For the formats %+v %#v, we set the plusV/sharpV flags + // and clear the plus/sharp flags since %+v and %#v are in effect + // different, flagless formats set at the top level. + plusV bool + sharpV bool +} + +// A formatInfo is the raw formatter used by Printf etc. +// It prints into a buffer that must be set up separately. +type formatInfo struct { + buf *bytes.Buffer + + fmtFlags + + wid int // width + prec int // precision + + // intbuf is large enough to store %b of an int64 with a sign and + // avoids padding at the end of the struct on 32 bit architectures. + intbuf [68]byte +} + +func (f *formatInfo) clearflags() { + f.fmtFlags = fmtFlags{} +} + +func (f *formatInfo) init(buf *bytes.Buffer) { + f.buf = buf + f.clearflags() +} + +// writePadding generates n bytes of padding. +func (f *formatInfo) writePadding(n int) { + if n <= 0 { // No padding bytes needed. + return + } + f.buf.Grow(n) + // Decide which byte the padding should be filled with. + padByte := byte(' ') + if f.zero { + padByte = byte('0') + } + // Fill padding with padByte. + for i := 0; i < n; i++ { + f.buf.WriteByte(padByte) // TODO: make more efficient. + } +} + +// pad appends b to f.buf, padded on left (!f.minus) or right (f.minus). +func (f *formatInfo) pad(b []byte) { + if !f.widPresent || f.wid == 0 { + f.buf.Write(b) + return + } + width := f.wid - utf8.RuneCount(b) + if !f.minus { + // left padding + f.writePadding(width) + f.buf.Write(b) + } else { + // right padding + f.buf.Write(b) + f.writePadding(width) + } +} + +// padString appends s to f.buf, padded on left (!f.minus) or right (f.minus). +func (f *formatInfo) padString(s string) { + if !f.widPresent || f.wid == 0 { + f.buf.WriteString(s) + return + } + width := f.wid - utf8.RuneCountInString(s) + if !f.minus { + // left padding + f.writePadding(width) + f.buf.WriteString(s) + } else { + // right padding + f.buf.WriteString(s) + f.writePadding(width) + } +} + +// fmt_boolean formats a boolean. +func (f *formatInfo) fmt_boolean(v bool) { + if v { + f.padString("true") + } else { + f.padString("false") + } +} + +// fmt_unicode formats a uint64 as "U+0078" or with f.sharp set as "U+0078 'x'". +func (f *formatInfo) fmt_unicode(u uint64) { + buf := f.intbuf[0:] + + // With default precision set the maximum needed buf length is 18 + // for formatting -1 with %#U ("U+FFFFFFFFFFFFFFFF") which fits + // into the already allocated intbuf with a capacity of 68 bytes. + prec := 4 + if f.precPresent && f.prec > 4 { + prec = f.prec + // Compute space needed for "U+" , number, " '", character, "'". + width := 2 + prec + 2 + utf8.UTFMax + 1 + if width > len(buf) { + buf = make([]byte, width) + } + } + + // Format into buf, ending at buf[i]. Formatting numbers is easier right-to-left. + i := len(buf) + + // For %#U we want to add a space and a quoted character at the end of the buffer. + if f.sharp && u <= utf8.MaxRune && strconv.IsPrint(rune(u)) { + i-- + buf[i] = '\'' + i -= utf8.RuneLen(rune(u)) + utf8.EncodeRune(buf[i:], rune(u)) + i-- + buf[i] = '\'' + i-- + buf[i] = ' ' + } + // Format the Unicode code point u as a hexadecimal number. + for u >= 16 { + i-- + buf[i] = udigits[u&0xF] + prec-- + u >>= 4 + } + i-- + buf[i] = udigits[u] + prec-- + // Add zeros in front of the number until requested precision is reached. + for prec > 0 { + i-- + buf[i] = '0' + prec-- + } + // Add a leading "U+". + i-- + buf[i] = '+' + i-- + buf[i] = 'U' + + oldZero := f.zero + f.zero = false + f.pad(buf[i:]) + f.zero = oldZero +} + +// fmt_integer formats signed and unsigned integers. +func (f *formatInfo) fmt_integer(u uint64, base int, isSigned bool, digits string) { + negative := isSigned && int64(u) < 0 + if negative { + u = -u + } + + buf := f.intbuf[0:] + // The already allocated f.intbuf with a capacity of 68 bytes + // is large enough for integer formatting when no precision or width is set. + if f.widPresent || f.precPresent { + // Account 3 extra bytes for possible addition of a sign and "0x". + width := 3 + f.wid + f.prec // wid and prec are always positive. + if width > len(buf) { + // We're going to need a bigger boat. + buf = make([]byte, width) + } + } + + // Two ways to ask for extra leading zero digits: %.3d or %03d. + // If both are specified the f.zero flag is ignored and + // padding with spaces is used instead. + prec := 0 + if f.precPresent { + prec = f.prec + // Precision of 0 and value of 0 means "print nothing" but padding. + if prec == 0 && u == 0 { + oldZero := f.zero + f.zero = false + f.writePadding(f.wid) + f.zero = oldZero + return + } + } else if f.zero && f.widPresent { + prec = f.wid + if negative || f.plus || f.space { + prec-- // leave room for sign + } + } + + // Because printing is easier right-to-left: format u into buf, ending at buf[i]. + // We could make things marginally faster by splitting the 32-bit case out + // into a separate block but it's not worth the duplication, so u has 64 bits. + i := len(buf) + // Use constants for the division and modulo for more efficient code. + // Switch cases ordered by popularity. + switch base { + case 10: + for u >= 10 { + i-- + next := u / 10 + buf[i] = byte('0' + u - next*10) + u = next + } + case 16: + for u >= 16 { + i-- + buf[i] = digits[u&0xF] + u >>= 4 + } + case 8: + for u >= 8 { + i-- + buf[i] = byte('0' + u&7) + u >>= 3 + } + case 2: + for u >= 2 { + i-- + buf[i] = byte('0' + u&1) + u >>= 1 + } + default: + panic("fmt: unknown base; can't happen") + } + i-- + buf[i] = digits[u] + for i > 0 && prec > len(buf)-i { + i-- + buf[i] = '0' + } + + // Various prefixes: 0x, -, etc. + if f.sharp { + switch base { + case 8: + if buf[i] != '0' { + i-- + buf[i] = '0' + } + case 16: + // Add a leading 0x or 0X. + i-- + buf[i] = digits[16] + i-- + buf[i] = '0' + } + } + + if negative { + i-- + buf[i] = '-' + } else if f.plus { + i-- + buf[i] = '+' + } else if f.space { + i-- + buf[i] = ' ' + } + + // Left padding with zeros has already been handled like precision earlier + // or the f.zero flag is ignored due to an explicitly set precision. + oldZero := f.zero + f.zero = false + f.pad(buf[i:]) + f.zero = oldZero +} + +// truncate truncates the string to the specified precision, if present. +func (f *formatInfo) truncate(s string) string { + if f.precPresent { + n := f.prec + for i := range s { + n-- + if n < 0 { + return s[:i] + } + } + } + return s +} + +// fmt_s formats a string. +func (f *formatInfo) fmt_s(s string) { + s = f.truncate(s) + f.padString(s) +} + +// fmt_sbx formats a string or byte slice as a hexadecimal encoding of its bytes. +func (f *formatInfo) fmt_sbx(s string, b []byte, digits string) { + length := len(b) + if b == nil { + // No byte slice present. Assume string s should be encoded. + length = len(s) + } + // Set length to not process more bytes than the precision demands. + if f.precPresent && f.prec < length { + length = f.prec + } + // Compute width of the encoding taking into account the f.sharp and f.space flag. + width := 2 * length + if width > 0 { + if f.space { + // Each element encoded by two hexadecimals will get a leading 0x or 0X. + if f.sharp { + width *= 2 + } + // Elements will be separated by a space. + width += length - 1 + } else if f.sharp { + // Only a leading 0x or 0X will be added for the whole string. + width += 2 + } + } else { // The byte slice or string that should be encoded is empty. + if f.widPresent { + f.writePadding(f.wid) + } + return + } + // Handle padding to the left. + if f.widPresent && f.wid > width && !f.minus { + f.writePadding(f.wid - width) + } + // Write the encoding directly into the output buffer. + buf := f.buf + if f.sharp { + // Add leading 0x or 0X. + buf.WriteByte('0') + buf.WriteByte(digits[16]) + } + var c byte + for i := 0; i < length; i++ { + if f.space && i > 0 { + // Separate elements with a space. + buf.WriteByte(' ') + if f.sharp { + // Add leading 0x or 0X for each element. + buf.WriteByte('0') + buf.WriteByte(digits[16]) + } + } + if b != nil { + c = b[i] // Take a byte from the input byte slice. + } else { + c = s[i] // Take a byte from the input string. + } + // Encode each byte as two hexadecimal digits. + buf.WriteByte(digits[c>>4]) + buf.WriteByte(digits[c&0xF]) + } + // Handle padding to the right. + if f.widPresent && f.wid > width && f.minus { + f.writePadding(f.wid - width) + } +} + +// fmt_sx formats a string as a hexadecimal encoding of its bytes. +func (f *formatInfo) fmt_sx(s, digits string) { + f.fmt_sbx(s, nil, digits) +} + +// fmt_bx formats a byte slice as a hexadecimal encoding of its bytes. +func (f *formatInfo) fmt_bx(b []byte, digits string) { + f.fmt_sbx("", b, digits) +} + +// fmt_q formats a string as a double-quoted, escaped Go string constant. +// If f.sharp is set a raw (backquoted) string may be returned instead +// if the string does not contain any control characters other than tab. +func (f *formatInfo) fmt_q(s string) { + s = f.truncate(s) + if f.sharp && strconv.CanBackquote(s) { + f.padString("`" + s + "`") + return + } + buf := f.intbuf[:0] + if f.plus { + f.pad(strconv.AppendQuoteToASCII(buf, s)) + } else { + f.pad(strconv.AppendQuote(buf, s)) + } +} + +// fmt_c formats an integer as a Unicode character. +// If the character is not valid Unicode, it will print '\ufffd'. +func (f *formatInfo) fmt_c(c uint64) { + r := rune(c) + if c > utf8.MaxRune { + r = utf8.RuneError + } + buf := f.intbuf[:0] + w := utf8.EncodeRune(buf[:utf8.UTFMax], r) + f.pad(buf[:w]) +} + +// fmt_qc formats an integer as a single-quoted, escaped Go character constant. +// If the character is not valid Unicode, it will print '\ufffd'. +func (f *formatInfo) fmt_qc(c uint64) { + r := rune(c) + if c > utf8.MaxRune { + r = utf8.RuneError + } + buf := f.intbuf[:0] + if f.plus { + f.pad(strconv.AppendQuoteRuneToASCII(buf, r)) + } else { + f.pad(strconv.AppendQuoteRune(buf, r)) + } +} + +// fmt_float formats a float64. It assumes that verb is a valid format specifier +// for strconv.AppendFloat and therefore fits into a byte. +func (f *formatInfo) fmt_float(v float64, size int, verb rune, prec int) { + // Explicit precision in format specifier overrules default precision. + if f.precPresent { + prec = f.prec + } + // Format number, reserving space for leading + sign if needed. + num := strconv.AppendFloat(f.intbuf[:1], v, byte(verb), prec, size) + if num[1] == '-' || num[1] == '+' { + num = num[1:] + } else { + num[0] = '+' + } + // f.space means to add a leading space instead of a "+" sign unless + // the sign is explicitly asked for by f.plus. + if f.space && num[0] == '+' && !f.plus { + num[0] = ' ' + } + // Special handling for infinities and NaN, + // which don't look like a number so shouldn't be padded with zeros. + if num[1] == 'I' || num[1] == 'N' { + oldZero := f.zero + f.zero = false + // Remove sign before NaN if not asked for. + if num[1] == 'N' && !f.space && !f.plus { + num = num[1:] + } + f.pad(num) + f.zero = oldZero + return + } + // The sharp flag forces printing a decimal point for non-binary formats + // and retains trailing zeros, which we may need to restore. + if f.sharp && verb != 'b' { + digits := 0 + switch verb { + case 'v', 'g', 'G': + digits = prec + // If no precision is set explicitly use a precision of 6. + if digits == -1 { + digits = 6 + } + } + + // Buffer pre-allocated with enough room for + // exponent notations of the form "e+123". + var tailBuf [5]byte + tail := tailBuf[:0] + + hasDecimalPoint := false + // Starting from i = 1 to skip sign at num[0]. + for i := 1; i < len(num); i++ { + switch num[i] { + case '.': + hasDecimalPoint = true + case 'e', 'E': + tail = append(tail, num[i:]...) + num = num[:i] + default: + digits-- + } + } + if !hasDecimalPoint { + num = append(num, '.') + } + for digits > 0 { + num = append(num, '0') + digits-- + } + num = append(num, tail...) + } + // We want a sign if asked for and if the sign is not positive. + if f.plus || num[0] != '+' { + // If we're zero padding to the left we want the sign before the leading zeros. + // Achieve this by writing the sign out and then padding the unsigned number. + if f.zero && f.widPresent && f.wid > len(num) { + f.buf.WriteByte(num[0]) + f.writePadding(f.wid - len(num)) + f.buf.Write(num[1:]) + return + } + f.pad(num) + return + } + // No sign to show and the number is positive; just print the unsigned number. + f.pad(num[1:]) +} diff --git a/vendor/golang.org/x/text/message/message.go b/vendor/golang.org/x/text/message/message.go index 32ff3ef90..8b3bad1b6 100644 --- a/vendor/golang.org/x/text/message/message.go +++ b/vendor/golang.org/x/text/message/message.go @@ -10,90 +10,121 @@ package message // import "golang.org/x/text/message" import ( - "fmt" "io" - "strings" + "os" - "golang.org/x/text/internal/format" "golang.org/x/text/language" + "golang.org/x/text/message/catalog" ) +// TODO: allow more than one goroutine per printer. This will allow porting from +// fmt much less error prone. + // A Printer implements language-specific formatted I/O analogous to the fmt // package. Only one goroutine may use a Printer at the same time. type Printer struct { - tag language.Tag - - cat *Catalog + // Wrap the fields in a hidden type to hide some of the implemented methods. + printer printer // NOTE: limiting one goroutine per Printer allows for many optimizations // and simplifications. We can consider removing this restriction down the // road if it the benefits do not seem to outweigh the disadvantages. } +type options struct { + cat *catalog.Catalog + // TODO: + // - allow %s to print integers in written form (tables are likely too large + // to enable this by default). + // - list behavior + // +} + +// An Option defines an option of a Printer. +type Option func(o *options) + +// Catalog defines the catalog to be used. +func Catalog(c *catalog.Catalog) Option { + return func(o *options) { o.cat = c } +} + // NewPrinter returns a Printer that formats messages tailored to language t. -func NewPrinter(t language.Tag) *Printer { - return DefaultCatalog.Printer(t) +func NewPrinter(t language.Tag, opts ...Option) *Printer { + options := &options{ + cat: defaultCatalog, + } + for _, o := range opts { + o(options) + } + p := &Printer{printer{ + tag: t, + }} + p.printer.catContext = options.cat.Context(t, &p.printer) + return p } // Sprint is like fmt.Sprint, but using language-specific formatting. func (p *Printer) Sprint(a ...interface{}) string { - return fmt.Sprint(p.bindArgs(a)...) + p.printer.reset() + p.printer.doPrint(a) + return p.printer.String() } // Fprint is like fmt.Fprint, but using language-specific formatting. func (p *Printer) Fprint(w io.Writer, a ...interface{}) (n int, err error) { - return fmt.Fprint(w, p.bindArgs(a)...) + p.printer.reset() + p.printer.doPrint(a) + n64, err := io.Copy(w, &p.printer.Buffer) + return int(n64), err } // Print is like fmt.Print, but using language-specific formatting. func (p *Printer) Print(a ...interface{}) (n int, err error) { - return fmt.Print(p.bindArgs(a)...) + return p.Fprint(os.Stdout, a...) } // Sprintln is like fmt.Sprintln, but using language-specific formatting. func (p *Printer) Sprintln(a ...interface{}) string { - return fmt.Sprintln(p.bindArgs(a)...) + p.printer.reset() + p.printer.doPrintln(a) + return p.printer.String() } // Fprintln is like fmt.Fprintln, but using language-specific formatting. func (p *Printer) Fprintln(w io.Writer, a ...interface{}) (n int, err error) { - return fmt.Fprintln(w, p.bindArgs(a)...) + p.printer.reset() + p.printer.doPrintln(a) + n64, err := io.Copy(w, &p.printer.Buffer) + return int(n64), err } // Println is like fmt.Println, but using language-specific formatting. func (p *Printer) Println(a ...interface{}) (n int, err error) { - return fmt.Println(p.bindArgs(a)...) + return p.Fprintln(os.Stdout, a...) } // Sprintf is like fmt.Sprintf, but using language-specific formatting. func (p *Printer) Sprintf(key Reference, a ...interface{}) string { - msg, hasSub := p.lookup(key) - if !hasSub { - return fmt.Sprintf(msg) // work around limitation of fmt - } - return fmt.Sprintf(msg, p.bindArgs(a)...) + lookupAndFormat(p, key, a) + return p.printer.String() } // Fprintf is like fmt.Fprintf, but using language-specific formatting. func (p *Printer) Fprintf(w io.Writer, key Reference, a ...interface{}) (n int, err error) { - msg, hasSub := p.lookup(key) - if !hasSub { - return fmt.Fprintf(w, msg) // work around limitation of fmt - } - return fmt.Fprintf(w, msg, p.bindArgs(a)...) + lookupAndFormat(p, key, a) + return w.Write(p.printer.Bytes()) } // Printf is like fmt.Printf, but using language-specific formatting. func (p *Printer) Printf(key Reference, a ...interface{}) (n int, err error) { - msg, hasSub := p.lookup(key) - if !hasSub { - return fmt.Printf(msg) // work around limitation of fmt - } - return fmt.Printf(msg, p.bindArgs(a)...) + lookupAndFormat(p, key, a) + return os.Stdout.Write(p.printer.Bytes()) } -func (p *Printer) lookup(r Reference) (msg string, hasSub bool) { - var id string +func lookupAndFormat(p *Printer, r Reference, a []interface{}) { + p.printer.reset() + p.printer.args = a + var id, msg string switch v := r.(type) { case string: id, msg = v, v @@ -102,33 +133,31 @@ func (p *Printer) lookup(r Reference) (msg string, hasSub bool) { default: panic("key argument is not a Reference") } - if s, ok := p.cat.get(p.tag, id); ok { - msg = s - } - // fmt does not allow all arguments to be dropped in a format string. It - // only allows arguments to be dropped if at least one of the substitutions - // uses the positional marker (e.g. %[1]s). This hack works around this. - // TODO: This is only an approximation of the parsing of substitution - // patterns. Make more precise once we know if we can get by with fmt's - // formatting, which may not be the case. - for i := 0; i < len(msg)-1; i++ { - if msg[i] == '%' { - for i++; i < len(msg); i++ { - if strings.IndexByte("[]#+- *01234567890.", msg[i]) < 0 { - break - } - } - if i < len(msg) && msg[i] != '%' { - hasSub = true - break - } + + if p.printer.catContext.Execute(id) == catalog.ErrNotFound { + if p.printer.catContext.Execute(msg) == catalog.ErrNotFound { + p.printer.Render(msg) + return } } - return msg, hasSub +} + +// Arg implements catmsg.Renderer. +func (p *printer) Arg(i int) interface{} { // TODO, also return "ok" bool + if uint(i) < uint(len(p.args)) { + return p.args[i] + } + return nil +} + +// Render implements catmsg.Renderer. +func (p *printer) Render(msg string) { + p.doPrintf(msg) } // A Reference is a string or a message reference. type Reference interface { + // TODO: also allow []string } // Key creates a message Reference for a message where the given id is used for @@ -140,46 +169,3 @@ func Key(id string, fallback string) Reference { type key struct { id, fallback string } - -// bindArgs wraps arguments with implementation of fmt.Formatter, if needed. -func (p *Printer) bindArgs(a []interface{}) []interface{} { - out := make([]interface{}, len(a)) - for i, x := range a { - switch v := x.(type) { - case fmt.Formatter: - // Wrap the value with a Formatter that augments the State with - // language-specific attributes. - out[i] = &value{v, p} - - // NOTE: as we use fmt.Formatter, we can't distinguish between - // regular and localized formatters, so we always need to wrap it. - - // TODO: handle - // - numbers - // - lists - // - time? - default: - out[i] = x - } - } - return out -} - -// state implements "golang.org/x/text/internal/format".State. -type state struct { - fmt.State - p *Printer -} - -func (s *state) Language() language.Tag { return s.p.tag } - -var _ format.State = &state{} - -type value struct { - x fmt.Formatter - p *Printer -} - -func (v *value) Format(s fmt.State, verb rune) { - v.x.Format(&state{s, v.p}, verb) -} diff --git a/vendor/golang.org/x/text/message/message_test.go b/vendor/golang.org/x/text/message/message_test.go index f7dba8d06..e411415b1 100644 --- a/vendor/golang.org/x/text/message/message_test.go +++ b/vendor/golang.org/x/text/message/message_test.go @@ -10,8 +10,10 @@ import ( "io" "testing" + "golang.org/x/text/internal" "golang.org/x/text/internal/format" "golang.org/x/text/language" + "golang.org/x/text/message/catalog" ) type formatFunc func(s fmt.State, v rune) @@ -130,20 +132,35 @@ func TestFormatSelection(t *testing.T) { cat, _ := initCat(tc.cat) for i, pt := range tc.test { - p := cat.Printer(language.MustParse(pt.tag)) + t.Run(fmt.Sprintf("%s:%d", tc.desc, i), func(t *testing.T) { + p := NewPrinter(language.MustParse(pt.tag), Catalog(cat)) - if got := p.Sprintf(pt.key, pt.args...); got != pt.want { - t.Errorf("%s:%d:Sprintf(%s, %v) = %s; want %s", - tc.desc, i, pt.key, pt.args, got, pt.want) - continue // Next error will likely be the same. - } + if got := p.Sprintf(pt.key, pt.args...); got != pt.want { + t.Errorf("Sprintf(%q, %v) = %s; want %s", + pt.key, pt.args, got, pt.want) + return // Next error will likely be the same. + } - w := &bytes.Buffer{} - p.Fprintf(w, pt.key, pt.args...) - if got := w.String(); got != pt.want { - t.Errorf("%s:%d:Fprintf(%s, %v) = %s; want %s", - tc.desc, i, pt.key, pt.args, got, pt.want) - } + w := &bytes.Buffer{} + p.Fprintf(w, pt.key, pt.args...) + if got := w.String(); got != pt.want { + t.Errorf("Fprintf(%q, %v) = %s; want %s", + pt.key, pt.args, got, pt.want) + } + }) } } } + +type entry struct{ tag, key, msg string } + +func initCat(entries []entry) (*catalog.Catalog, []language.Tag) { + tags := []language.Tag{} + cat := catalog.New() + for _, e := range entries { + tag := language.MustParse(e.tag) + tags = append(tags, tag) + cat.SetString(tag, e.key, e.msg) + } + return cat, internal.UniqueTags(tags) +} diff --git a/vendor/golang.org/x/text/message/print.go b/vendor/golang.org/x/text/message/print.go new file mode 100644 index 000000000..caa50b6be --- /dev/null +++ b/vendor/golang.org/x/text/message/print.go @@ -0,0 +1,972 @@ +// 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 message + +import ( + "bytes" + // TODO: consider copying interfaces from package fmt to avoid dependency. + "fmt" + "reflect" + "unicode/utf8" + + "golang.org/x/text/language" + "golang.org/x/text/message/catalog" +) + +// Strings for use with buffer.WriteString. +// This is less overhead than using buffer.Write with byte arrays. +const ( + commaSpaceString = ", " + nilAngleString = "" + nilParenString = "(nil)" + nilString = "nil" + mapString = "map[" + percentBangString = "%!" + missingString = "(MISSING)" + badIndexString = "(BADINDEX)" + panicString = "(PANIC=" + extraString = "%!(EXTRA " + badWidthString = "%!(BADWIDTH)" + badPrecString = "%!(BADPREC)" + noVerbString = "%!(NOVERB)" + + invReflectString = "" +) + +// printer is used to store a printer's state. +// It implements "golang.org/x/text/internal/format".State. +type printer struct { + // the context for looking up message translations + catContext *catalog.Context + // the language + tag language.Tag + + // buffer for accumulating output. + bytes.Buffer + + // retain arguments across calls. + args []interface{} + // retain current argument number across calls + argNum int + // arg holds the current item, as an interface{}. + arg interface{} + // value is used instead of arg for reflect values. + value reflect.Value + + // fmt is used to format basic items such as integers or strings. + fmt formatInfo + + // reordered records whether the format string used argument reordering. + reordered bool + // goodArgNum records whether the most recent reordering directive was valid. + goodArgNum bool + // panicking is set by catchPanic to avoid infinite panic, recover, panic, ... recursion. + panicking bool + // erroring is set when printing an error string to guard against calling handleMethods. + erroring bool +} + +func (p *printer) reset() { + p.Buffer.Reset() + p.argNum = 0 + p.reordered = false + p.panicking = false + p.erroring = false + p.fmt.init(&p.Buffer) +} + +// Language implements "golang.org/x/text/internal/format".State. +func (p *printer) Language() language.Tag { return p.tag } + +func (p *printer) Width() (wid int, ok bool) { return p.fmt.wid, p.fmt.widPresent } + +func (p *printer) Precision() (prec int, ok bool) { return p.fmt.prec, p.fmt.precPresent } + +func (p *printer) Flag(b int) bool { + switch b { + case '-': + return p.fmt.minus + case '+': + return p.fmt.plus || p.fmt.plusV + case '#': + return p.fmt.sharp || p.fmt.sharpV + case ' ': + return p.fmt.space + case '0': + return p.fmt.zero + } + return false +} + +// getField gets the i'th field of the struct value. +// If the field is itself is an interface, return a value for +// the thing inside the interface, not the interface itself. +func getField(v reflect.Value, i int) reflect.Value { + val := v.Field(i) + if val.Kind() == reflect.Interface && !val.IsNil() { + val = val.Elem() + } + return val +} + +// tooLarge reports whether the magnitude of the integer is +// too large to be used as a formatting width or precision. +func tooLarge(x int) bool { + const max int = 1e6 + return x > max || x < -max +} + +// parsenum converts ASCII to integer. num is 0 (and isnum is false) if no number present. +func parsenum(s string, start, end int) (num int, isnum bool, newi int) { + if start >= end { + return 0, false, end + } + for newi = start; newi < end && '0' <= s[newi] && s[newi] <= '9'; newi++ { + if tooLarge(num) { + return 0, false, end // Overflow; crazy long number most likely. + } + num = num*10 + int(s[newi]-'0') + isnum = true + } + return +} + +func (p *printer) unknownType(v reflect.Value) { + if !v.IsValid() { + p.WriteString(nilAngleString) + return + } + p.WriteByte('?') + p.WriteString(v.Type().String()) + p.WriteByte('?') +} + +func (p *printer) badVerb(verb rune) { + p.erroring = true + p.WriteString(percentBangString) + p.WriteRune(verb) + p.WriteByte('(') + switch { + case p.arg != nil: + p.WriteString(reflect.TypeOf(p.arg).String()) + p.WriteByte('=') + p.printArg(p.arg, 'v') + case p.value.IsValid(): + p.WriteString(p.value.Type().String()) + p.WriteByte('=') + p.printValue(p.value, 'v', 0) + default: + p.WriteString(nilAngleString) + } + p.WriteByte(')') + p.erroring = false +} + +func (p *printer) fmtBool(v bool, verb rune) { + switch verb { + case 't', 'v': + p.fmt.fmt_boolean(v) + default: + p.badVerb(verb) + } +} + +// fmt0x64 formats a uint64 in hexadecimal and prefixes it with 0x or +// not, as requested, by temporarily setting the sharp flag. +func (p *printer) fmt0x64(v uint64, leading0x bool) { + sharp := p.fmt.sharp + p.fmt.sharp = leading0x + p.fmt.fmt_integer(v, 16, unsigned, ldigits) + p.fmt.sharp = sharp +} + +// fmtInteger formats a signed or unsigned integer. +func (p *printer) fmtInteger(v uint64, isSigned bool, verb rune) { + switch verb { + case 'v': + if p.fmt.sharpV && !isSigned { + p.fmt0x64(v, true) + } else { + p.fmt.fmt_integer(v, 10, isSigned, ldigits) + } + case 'd': + p.fmt.fmt_integer(v, 10, isSigned, ldigits) + case 'b': + p.fmt.fmt_integer(v, 2, isSigned, ldigits) + case 'o': + p.fmt.fmt_integer(v, 8, isSigned, ldigits) + case 'x': + p.fmt.fmt_integer(v, 16, isSigned, ldigits) + case 'X': + p.fmt.fmt_integer(v, 16, isSigned, udigits) + case 'c': + p.fmt.fmt_c(v) + case 'q': + if v <= utf8.MaxRune { + p.fmt.fmt_qc(v) + } else { + p.badVerb(verb) + } + case 'U': + p.fmt.fmt_unicode(v) + default: + p.badVerb(verb) + } +} + +// fmtFloat formats a float. The default precision for each verb +// is specified as last argument in the call to fmt_float. +func (p *printer) fmtFloat(v float64, size int, verb rune) { + switch verb { + case 'v': + p.fmt.fmt_float(v, size, 'g', -1) + case 'b', 'g', 'G': + p.fmt.fmt_float(v, size, verb, -1) + case 'f', 'e', 'E': + p.fmt.fmt_float(v, size, verb, 6) + case 'F': + p.fmt.fmt_float(v, size, 'f', 6) + default: + p.badVerb(verb) + } +} + +// fmtComplex formats a complex number v with +// r = real(v) and j = imag(v) as (r+ji) using +// fmtFloat for r and j formatting. +func (p *printer) fmtComplex(v complex128, size int, verb rune) { + // Make sure any unsupported verbs are found before the + // calls to fmtFloat to not generate an incorrect error string. + switch verb { + case 'v', 'b', 'g', 'G', 'f', 'F', 'e', 'E': + oldPlus := p.fmt.plus + p.WriteByte('(') + p.fmtFloat(real(v), size/2, verb) + // Imaginary part always has a sign. + p.fmt.plus = true + p.fmtFloat(imag(v), size/2, verb) + p.WriteString("i)") + p.fmt.plus = oldPlus + default: + p.badVerb(verb) + } +} + +func (p *printer) fmtString(v string, verb rune) { + switch verb { + case 'v': + if p.fmt.sharpV { + p.fmt.fmt_q(v) + } else { + p.fmt.fmt_s(v) + } + case 's': + p.fmt.fmt_s(v) + case 'x': + p.fmt.fmt_sx(v, ldigits) + case 'X': + p.fmt.fmt_sx(v, udigits) + case 'q': + p.fmt.fmt_q(v) + default: + p.badVerb(verb) + } +} + +func (p *printer) fmtBytes(v []byte, verb rune, typeString string) { + switch verb { + case 'v', 'd': + if p.fmt.sharpV { + p.WriteString(typeString) + if v == nil { + p.WriteString(nilParenString) + return + } + p.WriteByte('{') + for i, c := range v { + if i > 0 { + p.WriteString(commaSpaceString) + } + p.fmt0x64(uint64(c), true) + } + p.WriteByte('}') + } else { + p.WriteByte('[') + for i, c := range v { + if i > 0 { + p.WriteByte(' ') + } + p.fmt.fmt_integer(uint64(c), 10, unsigned, ldigits) + } + p.WriteByte(']') + } + case 's': + p.fmt.fmt_s(string(v)) + case 'x': + p.fmt.fmt_bx(v, ldigits) + case 'X': + p.fmt.fmt_bx(v, udigits) + case 'q': + p.fmt.fmt_q(string(v)) + default: + p.printValue(reflect.ValueOf(v), verb, 0) + } +} + +func (p *printer) fmtPointer(value reflect.Value, verb rune) { + var u uintptr + switch value.Kind() { + case reflect.Chan, reflect.Func, reflect.Map, reflect.Ptr, reflect.Slice, reflect.UnsafePointer: + u = value.Pointer() + default: + p.badVerb(verb) + return + } + + switch verb { + case 'v': + if p.fmt.sharpV { + p.WriteByte('(') + p.WriteString(value.Type().String()) + p.WriteString(")(") + if u == 0 { + p.WriteString(nilString) + } else { + p.fmt0x64(uint64(u), true) + } + p.WriteByte(')') + } else { + if u == 0 { + p.fmt.padString(nilAngleString) + } else { + p.fmt0x64(uint64(u), !p.fmt.sharp) + } + } + case 'p': + p.fmt0x64(uint64(u), !p.fmt.sharp) + case 'b', 'o', 'd', 'x', 'X': + p.fmtInteger(uint64(u), unsigned, verb) + default: + p.badVerb(verb) + } +} + +func (p *printer) catchPanic(arg interface{}, verb rune) { + if err := recover(); err != nil { + // If it's a nil pointer, just say "". The likeliest causes are a + // Stringer that fails to guard against nil or a nil pointer for a + // value receiver, and in either case, "" is a nice result. + if v := reflect.ValueOf(arg); v.Kind() == reflect.Ptr && v.IsNil() { + p.WriteString(nilAngleString) + return + } + // Otherwise print a concise panic message. Most of the time the panic + // value will print itself nicely. + if p.panicking { + // Nested panics; the recursion in printArg cannot succeed. + panic(err) + } + + oldFlags := p.fmt.fmtFlags + // For this output we want default behavior. + p.fmt.clearflags() + + p.WriteString(percentBangString) + p.WriteRune(verb) + p.WriteString(panicString) + p.panicking = true + p.printArg(err, 'v') + p.panicking = false + p.WriteByte(')') + + p.fmt.fmtFlags = oldFlags + } +} + +func (p *printer) handleMethods(verb rune) (handled bool) { + if p.erroring { + return + } + // Is it a Formatter? + if formatter, ok := p.arg.(fmt.Formatter); ok { + handled = true + defer p.catchPanic(p.arg, verb) + formatter.Format(p, verb) + return + } + + // If we're doing Go syntax and the argument knows how to supply it, take care of it now. + if p.fmt.sharpV { + if stringer, ok := p.arg.(fmt.GoStringer); ok { + handled = true + defer p.catchPanic(p.arg, verb) + // Print the result of GoString unadorned. + p.fmt.fmt_s(stringer.GoString()) + return + } + } else { + // If a string is acceptable according to the format, see if + // the value satisfies one of the string-valued interfaces. + // Println etc. set verb to %v, which is "stringable". + switch verb { + case 'v', 's', 'x', 'X', 'q': + // Is it an error or Stringer? + // The duplication in the bodies is necessary: + // setting handled and deferring catchPanic + // must happen before calling the method. + switch v := p.arg.(type) { + case error: + handled = true + defer p.catchPanic(p.arg, verb) + p.fmtString(v.Error(), verb) + return + + case fmt.Stringer: + handled = true + defer p.catchPanic(p.arg, verb) + p.fmtString(v.String(), verb) + return + } + } + } + return false +} + +func (p *printer) printArg(arg interface{}, verb rune) { + p.arg = arg + p.value = reflect.Value{} + + if arg == nil { + switch verb { + case 'T', 'v': + p.fmt.padString(nilAngleString) + default: + p.badVerb(verb) + } + return + } + + // Special processing considerations. + // %T (the value's type) and %p (its address) are special; we always do them first. + switch verb { + case 'T': + p.fmt.fmt_s(reflect.TypeOf(arg).String()) + return + case 'p': + p.fmtPointer(reflect.ValueOf(arg), 'p') + return + } + + // Some types can be done without reflection. + switch f := arg.(type) { + case bool: + p.fmtBool(f, verb) + case float32: + p.fmtFloat(float64(f), 32, verb) + case float64: + p.fmtFloat(f, 64, verb) + case complex64: + p.fmtComplex(complex128(f), 64, verb) + case complex128: + p.fmtComplex(f, 128, verb) + case int: + p.fmtInteger(uint64(f), signed, verb) + case int8: + p.fmtInteger(uint64(f), signed, verb) + case int16: + p.fmtInteger(uint64(f), signed, verb) + case int32: + p.fmtInteger(uint64(f), signed, verb) + case int64: + p.fmtInteger(uint64(f), signed, verb) + case uint: + p.fmtInteger(uint64(f), unsigned, verb) + case uint8: + p.fmtInteger(uint64(f), unsigned, verb) + case uint16: + p.fmtInteger(uint64(f), unsigned, verb) + case uint32: + p.fmtInteger(uint64(f), unsigned, verb) + case uint64: + p.fmtInteger(f, unsigned, verb) + case uintptr: + p.fmtInteger(uint64(f), unsigned, verb) + case string: + p.fmtString(f, verb) + case []byte: + p.fmtBytes(f, verb, "[]byte") + case reflect.Value: + // Handle extractable values with special methods + // since printValue does not handle them at depth 0. + if f.IsValid() && f.CanInterface() { + p.arg = f.Interface() + if p.handleMethods(verb) { + return + } + } + p.printValue(f, verb, 0) + default: + // If the type is not simple, it might have methods. + if !p.handleMethods(verb) { + // Need to use reflection, since the type had no + // interface methods that could be used for formatting. + p.printValue(reflect.ValueOf(f), verb, 0) + } + } +} + +// printValue is similar to printArg but starts with a reflect value, not an interface{} value. +// It does not handle 'p' and 'T' verbs because these should have been already handled by printArg. +func (p *printer) printValue(value reflect.Value, verb rune, depth int) { + // Handle values with special methods if not already handled by printArg (depth == 0). + if depth > 0 && value.IsValid() && value.CanInterface() { + p.arg = value.Interface() + if p.handleMethods(verb) { + return + } + } + p.arg = nil + p.value = value + + switch f := value; value.Kind() { + case reflect.Invalid: + if depth == 0 { + p.WriteString(invReflectString) + } else { + switch verb { + case 'v': + p.WriteString(nilAngleString) + default: + p.badVerb(verb) + } + } + case reflect.Bool: + p.fmtBool(f.Bool(), verb) + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + p.fmtInteger(uint64(f.Int()), signed, verb) + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + p.fmtInteger(f.Uint(), unsigned, verb) + case reflect.Float32: + p.fmtFloat(f.Float(), 32, verb) + case reflect.Float64: + p.fmtFloat(f.Float(), 64, verb) + case reflect.Complex64: + p.fmtComplex(f.Complex(), 64, verb) + case reflect.Complex128: + p.fmtComplex(f.Complex(), 128, verb) + case reflect.String: + p.fmtString(f.String(), verb) + case reflect.Map: + if p.fmt.sharpV { + p.WriteString(f.Type().String()) + if f.IsNil() { + p.WriteString(nilParenString) + return + } + p.WriteByte('{') + } else { + p.WriteString(mapString) + } + keys := f.MapKeys() + for i, key := range keys { + if i > 0 { + if p.fmt.sharpV { + p.WriteString(commaSpaceString) + } else { + p.WriteByte(' ') + } + } + p.printValue(key, verb, depth+1) + p.WriteByte(':') + p.printValue(f.MapIndex(key), verb, depth+1) + } + if p.fmt.sharpV { + p.WriteByte('}') + } else { + p.WriteByte(']') + } + case reflect.Struct: + if p.fmt.sharpV { + p.WriteString(f.Type().String()) + } + p.WriteByte('{') + for i := 0; i < f.NumField(); i++ { + if i > 0 { + if p.fmt.sharpV { + p.WriteString(commaSpaceString) + } else { + p.WriteByte(' ') + } + } + if p.fmt.plusV || p.fmt.sharpV { + if name := f.Type().Field(i).Name; name != "" { + p.WriteString(name) + p.WriteByte(':') + } + } + p.printValue(getField(f, i), verb, depth+1) + } + p.WriteByte('}') + case reflect.Interface: + value := f.Elem() + if !value.IsValid() { + if p.fmt.sharpV { + p.WriteString(f.Type().String()) + p.WriteString(nilParenString) + } else { + p.WriteString(nilAngleString) + } + } else { + p.printValue(value, verb, depth+1) + } + case reflect.Array, reflect.Slice: + switch verb { + case 's', 'q', 'x', 'X': + // Handle byte and uint8 slices and arrays special for the above verbs. + t := f.Type() + if t.Elem().Kind() == reflect.Uint8 { + var bytes []byte + if f.Kind() == reflect.Slice { + bytes = f.Bytes() + } else if f.CanAddr() { + bytes = f.Slice(0, f.Len()).Bytes() + } else { + // We have an array, but we cannot Slice() a non-addressable array, + // so we build a slice by hand. This is a rare case but it would be nice + // if reflection could help a little more. + bytes = make([]byte, f.Len()) + for i := range bytes { + bytes[i] = byte(f.Index(i).Uint()) + } + } + p.fmtBytes(bytes, verb, t.String()) + return + } + } + if p.fmt.sharpV { + p.WriteString(f.Type().String()) + if f.Kind() == reflect.Slice && f.IsNil() { + p.WriteString(nilParenString) + return + } + p.WriteByte('{') + for i := 0; i < f.Len(); i++ { + if i > 0 { + p.WriteString(commaSpaceString) + } + p.printValue(f.Index(i), verb, depth+1) + } + p.WriteByte('}') + } else { + p.WriteByte('[') + for i := 0; i < f.Len(); i++ { + if i > 0 { + p.WriteByte(' ') + } + p.printValue(f.Index(i), verb, depth+1) + } + p.WriteByte(']') + } + case reflect.Ptr: + // pointer to array or slice or struct? ok at top level + // but not embedded (avoid loops) + if depth == 0 && f.Pointer() != 0 { + switch a := f.Elem(); a.Kind() { + case reflect.Array, reflect.Slice, reflect.Struct, reflect.Map: + p.WriteByte('&') + p.printValue(a, verb, depth+1) + return + } + } + fallthrough + case reflect.Chan, reflect.Func, reflect.UnsafePointer: + p.fmtPointer(f, verb) + default: + p.unknownType(f) + } +} + +// intFromArg gets the argNumth element of a. On return, isInt reports whether the argument has integer type. +func (p *printer) intFromArg() (num int, isInt bool) { + if p.argNum < len(p.args) { + arg := p.args[p.argNum] + num, isInt = arg.(int) // Almost always OK. + if !isInt { + // Work harder. + switch v := reflect.ValueOf(arg); v.Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + n := v.Int() + if int64(int(n)) == n { + num = int(n) + isInt = true + } + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + n := v.Uint() + if int64(n) >= 0 && uint64(int(n)) == n { + num = int(n) + isInt = true + } + default: + // Already 0, false. + } + } + p.argNum++ + if tooLarge(num) { + num = 0 + isInt = false + } + } + return +} + +// parseArgNumber returns the value of the bracketed number, minus 1 +// (explicit argument numbers are one-indexed but we want zero-indexed). +// The opening bracket is known to be present at format[0]. +// The returned values are the index, the number of bytes to consume +// up to the closing paren, if present, and whether the number parsed +// ok. The bytes to consume will be 1 if no closing paren is present. +func parseArgNumber(format string) (index int, wid int, ok bool) { + // There must be at least 3 bytes: [n]. + if len(format) < 3 { + return 0, 1, false + } + + // Find closing bracket. + for i := 1; i < len(format); i++ { + if format[i] == ']' { + width, ok, newi := parsenum(format, 1, i) + if !ok || newi != i { + return 0, i + 1, false + } + return width - 1, i + 1, true // arg numbers are one-indexed and skip paren. + } + } + return 0, 1, false +} + +// updateArgNumber returns the next argument to evaluate, which is either the value of the passed-in +// argNum or the value of the bracketed integer that begins format[i:]. It also returns +// the new value of i, that is, the index of the next byte of the format to process. +func (p *printer) updateArgNumber(format string, i int) (newi int, found bool) { + if len(format) <= i || format[i] != '[' { + return i, false + } + p.reordered = true + index, wid, ok := parseArgNumber(format[i:]) + if ok && 0 <= index && index < len(p.args) { + p.argNum = index + return i + wid, true + } + p.goodArgNum = false + return i + wid, ok +} + +func (p *printer) badArgNum(verb rune) { + p.WriteString(percentBangString) + p.WriteRune(verb) + p.WriteString(badIndexString) +} + +func (p *printer) missingArg(verb rune) { + p.WriteString(percentBangString) + p.WriteRune(verb) + p.WriteString(missingString) +} + +func (p *printer) doPrintf(format string) { + end := len(format) + afterIndex := false // previous item in format was an index like [3]. +formatLoop: + for i := 0; i < end; { + p.goodArgNum = true + lasti := i + for i < end && format[i] != '%' { + i++ + } + if i > lasti { + p.WriteString(format[lasti:i]) + } + if i >= end { + // done processing format string + break + } + + // Process one verb + i++ + + // Do we have flags? + p.fmt.clearflags() + simpleFormat: + for ; i < end; i++ { + c := format[i] + switch c { + case '#': + p.fmt.sharp = true + case '0': + p.fmt.zero = !p.fmt.minus // Only allow zero padding to the left. + case '+': + p.fmt.plus = true + case '-': + p.fmt.minus = true + p.fmt.zero = false // Do not pad with zeros to the right. + case ' ': + p.fmt.space = true + default: + // Fast path for common case of ascii lower case simple verbs + // without precision or width or argument indices. + if 'a' <= c && c <= 'z' && p.argNum < len(p.args) { + if c == 'v' { + // Go syntax + p.fmt.sharpV = p.fmt.sharp + p.fmt.sharp = false + // Struct-field syntax + p.fmt.plusV = p.fmt.plus + p.fmt.plus = false + } + p.printArg(p.Arg(p.argNum), rune(c)) + p.argNum++ + i++ + continue formatLoop + } + // Format is more complex than simple flags and a verb or is malformed. + break simpleFormat + } + } + + // Do we have an explicit argument index? + i, afterIndex = p.updateArgNumber(format, i) + + // Do we have width? + if i < end && format[i] == '*' { + i++ + p.fmt.wid, p.fmt.widPresent = p.intFromArg() + + if !p.fmt.widPresent { + p.WriteString(badWidthString) + } + + // We have a negative width, so take its value and ensure + // that the minus flag is set + if p.fmt.wid < 0 { + p.fmt.wid = -p.fmt.wid + p.fmt.minus = true + p.fmt.zero = false // Do not pad with zeros to the right. + } + afterIndex = false + } else { + p.fmt.wid, p.fmt.widPresent, i = parsenum(format, i, end) + if afterIndex && p.fmt.widPresent { // "%[3]2d" + p.goodArgNum = false + } + } + + // Do we have precision? + if i+1 < end && format[i] == '.' { + i++ + if afterIndex { // "%[3].2d" + p.goodArgNum = false + } + i, afterIndex = p.updateArgNumber(format, i) + if i < end && format[i] == '*' { + i++ + p.fmt.prec, p.fmt.precPresent = p.intFromArg() + // Negative precision arguments don't make sense + if p.fmt.prec < 0 { + p.fmt.prec = 0 + p.fmt.precPresent = false + } + if !p.fmt.precPresent { + p.WriteString(badPrecString) + } + afterIndex = false + } else { + p.fmt.prec, p.fmt.precPresent, i = parsenum(format, i, end) + if !p.fmt.precPresent { + p.fmt.prec = 0 + p.fmt.precPresent = true + } + } + } + + if !afterIndex { + i, afterIndex = p.updateArgNumber(format, i) + } + + if i >= end { + p.WriteString(noVerbString) + break + } + + verb, w := utf8.DecodeRuneInString(format[i:]) + i += w + + switch { + case verb == '%': // Percent does not absorb operands and ignores f.wid and f.prec. + p.WriteByte('%') + case !p.goodArgNum: + p.badArgNum(verb) + case p.argNum >= len(p.args): // No argument left over to print for the current verb. + p.missingArg(verb) + case verb == 'v': + // Go syntax + p.fmt.sharpV = p.fmt.sharp + p.fmt.sharp = false + // Struct-field syntax + p.fmt.plusV = p.fmt.plus + p.fmt.plus = false + fallthrough + default: + p.printArg(p.args[p.argNum], verb) + p.argNum++ + } + } + + // Check for extra arguments, but only if there was at least one ordered + // argument. Note that this behavior is necessarily different from fmt: + // different variants of messages may opt to drop some or all of the + // arguments. + if !p.reordered && p.argNum < len(p.args) && p.argNum != 0 { + p.fmt.clearflags() + p.WriteString(extraString) + for i, arg := range p.args[p.argNum:] { + if i > 0 { + p.WriteString(commaSpaceString) + } + if arg == nil { + p.WriteString(nilAngleString) + } else { + p.WriteString(reflect.TypeOf(arg).String()) + p.WriteByte('=') + p.printArg(arg, 'v') + } + } + p.WriteByte(')') + } +} + +func (p *printer) doPrint(a []interface{}) { + prevString := false + for argNum, arg := range a { + isString := arg != nil && reflect.TypeOf(arg).Kind() == reflect.String + // Add a space between two non-string arguments. + if argNum > 0 && !isString && !prevString { + p.WriteByte(' ') + } + p.printArg(arg, 'v') + prevString = isString + } +} + +// doPrintln is like doPrint but always adds a space between arguments +// and a newline after the last argument. +func (p *printer) doPrintln(a []interface{}) { + for argNum, arg := range a { + if argNum > 0 { + p.WriteByte(' ') + } + p.printArg(arg, 'v') + } + p.WriteByte('\n') +} diff --git a/vendor/golang.org/x/text/secure/precis/enforce_test.go b/vendor/golang.org/x/text/secure/precis/enforce_test.go index 927d4ab6f..0cb5b606f 100644 --- a/vendor/golang.org/x/text/secure/precis/enforce_test.go +++ b/vendor/golang.org/x/text/secure/precis/enforce_test.go @@ -113,6 +113,8 @@ var enforceTestCases = []struct { {"α͵α", "α͵α", nil}, {"͵͵α", "͵͵α", nil}, // The numeric sign is itself Greek. {"α͵͵α", "α͵͵α", nil}, + {"α͵͵", "", errContext}, + {"α͵͵a", "", errContext}, }}, {"Context Rule 5+6", NewFreeform(), []testCase{ diff --git a/vendor/golang.org/x/text/secure/precis/profile.go b/vendor/golang.org/x/text/secure/precis/profile.go index 1d7898d47..bf1025338 100644 --- a/vendor/golang.org/x/text/secure/precis/profile.go +++ b/vendor/golang.org/x/text/secure/precis/profile.go @@ -322,33 +322,35 @@ func (c *checker) span(src []byte, atEOF bool) (n int, err error) { } return n, errDisallowedRune } + doLookAhead := false if property(e) < c.p.class.validFrom { if d.rule == nil { return n, errDisallowedRune } - doLookAhead, err := d.rule(c.beforeBits) + doLookAhead, err = d.rule(c.beforeBits) if err != nil { return n, err } - if doLookAhead { - c.beforeBits &= d.keep - c.beforeBits |= d.set - // We may still have a lookahead rule which we will require to - // complete (by checking termBits == 0) before setting the new - // bits. - if c.termBits != 0 && (!c.checkLookahead() || c.termBits == 0) { - return n, err - } - c.termBits = d.term - c.acceptBits = d.accept - n += sz - continue - } } c.beforeBits &= d.keep c.beforeBits |= d.set - if c.termBits != 0 && !c.checkLookahead() { - return n, errContext + if c.termBits != 0 { + // We are currently in an unterminated lookahead. + if c.beforeBits&c.termBits != 0 { + c.termBits = 0 + c.acceptBits = 0 + } else if c.beforeBits&c.acceptBits == 0 { + // Invalid continuation of the unterminated lookahead sequence. + return n, errContext + } + } + if doLookAhead { + if c.termBits != 0 { + // A previous lookahead run has not been terminated yet. + return n, errContext + } + c.termBits = d.term + c.acceptBits = d.accept } n += sz } @@ -358,18 +360,6 @@ func (c *checker) span(src []byte, atEOF bool) (n int, err error) { return n, err } -func (c *checker) checkLookahead() bool { - switch { - case c.beforeBits&c.termBits != 0: - c.termBits = 0 - c.acceptBits = 0 - case c.beforeBits&c.acceptBits != 0: - default: - return false - } - return true -} - // TODO: we may get rid of this transform if transform.Chain understands // something like a Spanner interface. func (c checker) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) { -- cgit v1.2.3-1-g7c22