Checking in vendor folder for ease of using go get.
This commit is contained in:
parent
7a1251853b
commit
cdb4b5a1d0
3554 changed files with 1270116 additions and 0 deletions
376
vendor/golang.org/x/text/internal/catmsg/catmsg.go
generated
vendored
Normal file
376
vendor/golang.org/x/text/internal/catmsg/catmsg.go
generated
vendored
Normal file
|
@ -0,0 +1,376 @@
|
|||
// 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 catmsg contains support types for package x/text/message/catalog.
|
||||
//
|
||||
// This package contains the low-level implementations of Message used by the
|
||||
// catalog package and provides primitives for other packages to implement their
|
||||
// own. For instance, the plural package provides functionality for selecting
|
||||
// translation strings based on the plural category of substitution arguments.
|
||||
//
|
||||
//
|
||||
// Encoding and Decoding
|
||||
//
|
||||
// Catalogs store Messages encoded as a single string. Compiling a message into
|
||||
// a string both results in compacter representation and speeds up evaluation.
|
||||
//
|
||||
// A Message must implement a Compile method to convert its arbitrary
|
||||
// representation to a string. The Compile method takes an Encoder which
|
||||
// facilitates serializing the message. Encoders also provide more context of
|
||||
// the messages's creation (such as for which language the message is intended),
|
||||
// which may not be known at the time of the creation of the message.
|
||||
//
|
||||
// Each message type must also have an accompanying decoder registered to decode
|
||||
// the message. This decoder takes a Decoder argument which provides the
|
||||
// counterparts for the decoding.
|
||||
//
|
||||
//
|
||||
// Renderers
|
||||
//
|
||||
// A Decoder must be initialized with a Renderer implementation. These
|
||||
// implementations must be provided by packages that use Catalogs, typically
|
||||
// formatting packages such as x/text/message. A typical user will not need to
|
||||
// worry about this type; it is only relevant to packages that do string
|
||||
// formatting and want to use the catalog package to handle localized strings.
|
||||
//
|
||||
// A package that uses catalogs for selecting strings receives selection results
|
||||
// as sequence of substrings passed to the Renderer. The following snippet shows
|
||||
// how to express the above example using the message package.
|
||||
//
|
||||
// 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.Printf("You are %d minute(s) late.", 5) // always 5 minutes late.
|
||||
//
|
||||
// To evaluate the Printf, package message wraps the arguments in a Renderer
|
||||
// that is passed to the catalog for message decoding. The call sequence that
|
||||
// results from evaluating the above message, assuming the person is rather
|
||||
// tardy, is:
|
||||
//
|
||||
// Render("You are %[1]d ")
|
||||
// Arg(1)
|
||||
// Render("minutes")
|
||||
// Render(" late.")
|
||||
//
|
||||
// The calls to Arg is caused by the plural.Select execution, which evaluates
|
||||
// the argument to determine whether the singular or plural message form should
|
||||
// be selected. The calls to Render reports the partial results to the message
|
||||
// package for further evaluation.
|
||||
package catmsg
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"golang.org/x/text/language"
|
||||
)
|
||||
|
||||
// A Handle refers to a registered message type.
|
||||
type Handle int
|
||||
|
||||
// A Handler decodes and evaluates data compiled by a Message and sends the
|
||||
// result to the Decoder. The output may depend on the value of the substitution
|
||||
// arguments, accessible by the Decoder's Arg method. The Handler returns false
|
||||
// if there is no translation for the given substitution arguments.
|
||||
type Handler func(d *Decoder) bool
|
||||
|
||||
// Register records the existence of a message type and returns a Handle that
|
||||
// can be used in the Encoder's EncodeMessageType method to create such
|
||||
// messages. The prefix of the name should be the package path followed by
|
||||
// an optional disambiguating string.
|
||||
// Register will panic if a handle for the same name was already registered.
|
||||
func Register(name string, handler Handler) Handle {
|
||||
mutex.Lock()
|
||||
defer mutex.Unlock()
|
||||
|
||||
if _, ok := names[name]; ok {
|
||||
panic(fmt.Errorf("catmsg: handler for %q already exists", name))
|
||||
}
|
||||
h := Handle(len(handlers))
|
||||
names[name] = h
|
||||
handlers = append(handlers, handler)
|
||||
return h
|
||||
}
|
||||
|
||||
// These handlers require fixed positions in the handlers slice.
|
||||
const (
|
||||
msgVars Handle = iota
|
||||
msgFirst
|
||||
msgRaw
|
||||
msgString
|
||||
numFixed
|
||||
)
|
||||
|
||||
const prefix = "golang.org/x/text/internal/catmsg."
|
||||
|
||||
var (
|
||||
mutex sync.Mutex
|
||||
names = map[string]Handle{
|
||||
prefix + "Vars": msgVars,
|
||||
prefix + "First": msgFirst,
|
||||
prefix + "Raw": msgRaw,
|
||||
prefix + "String": msgString,
|
||||
}
|
||||
handlers = make([]Handler, numFixed)
|
||||
)
|
||||
|
||||
func init() {
|
||||
// This handler is a message type wrapper that initializes a decoder
|
||||
// with a variable block. This message type, if present, is always at the
|
||||
// start of an encoded message.
|
||||
handlers[msgVars] = func(d *Decoder) bool {
|
||||
blockSize := int(d.DecodeUint())
|
||||
d.vars = d.data[:blockSize]
|
||||
d.data = d.data[blockSize:]
|
||||
return d.executeMessage()
|
||||
}
|
||||
|
||||
// First takes the first message in a sequence that results in a match for
|
||||
// the given substitution arguments.
|
||||
handlers[msgFirst] = func(d *Decoder) bool {
|
||||
for !d.Done() {
|
||||
if d.ExecuteMessage() {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
handlers[msgRaw] = func(d *Decoder) bool {
|
||||
d.Render(d.data)
|
||||
return true
|
||||
}
|
||||
|
||||
// A String message alternates between a string constant and a variable
|
||||
// substitution.
|
||||
handlers[msgString] = func(d *Decoder) bool {
|
||||
for !d.Done() {
|
||||
if str := d.DecodeString(); str != "" {
|
||||
d.Render(str)
|
||||
}
|
||||
if d.Done() {
|
||||
break
|
||||
}
|
||||
d.ExecuteSubstitution()
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
// ErrIncomplete indicates a compiled message does not define translations
|
||||
// for all possible argument values. If this message is returned, evaluating
|
||||
// a message may result in the ErrNoMatch error.
|
||||
ErrIncomplete = errors.New("catmsg: incomplete message; may not give result for all inputs")
|
||||
|
||||
// ErrNoMatch indicates no translation message matched the given input
|
||||
// parameters when evaluating a message.
|
||||
ErrNoMatch = errors.New("catmsg: no translation for inputs")
|
||||
)
|
||||
|
||||
// A Message holds a collection of translations for the same phrase that may
|
||||
// vary based on the values of substitution arguments.
|
||||
type Message interface {
|
||||
// Compile encodes the format string(s) of the message as a string for later
|
||||
// evaluation.
|
||||
//
|
||||
// The first call Compile makes on the encoder must be EncodeMessageType.
|
||||
// The handle passed to this call may either be a handle returned by
|
||||
// Register to encode a single custom message, or HandleFirst followed by
|
||||
// a sequence of calls to EncodeMessage.
|
||||
//
|
||||
// Compile must return ErrIncomplete if it is possible for evaluation to
|
||||
// not match any translation for a given set of formatting parameters.
|
||||
// For example, selecting a translation based on plural form may not yield
|
||||
// a match if the form "Other" is not one of the selectors.
|
||||
//
|
||||
// Compile may return any other application-specific error. For backwards
|
||||
// compatibility with package like fmt, which often do not do sanity
|
||||
// checking of format strings ahead of time, Compile should still make an
|
||||
// effort to have some sensible fallback in case of an error.
|
||||
Compile(e *Encoder) error
|
||||
}
|
||||
|
||||
// Compile converts a Message to a data string that can be stored in a Catalog.
|
||||
// The resulting string can subsequently be decoded by passing to the Execute
|
||||
// method of a Decoder.
|
||||
func Compile(tag language.Tag, macros Dictionary, m Message) (data string, err error) {
|
||||
// TODO: pass macros so they can be used for validation.
|
||||
v := &Encoder{inBody: true} // encoder for variables
|
||||
v.root = v
|
||||
e := &Encoder{root: v, parent: v, tag: tag} // encoder for messages
|
||||
err = m.Compile(e)
|
||||
// This package serves te message package, which in turn is meant to be a
|
||||
// drop-in replacement for fmt. With the fmt package, format strings are
|
||||
// evaluated lazily and errors are handled by substituting strings in the
|
||||
// result, rather then returning an error. Dealing with multiple languages
|
||||
// makes it more important to check errors ahead of time. We chose to be
|
||||
// consistent and compatible and allow graceful degradation in case of
|
||||
// errors.
|
||||
buf := e.buf[stripPrefix(e.buf):]
|
||||
if len(v.buf) > 0 {
|
||||
// Prepend variable block.
|
||||
b := make([]byte, 1+maxVarintBytes+len(v.buf)+len(buf))
|
||||
b[0] = byte(msgVars)
|
||||
b = b[:1+encodeUint(b[1:], uint64(len(v.buf)))]
|
||||
b = append(b, v.buf...)
|
||||
b = append(b, buf...)
|
||||
buf = b
|
||||
}
|
||||
if err == nil {
|
||||
err = v.err
|
||||
}
|
||||
return string(buf), err
|
||||
}
|
||||
|
||||
// FirstOf is a message type that prints the first message in the sequence that
|
||||
// resolves to a match for the given substitution arguments.
|
||||
type FirstOf []Message
|
||||
|
||||
// Compile implements Message.
|
||||
func (s FirstOf) Compile(e *Encoder) error {
|
||||
e.EncodeMessageType(msgFirst)
|
||||
err := 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
|
||||
}
|
||||
|
||||
// Var defines a message that can be substituted for a placeholder of the same
|
||||
// name. If an expression does not result in a string after evaluation, Name is
|
||||
// used as the substitution. For example:
|
||||
// Var{
|
||||
// Name: "minutes",
|
||||
// Message: plural.Select(1, "one", "minute"),
|
||||
// }
|
||||
// will resolve to minute for singular and minutes for plural forms.
|
||||
type Var struct {
|
||||
Name string
|
||||
Message Message
|
||||
}
|
||||
|
||||
var errIsVar = errors.New("catmsg: variable used as message")
|
||||
|
||||
// Compile implements Message.
|
||||
//
|
||||
// Note that this method merely registers a variable; it does not create an
|
||||
// encoded message.
|
||||
func (v *Var) Compile(e *Encoder) error {
|
||||
if err := e.addVar(v.Name, v.Message); err != nil {
|
||||
return err
|
||||
}
|
||||
// Using a Var by itself is an error. If it is in a sequence followed by
|
||||
// other messages referring to it, this error will be ignored.
|
||||
return errIsVar
|
||||
}
|
||||
|
||||
// Raw is a message consisting of a single format string that is passed as is
|
||||
// to the Renderer.
|
||||
//
|
||||
// Note that a Renderer may still do its own variable substitution.
|
||||
type Raw string
|
||||
|
||||
// Compile implements Message.
|
||||
func (r Raw) Compile(e *Encoder) (err error) {
|
||||
e.EncodeMessageType(msgRaw)
|
||||
// Special case: raw strings don't have a size encoding and so don't use
|
||||
// EncodeString.
|
||||
e.buf = append(e.buf, r...)
|
||||
return nil
|
||||
}
|
||||
|
||||
// String is a message consisting of a single format string which contains
|
||||
// placeholders that may be substituted with variables.
|
||||
//
|
||||
// Variable substitutions are marked with placeholders and a variable name of
|
||||
// the form ${name}. Any other substitutions such as Go templates or
|
||||
// printf-style substitutions are left to be done by the Renderer.
|
||||
//
|
||||
// When evaluation a string interpolation, a Renderer will receive separate
|
||||
// calls for each placeholder and interstitial string. For example, for the
|
||||
// message: "%[1]v ${invites} %[2]v to ${their} party." The sequence of calls
|
||||
// is:
|
||||
// d.Render("%[1]v ")
|
||||
// d.Arg(1)
|
||||
// d.Render(resultOfInvites)
|
||||
// d.Render(" %[2]v to ")
|
||||
// d.Arg(2)
|
||||
// d.Render(resultOfTheir)
|
||||
// d.Render(" party.")
|
||||
// where the messages for "invites" and "their" both use a plural.Select
|
||||
// referring to the first argument.
|
||||
//
|
||||
// Strings may also invoke macros. Macros are essentially variables that can be
|
||||
// reused. Macros may, for instance, be used to make selections between
|
||||
// different conjugations of a verb. See the catalog package description for an
|
||||
// overview of macros.
|
||||
type String string
|
||||
|
||||
// Compile implements Message. It parses the placeholder formats and returns
|
||||
// any error.
|
||||
func (s String) Compile(e *Encoder) (err error) {
|
||||
msg := string(s)
|
||||
const subStart = "${"
|
||||
hasHeader := false
|
||||
p := 0
|
||||
b := []byte{}
|
||||
for {
|
||||
i := strings.Index(msg[p:], subStart)
|
||||
if i == -1 {
|
||||
break
|
||||
}
|
||||
b = append(b, msg[p:p+i]...)
|
||||
p += i + len(subStart)
|
||||
if i = strings.IndexByte(msg[p:], '}'); i == -1 {
|
||||
b = append(b, "$!(MISSINGBRACE)"...)
|
||||
err = fmt.Errorf("catmsg: missing '}'")
|
||||
p = len(msg)
|
||||
break
|
||||
}
|
||||
name := strings.TrimSpace(msg[p : p+i])
|
||||
if q := strings.IndexByte(name, '('); q == -1 {
|
||||
if !hasHeader {
|
||||
hasHeader = true
|
||||
e.EncodeMessageType(msgString)
|
||||
}
|
||||
e.EncodeString(string(b))
|
||||
e.EncodeSubstitution(name)
|
||||
b = b[:0]
|
||||
} else if j := strings.IndexByte(name[q:], ')'); j == -1 {
|
||||
// TODO: what should the error be?
|
||||
b = append(b, "$!(MISSINGPAREN)"...)
|
||||
err = fmt.Errorf("catmsg: missing ')'")
|
||||
} else if x, sErr := strconv.ParseUint(strings.TrimSpace(name[q+1:q+j]), 10, 32); sErr != nil {
|
||||
// TODO: handle more than one argument
|
||||
b = append(b, "$!(BADNUM)"...)
|
||||
err = fmt.Errorf("catmsg: invalid number %q", strings.TrimSpace(name[q+1:q+j]))
|
||||
} else {
|
||||
if !hasHeader {
|
||||
hasHeader = true
|
||||
e.EncodeMessageType(msgString)
|
||||
}
|
||||
e.EncodeString(string(b))
|
||||
e.EncodeSubstitution(name[:q], int(x))
|
||||
b = b[:0]
|
||||
}
|
||||
p += i + 1
|
||||
}
|
||||
b = append(b, msg[p:]...)
|
||||
if !hasHeader {
|
||||
// Simplify string to a raw string.
|
||||
Raw(string(b)).Compile(e)
|
||||
} else if len(b) > 0 {
|
||||
e.EncodeString(string(b))
|
||||
}
|
||||
return err
|
||||
}
|
316
vendor/golang.org/x/text/internal/catmsg/catmsg_test.go
generated
vendored
Normal file
316
vendor/golang.org/x/text/internal/catmsg/catmsg_test.go
generated
vendored
Normal file
|
@ -0,0 +1,316 @@
|
|||
// 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 catmsg
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"golang.org/x/text/language"
|
||||
)
|
||||
|
||||
type renderer struct {
|
||||
args []int
|
||||
result string
|
||||
}
|
||||
|
||||
func (r *renderer) Arg(i int) interface{} {
|
||||
if i >= len(r.args) {
|
||||
return nil
|
||||
}
|
||||
return r.args[i]
|
||||
}
|
||||
|
||||
func (r *renderer) Render(s string) {
|
||||
if r.result != "" {
|
||||
r.result += "|"
|
||||
}
|
||||
r.result += s
|
||||
}
|
||||
|
||||
func TestCodec(t *testing.T) {
|
||||
type test struct {
|
||||
args []int
|
||||
out string
|
||||
decErr string
|
||||
}
|
||||
single := func(out, err string) []test { return []test{{out: out, decErr: err}} }
|
||||
testCases := []struct {
|
||||
desc string
|
||||
m Message
|
||||
enc string
|
||||
encErr string
|
||||
tests []test
|
||||
}{{
|
||||
desc: "unused variable",
|
||||
m: &Var{"name", String("foo")},
|
||||
encErr: errIsVar.Error(),
|
||||
tests: single("", ""),
|
||||
}, {
|
||||
desc: "empty",
|
||||
m: empty{},
|
||||
tests: single("", ""),
|
||||
}, {
|
||||
desc: "sequence with empty",
|
||||
m: seq{empty{}},
|
||||
tests: single("", ""),
|
||||
}, {
|
||||
desc: "raw string",
|
||||
m: Raw("foo"),
|
||||
tests: single("foo", ""),
|
||||
}, {
|
||||
desc: "raw string no sub",
|
||||
m: Raw("${foo}"),
|
||||
enc: "\x02${foo}",
|
||||
tests: single("${foo}", ""),
|
||||
}, {
|
||||
desc: "simple string",
|
||||
m: String("foo"),
|
||||
tests: single("foo", ""),
|
||||
}, {
|
||||
desc: "missing var",
|
||||
m: String("foo${bar}"),
|
||||
enc: "\x03\x03foo\x02\x03bar",
|
||||
encErr: `unknown var "bar"`,
|
||||
tests: single("foo|bar", ""),
|
||||
}, {
|
||||
desc: "empty var",
|
||||
m: seq{
|
||||
&Var{"bar", seq{}},
|
||||
String("foo${bar}"),
|
||||
},
|
||||
enc: "\x00\x05\x04\x02bar\x03\x03foo\x00\x00",
|
||||
// TODO: recognize that it is cheaper to substitute bar.
|
||||
tests: single("foo|bar", ""),
|
||||
}, {
|
||||
desc: "var after value",
|
||||
m: seq{
|
||||
String("foo${bar}"),
|
||||
&Var{"bar", String("baz")},
|
||||
},
|
||||
encErr: errIsVar.Error(),
|
||||
tests: single("foo|bar", ""),
|
||||
}, {
|
||||
desc: "substitution",
|
||||
m: seq{
|
||||
&Var{"bar", String("baz")},
|
||||
String("foo${bar}"),
|
||||
},
|
||||
tests: single("foo|baz", ""),
|
||||
}, {
|
||||
desc: "shadowed variable",
|
||||
m: seq{
|
||||
&Var{"bar", String("baz")},
|
||||
seq{
|
||||
&Var{"bar", String("BAZ")},
|
||||
String("foo${bar}"),
|
||||
},
|
||||
},
|
||||
tests: single("foo|BAZ", ""),
|
||||
}, {
|
||||
desc: "nested value",
|
||||
m: nestedLang{nestedLang{empty{}}},
|
||||
tests: single("nl|nl", ""),
|
||||
}, {
|
||||
desc: "not shadowed variable",
|
||||
m: seq{
|
||||
&Var{"bar", String("baz")},
|
||||
seq{
|
||||
String("foo${bar}"),
|
||||
&Var{"bar", String("BAZ")},
|
||||
},
|
||||
},
|
||||
encErr: errIsVar.Error(),
|
||||
tests: single("foo|baz", ""),
|
||||
}, {
|
||||
desc: "duplicate variable",
|
||||
m: seq{
|
||||
&Var{"bar", String("baz")},
|
||||
&Var{"bar", String("BAZ")},
|
||||
String("${bar}"),
|
||||
},
|
||||
encErr: "catmsg: duplicate variable \"bar\"",
|
||||
tests: single("baz", ""),
|
||||
}, {
|
||||
desc: "complete incomplete variable",
|
||||
m: seq{
|
||||
&Var{"bar", incomplete{}},
|
||||
String("${bar}"),
|
||||
},
|
||||
enc: "\x00\t\b\x01\x01\x04\x04\x02bar\x03\x00\x00\x00",
|
||||
// TODO: recognize that it is cheaper to substitute bar.
|
||||
tests: single("bar", ""),
|
||||
}, {
|
||||
desc: "incomplete sequence",
|
||||
m: seq{
|
||||
incomplete{},
|
||||
incomplete{},
|
||||
},
|
||||
encErr: ErrIncomplete.Error(),
|
||||
tests: single("", ErrNoMatch.Error()),
|
||||
}, {
|
||||
desc: "compile error variable",
|
||||
m: seq{
|
||||
&Var{"bar", errorCompileMsg{}},
|
||||
String("${bar}"),
|
||||
},
|
||||
encErr: errCompileTest.Error(),
|
||||
tests: single("bar", ""),
|
||||
}, {
|
||||
desc: "compile error message",
|
||||
m: errorCompileMsg{},
|
||||
encErr: errCompileTest.Error(),
|
||||
tests: single("", ""),
|
||||
}, {
|
||||
desc: "compile error sequence",
|
||||
m: seq{
|
||||
errorCompileMsg{},
|
||||
errorCompileMsg{},
|
||||
},
|
||||
encErr: errCompileTest.Error(),
|
||||
tests: single("", ""),
|
||||
}, {
|
||||
desc: "macro",
|
||||
m: String("${exists(1)}"),
|
||||
tests: single("you betya!", ""),
|
||||
}, {
|
||||
desc: "macro incomplete",
|
||||
m: String("${incomplete(1)}"),
|
||||
enc: "\x03\x00\x01\nincomplete\x01",
|
||||
tests: single("incomplete", ""),
|
||||
}, {
|
||||
desc: "macro undefined at end",
|
||||
m: String("${undefined(1)}"),
|
||||
enc: "\x03\x00\x01\tundefined\x01",
|
||||
tests: single("undefined", "catmsg: undefined macro \"undefined\""),
|
||||
}, {
|
||||
desc: "macro undefined with more text following",
|
||||
m: String("${undefined(1)}."),
|
||||
enc: "\x03\x00\x01\tundefined\x01\x01.",
|
||||
tests: single("undefined|.", "catmsg: undefined macro \"undefined\""),
|
||||
}, {
|
||||
desc: "macro missing paren",
|
||||
m: String("${missing(1}"),
|
||||
encErr: "catmsg: missing ')'",
|
||||
tests: single("$!(MISSINGPAREN)", ""),
|
||||
}, {
|
||||
desc: "macro bad num",
|
||||
m: String("aa${bad(a)}"),
|
||||
encErr: "catmsg: invalid number \"a\"",
|
||||
tests: single("aa$!(BADNUM)", ""),
|
||||
}, {
|
||||
desc: "var missing brace",
|
||||
m: String("a${missing"),
|
||||
encErr: "catmsg: missing '}'",
|
||||
tests: single("a$!(MISSINGBRACE)", ""),
|
||||
}}
|
||||
r := &renderer{}
|
||||
dec := NewDecoder(language.Und, r, macros)
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
// Use a language other than Und so that we can test
|
||||
// passing the language to nested values.
|
||||
data, err := Compile(language.Dutch, macros, tc.m)
|
||||
if failErr(err, tc.encErr) {
|
||||
t.Errorf("encoding error: got %+q; want %+q", err, tc.encErr)
|
||||
}
|
||||
if tc.enc != "" && data != tc.enc {
|
||||
t.Errorf("encoding: got %+q; want %+q", data, tc.enc)
|
||||
}
|
||||
for _, st := range tc.tests {
|
||||
t.Run("", func(t *testing.T) {
|
||||
*r = renderer{args: st.args}
|
||||
if err = dec.Execute(data); failErr(err, st.decErr) {
|
||||
t.Errorf("decoding error: got %+q; want %+q", err, st.decErr)
|
||||
}
|
||||
if r.result != st.out {
|
||||
t.Errorf("decode: got %+q; want %+q", r.result, st.out)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func failErr(got error, want string) bool {
|
||||
if got == nil {
|
||||
return want != ""
|
||||
}
|
||||
return want == "" || !strings.Contains(got.Error(), want)
|
||||
}
|
||||
|
||||
type seq []Message
|
||||
|
||||
func (s seq) Compile(e *Encoder) (err error) {
|
||||
err = ErrIncomplete
|
||||
e.EncodeMessageType(msgFirst)
|
||||
for _, m := range s {
|
||||
// Pass only the last error, but allow erroneous or complete messages
|
||||
// here to allow testing different scenarios.
|
||||
err = e.EncodeMessage(m)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
type empty struct{}
|
||||
|
||||
func (empty) Compile(e *Encoder) (err error) { return nil }
|
||||
|
||||
var msgIncomplete = Register(
|
||||
"golang.org/x/text/internal/catmsg.incomplete",
|
||||
func(d *Decoder) bool { return false })
|
||||
|
||||
type incomplete struct{}
|
||||
|
||||
func (incomplete) Compile(e *Encoder) (err error) {
|
||||
e.EncodeMessageType(msgIncomplete)
|
||||
return ErrIncomplete
|
||||
}
|
||||
|
||||
var msgNested = Register(
|
||||
"golang.org/x/text/internal/catmsg.nested",
|
||||
func(d *Decoder) bool {
|
||||
d.Render(d.DecodeString())
|
||||
d.ExecuteMessage()
|
||||
return true
|
||||
})
|
||||
|
||||
type nestedLang struct{ Message }
|
||||
|
||||
func (n nestedLang) Compile(e *Encoder) (err error) {
|
||||
e.EncodeMessageType(msgNested)
|
||||
e.EncodeString(e.Language().String())
|
||||
e.EncodeMessage(n.Message)
|
||||
return nil
|
||||
}
|
||||
|
||||
type errorCompileMsg struct{}
|
||||
|
||||
var errCompileTest = errors.New("catmsg: compile error test")
|
||||
|
||||
func (errorCompileMsg) Compile(e *Encoder) (err error) {
|
||||
return errCompileTest
|
||||
}
|
||||
|
||||
type dictionary struct{}
|
||||
|
||||
var (
|
||||
macros = dictionary{}
|
||||
dictMessages = map[string]string{
|
||||
"exists": compile(String("you betya!")),
|
||||
"incomplete": compile(incomplete{}),
|
||||
}
|
||||
)
|
||||
|
||||
func (d dictionary) Lookup(key string) (data string, ok bool) {
|
||||
data, ok = dictMessages[key]
|
||||
return
|
||||
}
|
||||
|
||||
func compile(m Message) (data string) {
|
||||
data, _ = Compile(language.Und, macros, m)
|
||||
return data
|
||||
}
|
407
vendor/golang.org/x/text/internal/catmsg/codec.go
generated
vendored
Normal file
407
vendor/golang.org/x/text/internal/catmsg/codec.go
generated
vendored
Normal file
|
@ -0,0 +1,407 @@
|
|||
// 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 catmsg
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"golang.org/x/text/language"
|
||||
)
|
||||
|
||||
// A Renderer renders a Message.
|
||||
type Renderer interface {
|
||||
// Render renders the given string. The given string may be interpreted as a
|
||||
// format string, such as the one used by the fmt package or a template.
|
||||
Render(s string)
|
||||
|
||||
// Arg returns the i-th argument passed to format a message. This method
|
||||
// should return nil if there is no such argument. Messages need access to
|
||||
// arguments to allow selecting a message based on linguistic features of
|
||||
// those arguments.
|
||||
Arg(i int) interface{}
|
||||
}
|
||||
|
||||
// A Dictionary specifies a source of messages, including variables or macros.
|
||||
type Dictionary interface {
|
||||
// Lookup returns the message for the given key. It returns false for ok if
|
||||
// such a message could not be found.
|
||||
Lookup(key string) (data string, ok bool)
|
||||
|
||||
// TODO: consider returning an interface, instead of a string. This will
|
||||
// allow implementations to do their own message type decoding.
|
||||
}
|
||||
|
||||
// An Encoder serializes a Message to a string.
|
||||
type Encoder struct {
|
||||
// The root encoder is used for storing encoded variables.
|
||||
root *Encoder
|
||||
// The parent encoder provides the surrounding scopes for resolving variable
|
||||
// names.
|
||||
parent *Encoder
|
||||
|
||||
tag language.Tag
|
||||
|
||||
// buf holds the encoded message so far. After a message completes encoding,
|
||||
// the contents of buf, prefixed by the encoded length, are flushed to the
|
||||
// parent buffer.
|
||||
buf []byte
|
||||
|
||||
// vars is the lookup table of variables in the current scope.
|
||||
vars []keyVal
|
||||
|
||||
err error
|
||||
inBody bool // if false next call must be EncodeMessageType
|
||||
}
|
||||
|
||||
type keyVal struct {
|
||||
key string
|
||||
offset int
|
||||
}
|
||||
|
||||
// Language reports the language for which the encoded message will be stored
|
||||
// in the Catalog.
|
||||
func (e *Encoder) Language() language.Tag { return e.tag }
|
||||
|
||||
func (e *Encoder) setError(err error) {
|
||||
if e.root.err == nil {
|
||||
e.root.err = err
|
||||
}
|
||||
}
|
||||
|
||||
// EncodeUint encodes x.
|
||||
func (e *Encoder) EncodeUint(x uint64) {
|
||||
e.checkInBody()
|
||||
var buf [maxVarintBytes]byte
|
||||
n := encodeUint(buf[:], x)
|
||||
e.buf = append(e.buf, buf[:n]...)
|
||||
}
|
||||
|
||||
// EncodeString encodes s.
|
||||
func (e *Encoder) EncodeString(s string) {
|
||||
e.checkInBody()
|
||||
e.EncodeUint(uint64(len(s)))
|
||||
e.buf = append(e.buf, s...)
|
||||
}
|
||||
|
||||
// EncodeMessageType marks the current message to be of type h.
|
||||
//
|
||||
// It must be the first call of a Message's Compile method.
|
||||
func (e *Encoder) EncodeMessageType(h Handle) {
|
||||
if e.inBody {
|
||||
panic("catmsg: EncodeMessageType not the first method called")
|
||||
}
|
||||
e.inBody = true
|
||||
e.EncodeUint(uint64(h))
|
||||
}
|
||||
|
||||
// EncodeMessage serializes the given message inline at the current position.
|
||||
func (e *Encoder) EncodeMessage(m Message) error {
|
||||
e = &Encoder{root: e.root, parent: e, tag: e.tag}
|
||||
err := m.Compile(e)
|
||||
if _, ok := m.(*Var); !ok {
|
||||
e.flushTo(e.parent)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (e *Encoder) checkInBody() {
|
||||
if !e.inBody {
|
||||
panic("catmsg: expected prior call to EncodeMessageType")
|
||||
}
|
||||
}
|
||||
|
||||
// stripPrefix indicates the number of prefix bytes that must be stripped to
|
||||
// turn a single-element sequence into a message that is just this single member
|
||||
// without its size prefix. If the message can be stripped, b[1:n] contains the
|
||||
// size prefix.
|
||||
func stripPrefix(b []byte) (n int) {
|
||||
if len(b) > 0 && Handle(b[0]) == msgFirst {
|
||||
x, n, _ := decodeUint(b[1:])
|
||||
if 1+n+int(x) == len(b) {
|
||||
return 1 + n
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (e *Encoder) flushTo(dst *Encoder) {
|
||||
data := e.buf
|
||||
p := stripPrefix(data)
|
||||
if p > 0 {
|
||||
data = data[1:]
|
||||
} else {
|
||||
// Prefix the size.
|
||||
dst.EncodeUint(uint64(len(data)))
|
||||
}
|
||||
dst.buf = append(dst.buf, data...)
|
||||
}
|
||||
|
||||
func (e *Encoder) addVar(key string, m Message) error {
|
||||
for _, v := range e.parent.vars {
|
||||
if v.key == key {
|
||||
err := fmt.Errorf("catmsg: duplicate variable %q", key)
|
||||
e.setError(err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
scope := e.parent
|
||||
// If a variable message is Incomplete, and does not evaluate to a message
|
||||
// during execution, we fall back to the variable name. We encode this by
|
||||
// appending the variable name if the message reports it's incomplete.
|
||||
|
||||
err := m.Compile(e)
|
||||
if err != ErrIncomplete {
|
||||
e.setError(err)
|
||||
}
|
||||
switch {
|
||||
case len(e.buf) == 1 && Handle(e.buf[0]) == msgFirst: // empty sequence
|
||||
e.buf = e.buf[:0]
|
||||
e.inBody = false
|
||||
fallthrough
|
||||
case len(e.buf) == 0:
|
||||
// Empty message.
|
||||
if err := String(key).Compile(e); err != nil {
|
||||
e.setError(err)
|
||||
}
|
||||
case err == ErrIncomplete:
|
||||
if Handle(e.buf[0]) != msgFirst {
|
||||
seq := &Encoder{root: e.root, parent: e}
|
||||
seq.EncodeMessageType(msgFirst)
|
||||
e.flushTo(seq)
|
||||
e = seq
|
||||
}
|
||||
// e contains a sequence; append the fallback string.
|
||||
e.EncodeMessage(String(key))
|
||||
}
|
||||
|
||||
// Flush result to variable heap.
|
||||
offset := len(e.root.buf)
|
||||
e.flushTo(e.root)
|
||||
e.buf = e.buf[:0]
|
||||
|
||||
// Record variable offset in current scope.
|
||||
scope.vars = append(scope.vars, keyVal{key: key, offset: offset})
|
||||
return err
|
||||
}
|
||||
|
||||
const (
|
||||
substituteVar = iota
|
||||
substituteMacro
|
||||
substituteError
|
||||
)
|
||||
|
||||
// EncodeSubstitution inserts a resolved reference to a variable or macro.
|
||||
//
|
||||
// This call must be matched with a call to ExecuteSubstitution at decoding
|
||||
// time.
|
||||
func (e *Encoder) EncodeSubstitution(name string, arguments ...int) {
|
||||
if arity := len(arguments); arity > 0 {
|
||||
// TODO: also resolve macros.
|
||||
e.EncodeUint(substituteMacro)
|
||||
e.EncodeString(name)
|
||||
for _, a := range arguments {
|
||||
e.EncodeUint(uint64(a))
|
||||
}
|
||||
return
|
||||
}
|
||||
for scope := e; scope != nil; scope = scope.parent {
|
||||
for _, v := range scope.vars {
|
||||
if v.key != name {
|
||||
continue
|
||||
}
|
||||
e.EncodeUint(substituteVar) // TODO: support arity > 0
|
||||
e.EncodeUint(uint64(v.offset))
|
||||
return
|
||||
}
|
||||
}
|
||||
// TODO: refer to dictionary-wide scoped variables.
|
||||
e.EncodeUint(substituteError)
|
||||
e.EncodeString(name)
|
||||
e.setError(fmt.Errorf("catmsg: unknown var %q", name))
|
||||
}
|
||||
|
||||
// A Decoder deserializes and evaluates messages that are encoded by an encoder.
|
||||
type Decoder struct {
|
||||
tag language.Tag
|
||||
dst Renderer
|
||||
macros Dictionary
|
||||
|
||||
err error
|
||||
vars string
|
||||
data string
|
||||
|
||||
macroArg int // TODO: allow more than one argument
|
||||
}
|
||||
|
||||
// NewDecoder returns a new Decoder.
|
||||
//
|
||||
// Decoders are designed to be reused for multiple invocations of Execute.
|
||||
// Only one goroutine may call Execute concurrently.
|
||||
func NewDecoder(tag language.Tag, r Renderer, macros Dictionary) *Decoder {
|
||||
return &Decoder{
|
||||
tag: tag,
|
||||
dst: r,
|
||||
macros: macros,
|
||||
}
|
||||
}
|
||||
|
||||
func (d *Decoder) setError(err error) {
|
||||
if d.err == nil {
|
||||
d.err = err
|
||||
}
|
||||
}
|
||||
|
||||
// Language returns the language in which the message is being rendered.
|
||||
//
|
||||
// The destination language may be a child language of the language used for
|
||||
// encoding. For instance, a decoding language of "pt-PT"" is consistent with an
|
||||
// encoding language of "pt".
|
||||
func (d *Decoder) Language() language.Tag { return d.tag }
|
||||
|
||||
// Done reports whether there are more bytes to process in this message.
|
||||
func (d *Decoder) Done() bool { return len(d.data) == 0 }
|
||||
|
||||
// Render implements Renderer.
|
||||
func (d *Decoder) Render(s string) { d.dst.Render(s) }
|
||||
|
||||
// Arg implements Renderer.
|
||||
//
|
||||
// During evaluation of macros, the argument positions may be mapped to
|
||||
// arguments that differ from the original call.
|
||||
func (d *Decoder) Arg(i int) interface{} {
|
||||
if d.macroArg != 0 {
|
||||
if i != 1 {
|
||||
panic("catmsg: only macros with single argument supported")
|
||||
}
|
||||
i = d.macroArg
|
||||
}
|
||||
return d.dst.Arg(i)
|
||||
}
|
||||
|
||||
// DecodeUint decodes a number that was encoded with EncodeUint and advances the
|
||||
// position.
|
||||
func (d *Decoder) DecodeUint() uint64 {
|
||||
x, n, err := decodeUintString(d.data)
|
||||
d.data = d.data[n:]
|
||||
if err != nil {
|
||||
d.setError(err)
|
||||
}
|
||||
return x
|
||||
}
|
||||
|
||||
// DecodeString decodes a string that was encoded with EncodeString and advances
|
||||
// the position.
|
||||
func (d *Decoder) DecodeString() string {
|
||||
size := d.DecodeUint()
|
||||
s := d.data[:size]
|
||||
d.data = d.data[size:]
|
||||
return s
|
||||
}
|
||||
|
||||
// SkipMessage skips the message at the current location and advances the
|
||||
// position.
|
||||
func (d *Decoder) SkipMessage() {
|
||||
n := int(d.DecodeUint())
|
||||
d.data = d.data[n:]
|
||||
}
|
||||
|
||||
// Execute decodes and evaluates msg.
|
||||
//
|
||||
// Only one goroutine may call execute.
|
||||
func (d *Decoder) Execute(msg string) error {
|
||||
d.err = nil
|
||||
if !d.execute(msg) {
|
||||
return ErrNoMatch
|
||||
}
|
||||
return d.err
|
||||
}
|
||||
|
||||
func (d *Decoder) execute(msg string) bool {
|
||||
saved := d.data
|
||||
d.data = msg
|
||||
ok := d.executeMessage()
|
||||
d.data = saved
|
||||
return ok
|
||||
}
|
||||
|
||||
// executeMessageFromData is like execute, but also decodes a leading message
|
||||
// size and clips the given string accordingly.
|
||||
//
|
||||
// It reports the number of bytes consumed and whether a message was selected.
|
||||
func (d *Decoder) executeMessageFromData(s string) (n int, ok bool) {
|
||||
saved := d.data
|
||||
d.data = s
|
||||
size := int(d.DecodeUint())
|
||||
n = len(s) - len(d.data)
|
||||
// Sanitize the setting. This allows skipping a size argument for
|
||||
// RawString and method Done.
|
||||
d.data = d.data[:size]
|
||||
ok = d.executeMessage()
|
||||
n += size - len(d.data)
|
||||
d.data = saved
|
||||
return n, ok
|
||||
}
|
||||
|
||||
var errUnknownHandler = errors.New("catmsg: string contains unsupported handler")
|
||||
|
||||
// executeMessage reads the handle id, initializes the decoder and executes the
|
||||
// message. It is assumed that all of d.data[d.p:] is the single message.
|
||||
func (d *Decoder) executeMessage() bool {
|
||||
if d.Done() {
|
||||
// We interpret no data as a valid empty message.
|
||||
return true
|
||||
}
|
||||
handle := d.DecodeUint()
|
||||
|
||||
var fn Handler
|
||||
mutex.Lock()
|
||||
if int(handle) < len(handlers) {
|
||||
fn = handlers[handle]
|
||||
}
|
||||
mutex.Unlock()
|
||||
if fn == nil {
|
||||
d.setError(errUnknownHandler)
|
||||
d.execute(fmt.Sprintf("\x02$!(UNKNOWNMSGHANDLER=%#x)", handle))
|
||||
return true
|
||||
}
|
||||
return fn(d)
|
||||
}
|
||||
|
||||
// ExecuteMessage decodes and executes the message at the current position.
|
||||
func (d *Decoder) ExecuteMessage() bool {
|
||||
n, ok := d.executeMessageFromData(d.data)
|
||||
d.data = d.data[n:]
|
||||
return ok
|
||||
}
|
||||
|
||||
// ExecuteSubstitution executes the message corresponding to the substitution
|
||||
// as encoded by EncodeSubstitution.
|
||||
func (d *Decoder) ExecuteSubstitution() {
|
||||
switch x := d.DecodeUint(); x {
|
||||
case substituteVar:
|
||||
offset := d.DecodeUint()
|
||||
d.executeMessageFromData(d.vars[offset:])
|
||||
case substituteMacro:
|
||||
name := d.DecodeString()
|
||||
data, ok := d.macros.Lookup(name)
|
||||
old := d.macroArg
|
||||
// TODO: support macros of arity other than 1.
|
||||
d.macroArg = int(d.DecodeUint())
|
||||
switch {
|
||||
case !ok:
|
||||
// TODO: detect this at creation time.
|
||||
d.setError(fmt.Errorf("catmsg: undefined macro %q", name))
|
||||
fallthrough
|
||||
case !d.execute(data):
|
||||
d.dst.Render(name) // fall back to macro name.
|
||||
}
|
||||
d.macroArg = old
|
||||
case substituteError:
|
||||
d.dst.Render(d.DecodeString())
|
||||
default:
|
||||
panic("catmsg: unreachable")
|
||||
}
|
||||
}
|
62
vendor/golang.org/x/text/internal/catmsg/varint.go
generated
vendored
Normal file
62
vendor/golang.org/x/text/internal/catmsg/varint.go
generated
vendored
Normal file
|
@ -0,0 +1,62 @@
|
|||
// 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 catmsg
|
||||
|
||||
// This file implements varint encoding analogous to the one in encoding/binary.
|
||||
// We need a string version of this function, so we add that here and then add
|
||||
// the rest for consistency.
|
||||
|
||||
import "errors"
|
||||
|
||||
var (
|
||||
errIllegalVarint = errors.New("catmsg: illegal varint")
|
||||
errVarintTooLarge = errors.New("catmsg: varint too large for uint64")
|
||||
)
|
||||
|
||||
const maxVarintBytes = 10 // maximum length of a varint
|
||||
|
||||
// encodeUint encodes x as a variable-sized integer into buf and returns the
|
||||
// number of bytes written. buf must be at least maxVarintBytes long
|
||||
func encodeUint(buf []byte, x uint64) (n int) {
|
||||
for ; x > 127; n++ {
|
||||
buf[n] = 0x80 | uint8(x&0x7F)
|
||||
x >>= 7
|
||||
}
|
||||
buf[n] = uint8(x)
|
||||
n++
|
||||
return n
|
||||
}
|
||||
|
||||
func decodeUintString(s string) (x uint64, size int, err error) {
|
||||
i := 0
|
||||
for shift := uint(0); shift < 64; shift += 7 {
|
||||
if i >= len(s) {
|
||||
return 0, i, errIllegalVarint
|
||||
}
|
||||
b := uint64(s[i])
|
||||
i++
|
||||
x |= (b & 0x7F) << shift
|
||||
if b&0x80 == 0 {
|
||||
return x, i, nil
|
||||
}
|
||||
}
|
||||
return 0, i, errVarintTooLarge
|
||||
}
|
||||
|
||||
func decodeUint(b []byte) (x uint64, size int, err error) {
|
||||
i := 0
|
||||
for shift := uint(0); shift < 64; shift += 7 {
|
||||
if i >= len(b) {
|
||||
return 0, i, errIllegalVarint
|
||||
}
|
||||
c := uint64(b[i])
|
||||
i++
|
||||
x |= (c & 0x7F) << shift
|
||||
if c&0x80 == 0 {
|
||||
return x, i, nil
|
||||
}
|
||||
}
|
||||
return 0, i, errVarintTooLarge
|
||||
}
|
123
vendor/golang.org/x/text/internal/catmsg/varint_test.go
generated
vendored
Normal file
123
vendor/golang.org/x/text/internal/catmsg/varint_test.go
generated
vendored
Normal file
|
@ -0,0 +1,123 @@
|
|||
// 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 catmsg
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestEncodeUint(t *testing.T) {
|
||||
testCases := []struct {
|
||||
x uint64
|
||||
enc string
|
||||
}{
|
||||
{0, "\x00"},
|
||||
{1, "\x01"},
|
||||
{2, "\x02"},
|
||||
{0x7f, "\x7f"},
|
||||
{0x80, "\x80\x01"},
|
||||
{1 << 14, "\x80\x80\x01"},
|
||||
{0xffffffff, "\xff\xff\xff\xff\x0f"},
|
||||
{0xffffffffffffffff, "\xff\xff\xff\xff\xff\xff\xff\xff\xff\x01"},
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
buf := [maxVarintBytes]byte{}
|
||||
got := string(buf[:encodeUint(buf[:], tc.x)])
|
||||
if got != tc.enc {
|
||||
t.Errorf("EncodeUint(%#x) = %q; want %q", tc.x, got, tc.enc)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDecodeUint(t *testing.T) {
|
||||
testCases := []struct {
|
||||
x uint64
|
||||
size int
|
||||
enc string
|
||||
err error
|
||||
}{{
|
||||
x: 0,
|
||||
size: 0,
|
||||
enc: "",
|
||||
err: errIllegalVarint,
|
||||
}, {
|
||||
x: 0,
|
||||
size: 1,
|
||||
enc: "\x80",
|
||||
err: errIllegalVarint,
|
||||
}, {
|
||||
x: 0,
|
||||
size: 3,
|
||||
enc: "\x80\x80\x80",
|
||||
err: errIllegalVarint,
|
||||
}, {
|
||||
x: 0,
|
||||
size: 1,
|
||||
enc: "\x00",
|
||||
}, {
|
||||
x: 1,
|
||||
size: 1,
|
||||
enc: "\x01",
|
||||
}, {
|
||||
x: 2,
|
||||
size: 1,
|
||||
enc: "\x02",
|
||||
}, {
|
||||
x: 0x7f,
|
||||
size: 1,
|
||||
enc: "\x7f",
|
||||
}, {
|
||||
x: 0x80,
|
||||
size: 2,
|
||||
enc: "\x80\x01",
|
||||
}, {
|
||||
x: 1 << 14,
|
||||
size: 3,
|
||||
enc: "\x80\x80\x01",
|
||||
}, {
|
||||
x: 0xffffffff,
|
||||
size: 5,
|
||||
enc: "\xff\xff\xff\xff\x0f",
|
||||
}, {
|
||||
x: 0xffffffffffffffff,
|
||||
size: 10,
|
||||
enc: "\xff\xff\xff\xff\xff\xff\xff\xff\xff\x01",
|
||||
}, {
|
||||
x: 0xffffffffffffffff,
|
||||
size: 10,
|
||||
enc: "\xff\xff\xff\xff\xff\xff\xff\xff\xff\x01\x00",
|
||||
}, {
|
||||
x: 0,
|
||||
size: 10,
|
||||
enc: "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\x01",
|
||||
err: errVarintTooLarge,
|
||||
}}
|
||||
forms := []struct {
|
||||
name string
|
||||
decode func(s string) (x uint64, size int, err error)
|
||||
}{
|
||||
{"decode", func(s string) (x uint64, size int, err error) {
|
||||
return decodeUint([]byte(s))
|
||||
}},
|
||||
{"decodeString", decodeUintString},
|
||||
}
|
||||
for _, f := range forms {
|
||||
for _, tc := range testCases {
|
||||
t.Run(fmt.Sprintf("%s:%q", f.name, tc.enc), func(t *testing.T) {
|
||||
x, size, err := f.decode(tc.enc)
|
||||
if err != tc.err {
|
||||
t.Errorf("err = %q; want %q", err, tc.err)
|
||||
}
|
||||
if size != tc.size {
|
||||
t.Errorf("size = %d; want %d", size, tc.size)
|
||||
}
|
||||
if x != tc.x {
|
||||
t.Errorf("decode = %#x; want %#x", x, tc.x)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue