mirror of
https://github.com/fnproject/fn.git
synced 2022-10-28 21:29:17 +03:00
Fnlb/k8s grouper (#563)
* WIP: add k8s grouper - This shares a great deal of behaviour with allGrouper. Once it's tested, refactor that to share as much as possible - Glide hell. Checked in the yaml and lock files but a glide i -v will be required to bring vendor/ up-to-date. Will address once this is ready. * Update README. Make the watch tracking work. (To follow: add the junk that was pulled in via the glide update.) * Vendor updates. * go fmt * Use the allGrouper with a k8s-backed DBStore instead. This is much tidier :-) * Fix up go vet
This commit is contained in:
46
vendor/golang.org/x/text/feature/plural/example_test.go
generated
vendored
Normal file
46
vendor/golang.org/x/text/feature/plural/example_test.go
generated
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
// 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 plural_test
|
||||
|
||||
import (
|
||||
"golang.org/x/text/feature/plural"
|
||||
"golang.org/x/text/language"
|
||||
"golang.org/x/text/message"
|
||||
)
|
||||
|
||||
func ExampleSelect() {
|
||||
// Manually set some translations. This is typically done programmatically.
|
||||
message.Set(language.English, "%d files remaining",
|
||||
plural.Selectf(1, "%d",
|
||||
"=0", "done!",
|
||||
plural.One, "one file remaining",
|
||||
plural.Other, "%[1]d files remaining",
|
||||
))
|
||||
message.Set(language.Dutch, "%d files remaining",
|
||||
plural.Selectf(1, "%d",
|
||||
"=0", "klaar!",
|
||||
// One can also use a string instead of a Kind
|
||||
"one", "nog één bestand te gaan",
|
||||
"other", "nog %[1]d bestanden te gaan",
|
||||
))
|
||||
|
||||
p := message.NewPrinter(language.English)
|
||||
p.Printf("%d files remaining", 5)
|
||||
p.Println()
|
||||
p.Printf("%d files remaining", 1)
|
||||
p.Println()
|
||||
|
||||
p = message.NewPrinter(language.Dutch)
|
||||
p.Printf("%d files remaining", 1)
|
||||
p.Println()
|
||||
p.Printf("%d files remaining", 0)
|
||||
p.Println()
|
||||
|
||||
// Output:
|
||||
// 5 files remaining
|
||||
// one file remaining
|
||||
// nog één bestand te gaan
|
||||
// klaar!
|
||||
}
|
||||
244
vendor/golang.org/x/text/feature/plural/message.go
generated
vendored
Executable file
244
vendor/golang.org/x/text/feature/plural/message.go
generated
vendored
Executable file
@@ -0,0 +1,244 @@
|
||||
// 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 plural
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"reflect"
|
||||
"strconv"
|
||||
|
||||
"golang.org/x/text/internal/catmsg"
|
||||
"golang.org/x/text/internal/number"
|
||||
"golang.org/x/text/language"
|
||||
"golang.org/x/text/message/catalog"
|
||||
)
|
||||
|
||||
// TODO: consider deleting this interface. Maybe VisibleDigits is always
|
||||
// sufficient and practical.
|
||||
|
||||
// Interface is used for types that can determine their own plural form.
|
||||
type Interface interface {
|
||||
// PluralForm reports the plural form for the given language of the
|
||||
// underlying value. It also returns the integer value. If the integer value
|
||||
// is larger than fits in n, PluralForm may return a value modulo
|
||||
// 10,000,000.
|
||||
PluralForm(t language.Tag, scale int) (f Form, n int)
|
||||
}
|
||||
|
||||
// Selectf returns the first case for which its selector is a match for the
|
||||
// arg-th substitution argument to a formatting call, formatting it as indicated
|
||||
// by format.
|
||||
//
|
||||
// The cases argument are pairs of selectors and messages. Selectors are of type
|
||||
// string or Form. Messages are of type string or catalog.Message. A selector
|
||||
// matches an argument if:
|
||||
// - it is "other" or Other
|
||||
// - it matches the plural form of the argument: "zero", "one", "two", "few",
|
||||
// or "many", or the equivalent Form
|
||||
// - it is of the form "=x" where x is an integer that matches the value of
|
||||
// the argument.
|
||||
// - it is of the form "<x" where x is an integer that is larger than the
|
||||
// argument.
|
||||
//
|
||||
// The format argument determines the formatting parameters for which to
|
||||
// determine the plural form. This is especially relevant for non-integer
|
||||
// values.
|
||||
//
|
||||
// The format string may be "", in which case a best-effort attempt is made to
|
||||
// find a reasonable representation on which to base the plural form. Examples
|
||||
// of format strings are:
|
||||
// - %.2f decimal with scale 2
|
||||
// - %.2e scientific notation with precision 3 (scale + 1)
|
||||
// - %d integer
|
||||
func Selectf(arg int, format string, cases ...interface{}) catalog.Message {
|
||||
var p parser
|
||||
// Intercept the formatting parameters of format by doing a dummy print.
|
||||
fmt.Fprintf(ioutil.Discard, format, &p)
|
||||
m := &message{arg, kindDefault, 0, cases}
|
||||
switch p.verb {
|
||||
case 'g':
|
||||
m.kind = kindPrecision
|
||||
m.scale = p.scale
|
||||
case 'f':
|
||||
m.kind = kindScale
|
||||
m.scale = p.scale
|
||||
case 'e':
|
||||
m.kind = kindScientific
|
||||
m.scale = p.scale
|
||||
case 'd':
|
||||
m.kind = kindScale
|
||||
m.scale = 0
|
||||
default:
|
||||
// TODO: do we need to handle errors?
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
type parser struct {
|
||||
verb rune
|
||||
scale int
|
||||
}
|
||||
|
||||
func (p *parser) Format(s fmt.State, verb rune) {
|
||||
p.verb = verb
|
||||
p.scale = -1
|
||||
if prec, ok := s.Precision(); ok {
|
||||
p.scale = prec
|
||||
}
|
||||
}
|
||||
|
||||
type message struct {
|
||||
arg int
|
||||
kind int
|
||||
scale int
|
||||
cases []interface{}
|
||||
}
|
||||
|
||||
const (
|
||||
// Start with non-ASCII to allow skipping values.
|
||||
kindDefault = 0x80 + iota
|
||||
kindScale // verb f, number of fraction digits follows
|
||||
kindScientific // verb e, number of fraction digits follows
|
||||
kindPrecision // verb g, number of significant digits follows
|
||||
)
|
||||
|
||||
var handle = catmsg.Register("golang.org/x/text/feature/plural:plural", execute)
|
||||
|
||||
func (m *message) Compile(e *catmsg.Encoder) error {
|
||||
e.EncodeMessageType(handle)
|
||||
|
||||
e.EncodeUint(uint64(m.arg))
|
||||
|
||||
e.EncodeUint(uint64(m.kind))
|
||||
if m.kind > kindDefault {
|
||||
e.EncodeUint(uint64(m.scale))
|
||||
}
|
||||
|
||||
forms := validForms(cardinal, e.Language())
|
||||
|
||||
for i := 0; i < len(m.cases); {
|
||||
if err := compileSelector(e, forms, m.cases[i]); err != nil {
|
||||
return err
|
||||
}
|
||||
if i++; i >= len(m.cases) {
|
||||
return fmt.Errorf("plural: no message defined for selector %v", m.cases[i-1])
|
||||
}
|
||||
var msg catalog.Message
|
||||
switch x := m.cases[i].(type) {
|
||||
case string:
|
||||
msg = catalog.String(x)
|
||||
case catalog.Message:
|
||||
msg = x
|
||||
default:
|
||||
return fmt.Errorf("plural: message of type %T; must be string or catalog.Message", x)
|
||||
}
|
||||
if err := e.EncodeMessage(msg); err != nil {
|
||||
return err
|
||||
}
|
||||
i++
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func compileSelector(e *catmsg.Encoder, valid []Form, selector interface{}) error {
|
||||
form := Other
|
||||
switch x := selector.(type) {
|
||||
case string:
|
||||
if x == "" {
|
||||
return fmt.Errorf("plural: empty selector")
|
||||
}
|
||||
if c := x[0]; c == '=' || c == '<' {
|
||||
val, err := strconv.ParseUint(x[1:], 10, 16)
|
||||
if err != nil {
|
||||
return fmt.Errorf("plural: invalid number in selector %q: %v", selector, err)
|
||||
}
|
||||
e.EncodeUint(uint64(c))
|
||||
e.EncodeUint(val)
|
||||
return nil
|
||||
}
|
||||
var ok bool
|
||||
form, ok = countMap[x]
|
||||
if !ok {
|
||||
return fmt.Errorf("plural: invalid plural form %q", selector)
|
||||
}
|
||||
case Form:
|
||||
form = x
|
||||
default:
|
||||
return fmt.Errorf("plural: selector of type %T; want string or Form", selector)
|
||||
}
|
||||
|
||||
ok := false
|
||||
for _, f := range valid {
|
||||
if f == form {
|
||||
ok = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !ok {
|
||||
return fmt.Errorf("plural: form %q not supported for language %q", selector, e.Language())
|
||||
}
|
||||
e.EncodeUint(uint64(form))
|
||||
return nil
|
||||
}
|
||||
|
||||
func execute(d *catmsg.Decoder) bool {
|
||||
lang := d.Language()
|
||||
argN := int(d.DecodeUint())
|
||||
kind := int(d.DecodeUint())
|
||||
scale := -1 // default
|
||||
if kind > kindDefault {
|
||||
scale = int(d.DecodeUint())
|
||||
}
|
||||
form := Other
|
||||
n := -1
|
||||
if arg := d.Arg(argN); arg == nil {
|
||||
// Default to Other.
|
||||
} else if x, ok := arg.(number.VisibleDigits); ok {
|
||||
d := x.Digits(nil, lang, scale)
|
||||
form, n = cardinal.matchDisplayDigits(lang, &d)
|
||||
} else if x, ok := arg.(Interface); ok {
|
||||
// This covers lists and formatters from the number package.
|
||||
form, n = x.PluralForm(lang, scale)
|
||||
} else {
|
||||
var f number.Formatter
|
||||
switch kind {
|
||||
case kindScale:
|
||||
f.InitDecimal(lang)
|
||||
f.SetScale(scale)
|
||||
case kindScientific:
|
||||
f.InitScientific(lang)
|
||||
f.SetScale(scale)
|
||||
case kindPrecision:
|
||||
f.InitDecimal(lang)
|
||||
f.SetPrecision(scale)
|
||||
case kindDefault:
|
||||
// sensible default
|
||||
f.InitDecimal(lang)
|
||||
if k := reflect.TypeOf(arg).Kind(); reflect.Int <= k && k <= reflect.Uintptr {
|
||||
f.SetScale(0)
|
||||
} else {
|
||||
f.SetScale(2)
|
||||
}
|
||||
}
|
||||
var dec number.Decimal // TODO: buffer in Printer
|
||||
dec.Convert(f.RoundingContext, arg)
|
||||
v := number.FormatDigits(&dec, f.RoundingContext)
|
||||
if !v.NaN && !v.Inf {
|
||||
form, n = cardinal.matchDisplayDigits(d.Language(), &v)
|
||||
}
|
||||
}
|
||||
for !d.Done() {
|
||||
f := d.DecodeUint()
|
||||
if (f == '=' && n == int(d.DecodeUint())) ||
|
||||
(f == '<' && 0 <= n && n < int(d.DecodeUint())) ||
|
||||
form == Form(f) ||
|
||||
Other == Form(f) {
|
||||
return d.ExecuteMessage()
|
||||
}
|
||||
d.SkipMessage()
|
||||
}
|
||||
return false
|
||||
}
|
||||
197
vendor/golang.org/x/text/feature/plural/message_test.go
generated
vendored
Normal file
197
vendor/golang.org/x/text/feature/plural/message_test.go
generated
vendored
Normal file
@@ -0,0 +1,197 @@
|
||||
// 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 plural
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"golang.org/x/text/internal/catmsg"
|
||||
"golang.org/x/text/language"
|
||||
"golang.org/x/text/message/catalog"
|
||||
)
|
||||
|
||||
func TestSelect(t *testing.T) {
|
||||
lang := language.English
|
||||
type test struct {
|
||||
arg interface{}
|
||||
result string
|
||||
err string
|
||||
}
|
||||
testCases := []struct {
|
||||
desc string
|
||||
msg catalog.Message
|
||||
err string
|
||||
tests []test
|
||||
}{{
|
||||
desc: "basic",
|
||||
msg: Selectf(1, "%d", "one", "foo", "other", "bar"),
|
||||
tests: []test{
|
||||
{arg: 0, result: "bar"},
|
||||
{arg: 1, result: "foo"},
|
||||
{arg: 2, result: "bar"},
|
||||
{arg: opposite(1), result: "bar"},
|
||||
{arg: opposite(2), result: "foo"},
|
||||
{arg: "unknown", result: "bar"}, // other
|
||||
},
|
||||
}, {
|
||||
desc: "comparisons",
|
||||
msg: Selectf(1, "%d",
|
||||
"=0", "zero",
|
||||
"=1", "one",
|
||||
"one", "cannot match", // never matches
|
||||
"<5", "<5", // never matches
|
||||
"=5", "=5",
|
||||
Other, "other"),
|
||||
tests: []test{
|
||||
{arg: 0, result: "zero"},
|
||||
{arg: 1, result: "one"},
|
||||
{arg: 2, result: "<5"},
|
||||
{arg: 4, result: "<5"},
|
||||
{arg: 5, result: "=5"},
|
||||
{arg: 6, result: "other"},
|
||||
{arg: "unknown", result: "other"},
|
||||
},
|
||||
}, {
|
||||
desc: "fractions",
|
||||
msg: Selectf(1, "%.2f", "one", "foo", "other", "bar"),
|
||||
tests: []test{
|
||||
// fractions are always plural in english
|
||||
{arg: 0, result: "bar"},
|
||||
{arg: 1, result: "bar"},
|
||||
},
|
||||
}, {
|
||||
desc: "decimal without fractions",
|
||||
msg: Selectf(1, "%.0f", "one", "foo", "other", "bar"),
|
||||
tests: []test{
|
||||
// fractions are always plural in english
|
||||
{arg: 0, result: "bar"},
|
||||
{arg: 1, result: "foo"},
|
||||
},
|
||||
}, {
|
||||
desc: "scientific",
|
||||
msg: Selectf(1, "%.0e", "one", "foo", "other", "bar"),
|
||||
tests: []test{
|
||||
{arg: 0, result: "bar"},
|
||||
{arg: 1, result: "foo"},
|
||||
},
|
||||
}, {
|
||||
desc: "variable",
|
||||
msg: Selectf(1, "%.1g", "one", "foo", "other", "bar"),
|
||||
tests: []test{
|
||||
// fractions are always plural in english
|
||||
{arg: 0, result: "bar"},
|
||||
{arg: 1, result: "foo"},
|
||||
{arg: 2, result: "bar"},
|
||||
},
|
||||
}, {
|
||||
desc: "default",
|
||||
msg: Selectf(1, "", "one", "foo", "other", "bar"),
|
||||
tests: []test{
|
||||
{arg: 0, result: "bar"},
|
||||
{arg: 1, result: "foo"},
|
||||
{arg: 2, result: "bar"},
|
||||
{arg: 1.0, result: "bar"},
|
||||
},
|
||||
}, {
|
||||
desc: "nested",
|
||||
msg: Selectf(1, "", "other", Selectf(2, "", "one", "foo", "other", "bar")),
|
||||
tests: []test{
|
||||
{arg: 0, result: "bar"},
|
||||
{arg: 1, result: "foo"},
|
||||
{arg: 2, result: "bar"},
|
||||
},
|
||||
}, {
|
||||
desc: "arg unavailable",
|
||||
msg: Selectf(100, "%.2f", "one", "foo", "other", "bar"),
|
||||
tests: []test{{arg: 1, result: "bar"}},
|
||||
}, {
|
||||
desc: "no match",
|
||||
msg: Selectf(1, "%.2f", "one", "foo"),
|
||||
tests: []test{{arg: 0, result: "bar", err: catmsg.ErrNoMatch.Error()}},
|
||||
}, {
|
||||
desc: "error invalid form",
|
||||
err: `invalid plural form "excessive"`,
|
||||
msg: Selectf(1, "%d", "excessive", "foo"),
|
||||
}, {
|
||||
desc: "error form not used by language",
|
||||
err: `form "many" not supported for language "en"`,
|
||||
msg: Selectf(1, "%d", "many", "foo"),
|
||||
}, {
|
||||
desc: "error invalid selector",
|
||||
err: `selector of type int; want string or Form`,
|
||||
msg: Selectf(1, "%d", 1, "foo"),
|
||||
}, {
|
||||
desc: "error missing message",
|
||||
err: `no message defined for selector one`,
|
||||
msg: Selectf(1, "%d", "one"),
|
||||
}, {
|
||||
desc: "error invalid number",
|
||||
err: `invalid number in selector "<1.00"`,
|
||||
msg: Selectf(1, "%d", "<1.00"),
|
||||
}, {
|
||||
desc: "error empty selector",
|
||||
err: `empty selector`,
|
||||
msg: Selectf(1, "%d", "", "foo"),
|
||||
}, {
|
||||
desc: "error invalid message",
|
||||
err: `message of type int; must be string or catalog.Message`,
|
||||
msg: Selectf(1, "%d", "one", 3),
|
||||
}, {
|
||||
desc: "nested error",
|
||||
err: `empty selector`,
|
||||
msg: Selectf(1, "", "other", Selectf(2, "", "")),
|
||||
}}
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
data, err := catmsg.Compile(lang, nil, tc.msg)
|
||||
chkError(t, err, tc.err)
|
||||
for _, tx := range tc.tests {
|
||||
t.Run(fmt.Sprint(tx.arg), func(t *testing.T) {
|
||||
r := renderer{arg: tx.arg}
|
||||
d := catmsg.NewDecoder(lang, &r, nil)
|
||||
err := d.Execute(data)
|
||||
chkError(t, err, tx.err)
|
||||
if r.result != tx.result {
|
||||
t.Errorf("got %q; want %q", r.result, tx.result)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func chkError(t *testing.T, got error, want string) {
|
||||
if (got == nil && want != "") ||
|
||||
(got != nil && (want == "" || !strings.Contains(got.Error(), want))) {
|
||||
t.Fatalf("got %v; want %v", got, want)
|
||||
}
|
||||
if got != nil {
|
||||
t.SkipNow()
|
||||
}
|
||||
}
|
||||
|
||||
type renderer struct {
|
||||
arg interface{}
|
||||
result string
|
||||
}
|
||||
|
||||
func (r *renderer) Render(s string) { r.result += s }
|
||||
func (r *renderer) Arg(i int) interface{} {
|
||||
if i > 10 { // Allow testing "arg unavailable" path
|
||||
return nil
|
||||
}
|
||||
return r.arg
|
||||
}
|
||||
|
||||
type opposite int
|
||||
|
||||
func (o opposite) PluralForm(lang language.Tag, scale int) (Form, int) {
|
||||
if o == 1 {
|
||||
return Other, 1
|
||||
}
|
||||
return One, int(o)
|
||||
}
|
||||
34
vendor/golang.org/x/text/feature/plural/plural.go
generated
vendored
34
vendor/golang.org/x/text/feature/plural/plural.go
generated
vendored
@@ -13,6 +13,7 @@
|
||||
package plural
|
||||
|
||||
import (
|
||||
"golang.org/x/text/internal/number"
|
||||
"golang.org/x/text/language"
|
||||
)
|
||||
|
||||
@@ -109,21 +110,25 @@ func getIntApprox(digits []byte, start, end, nMod, big int) (n int) {
|
||||
// 123 []byte{1, 2, 3} 3 0
|
||||
// 123.4 []byte{1, 2, 3, 4} 3 1
|
||||
// 123.40 []byte{1, 2, 3, 4} 3 2
|
||||
// 100000 []byte{1} 6......0
|
||||
// 100000.00 []byte{1} 6......3
|
||||
// 100000 []byte{1} 6 0
|
||||
// 100000.00 []byte{1} 6 3
|
||||
func (p *Rules) MatchDigits(t language.Tag, digits []byte, exp, scale int) Form {
|
||||
index, _ := language.CompactIndex(t)
|
||||
endN := len(digits) + exp
|
||||
|
||||
// Differentiate up to including mod 1000000 for the integer part.
|
||||
n := getIntApprox(digits, 0, endN, 6, 1000000)
|
||||
n := getIntApprox(digits, 0, exp, 6, 1000000)
|
||||
|
||||
// Differentiate up to including mod 100 for the fractional part.
|
||||
f := getIntApprox(digits, endN, endN+scale, 2, 100)
|
||||
f := getIntApprox(digits, exp, exp+scale, 2, 100)
|
||||
|
||||
return matchPlural(p, index, n, f, scale)
|
||||
}
|
||||
|
||||
func (p *Rules) matchDisplayDigits(t language.Tag, d *number.Digits) (Form, int) {
|
||||
n := getIntApprox(d.Digits, 0, int(d.Exp), 6, 1000000)
|
||||
return p.MatchDigits(t, d.Digits, int(d.Exp), d.NumFracDigits()), n
|
||||
}
|
||||
|
||||
func validForms(p *Rules, t language.Tag) (forms []Form) {
|
||||
index, _ := language.CompactIndex(t)
|
||||
offset := p.langToIndex[index]
|
||||
@@ -145,6 +150,25 @@ func (p *Rules) matchComponents(t language.Tag, n, f, scale int) Form {
|
||||
return matchPlural(p, index, n, f, scale)
|
||||
}
|
||||
|
||||
// MatchPlural returns the plural form for the given language and plural
|
||||
// operands (as defined in
|
||||
// http://unicode.org/reports/tr35/tr35-numbers.html#Language_Plural_Rules):
|
||||
// where
|
||||
// n absolute value of the source number (integer and decimals)
|
||||
// input
|
||||
// i integer digits of n.
|
||||
// v number of visible fraction digits in n, with trailing zeros.
|
||||
// w number of visible fraction digits in n, without trailing zeros.
|
||||
// f visible fractional digits in n, with trailing zeros (f = t * 10^(v-w))
|
||||
// t visible fractional digits in n, without trailing zeros.
|
||||
//
|
||||
// If any of the operand values is too large to fit in an int, it is okay to
|
||||
// pass the value modulo 10,000,000.
|
||||
func (p *Rules) MatchPlural(lang language.Tag, i, v, w, f, t int) Form {
|
||||
index, _ := language.CompactIndex(lang)
|
||||
return matchPlural(p, index, i, f, v)
|
||||
}
|
||||
|
||||
func matchPlural(p *Rules, index int, n, f, v int) Form {
|
||||
nMask := p.inclusionMasks[n%maxMod]
|
||||
// Compute the fMask inline in the rules below, as it is relatively rare.
|
||||
|
||||
17
vendor/golang.org/x/text/feature/plural/plural_test.go
generated
vendored
17
vendor/golang.org/x/text/feature/plural/plural_test.go
generated
vendored
@@ -28,6 +28,8 @@ func TestGetIntApprox(t *testing.T) {
|
||||
{"123", 0, 2, 2, 12},
|
||||
{"123", 3, 4, 2, 0},
|
||||
{"12345", 3, 4, 2, 4},
|
||||
{"40", 0, 1, 2, 4},
|
||||
{"1", 0, 7, 2, big},
|
||||
|
||||
{"123", 0, 5, 2, big},
|
||||
{"123", 0, 5, 3, big},
|
||||
@@ -114,7 +116,7 @@ func testPlurals(t *testing.T, p *Rules, testCases []pluralTest) {
|
||||
for i := range digits {
|
||||
digits[i] -= '0'
|
||||
}
|
||||
if f := p.MatchDigits(tag, digits, 0, 0); f != Form(tc.form) {
|
||||
if f := p.MatchDigits(tag, digits, len(digits), 0); f != Form(tc.form) {
|
||||
t.Errorf("MatchDigits: got %v; want %v", f, Form(tc.form))
|
||||
}
|
||||
})
|
||||
@@ -139,14 +141,25 @@ func testPlurals(t *testing.T, p *Rules, testCases []pluralTest) {
|
||||
num := fmt.Sprintf("%[1]d.%0[3]*[2]d", n/m, n%m, scale)
|
||||
name := fmt.Sprintf("%s:dec(%s)", loc, num)
|
||||
t.Run(name, func(t *testing.T) {
|
||||
ff := n % m
|
||||
tt := ff
|
||||
w := scale
|
||||
for tt > 0 && tt%10 == 0 {
|
||||
w--
|
||||
tt /= 10
|
||||
}
|
||||
if f := p.MatchPlural(tag, n/m, scale, w, ff, tt); f != Form(tc.form) {
|
||||
t.Errorf("MatchPlural: got %v; want %v", f, Form(tc.form))
|
||||
}
|
||||
if f := p.matchComponents(tag, n/m, n%m, scale); f != Form(tc.form) {
|
||||
t.Errorf("matchComponents: got %v; want %v", f, Form(tc.form))
|
||||
}
|
||||
exp := strings.IndexByte(num, '.')
|
||||
digits := []byte(strings.Replace(num, ".", "", 1))
|
||||
for i := range digits {
|
||||
digits[i] -= '0'
|
||||
}
|
||||
if f := p.MatchDigits(tag, digits, -scale, scale); f != Form(tc.form) {
|
||||
if f := p.MatchDigits(tag, digits, exp, scale); f != Form(tc.form) {
|
||||
t.Errorf("MatchDigits: got %v; want %v", f, Form(tc.form))
|
||||
}
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user