golangci-lint: misc (#529)
This commit is contained in:
@@ -566,6 +566,7 @@ func fieldBoolTag(field reflect.StructField, tag string) bool {
|
|||||||
return ok && x == "true"
|
return ok && x == "true"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//nolint:cyclop
|
||||||
func (enc *Encoder) encodeTable(b []byte, ctx encoderCtx, t table) ([]byte, error) {
|
func (enc *Encoder) encodeTable(b []byte, ctx encoderCtx, t table) ([]byte, error) {
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
@@ -580,6 +581,7 @@ func (enc *Encoder) encodeTable(b []byte, ctx encoderCtx, t table) ([]byte, erro
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if enc.indentTables && len(ctx.parentKey) > 0 {
|
if enc.indentTables && len(ctx.parentKey) > 0 {
|
||||||
ctx.indent++
|
ctx.indent++
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -394,7 +394,10 @@ func equalStringsIgnoreNewlines(t *testing.T, expected string, actual string) {
|
|||||||
assert.Equal(t, strings.Trim(expected, cutset), strings.Trim(actual, cutset))
|
assert.Equal(t, strings.Trim(expected, cutset), strings.Trim(actual, cutset))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//nolint:funlen
|
||||||
func TestMarshalIndentTables(t *testing.T) {
|
func TestMarshalIndentTables(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
examples := []struct {
|
examples := []struct {
|
||||||
desc string
|
desc string
|
||||||
v interface{}
|
v interface{}
|
||||||
@@ -443,7 +446,10 @@ root = 'value0'
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, e := range examples {
|
for _, e := range examples {
|
||||||
|
e := e
|
||||||
t.Run(e.desc, func(t *testing.T) {
|
t.Run(e.desc, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
var buf strings.Builder
|
var buf strings.Builder
|
||||||
enc := toml.NewEncoder(&buf)
|
enc := toml.NewEncoder(&buf)
|
||||||
enc.SetIndentTables(true)
|
enc.SetIndentTables(true)
|
||||||
|
|||||||
@@ -98,9 +98,9 @@ func (p *parser) parseExpression(b []byte) (ast.Reference, []byte, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if b[0] == '#' {
|
if b[0] == '#' {
|
||||||
_, rest, err := scanComment(b)
|
_, rest := scanComment(b)
|
||||||
|
|
||||||
return ref, rest, err
|
return ref, rest, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if b[0] == '\n' || b[0] == '\r' {
|
if b[0] == '\n' || b[0] == '\r' {
|
||||||
@@ -121,9 +121,9 @@ func (p *parser) parseExpression(b []byte) (ast.Reference, []byte, error) {
|
|||||||
b = p.parseWhitespace(b)
|
b = p.parseWhitespace(b)
|
||||||
|
|
||||||
if len(b) > 0 && b[0] == '#' {
|
if len(b) > 0 && b[0] == '#' {
|
||||||
_, rest, err := scanComment(b)
|
_, rest := scanComment(b)
|
||||||
|
|
||||||
return ref, rest, err
|
return ref, rest, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return ref, b, nil
|
return ref, b, nil
|
||||||
@@ -456,10 +456,7 @@ func (p *parser) parseOptionalWhitespaceCommentNewline(b []byte) ([]byte, error)
|
|||||||
b = p.parseWhitespace(b)
|
b = p.parseWhitespace(b)
|
||||||
|
|
||||||
if len(b) > 0 && b[0] == '#' {
|
if len(b) > 0 && b[0] == '#' {
|
||||||
_, b, err = scanComment(b)
|
_, b = scanComment(b)
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(b) == 0 {
|
if len(b) == 0 {
|
||||||
|
|||||||
+53
-39
@@ -1,9 +1,12 @@
|
|||||||
package toml
|
package toml
|
||||||
|
|
||||||
import "fmt"
|
import (
|
||||||
|
"errors"
|
||||||
|
)
|
||||||
|
|
||||||
func scanFollows(b []byte, pattern string) bool {
|
func scanFollows(b []byte, pattern string) bool {
|
||||||
n := len(pattern)
|
n := len(pattern)
|
||||||
|
|
||||||
return len(b) >= n && string(b[:n]) == pattern
|
return len(b) >= n && string(b[:n]) == pattern
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -38,6 +41,7 @@ func scanUnquotedKey(b []byte) ([]byte, []byte, error) {
|
|||||||
return b[:i], b[i:], nil
|
return b[:i], b[i:], nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return b, b[len(b):], nil
|
return b, b[len(b):], nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -57,38 +61,44 @@ func scanLiteralString(b []byte) ([]byte, []byte, error) {
|
|||||||
return nil, nil, newDecodeError(b[i:i+1], "literal strings cannot have new lines")
|
return nil, nil, newDecodeError(b[i:i+1], "literal strings cannot have new lines")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, nil, newDecodeError(b[len(b):], "unterminated literal string")
|
return nil, nil, newDecodeError(b[len(b):], "unterminated literal string")
|
||||||
}
|
}
|
||||||
|
|
||||||
func scanMultilineLiteralString(b []byte) ([]byte, []byte, error) {
|
func scanMultilineLiteralString(b []byte) ([]byte, []byte, error) {
|
||||||
//ml-literal-string = ml-literal-string-delim [ newline ] ml-literal-body
|
// ml-literal-string = ml-literal-string-delim [ newline ] ml-literal-body
|
||||||
//ml-literal-string-delim
|
// ml-literal-string-delim
|
||||||
//ml-literal-string-delim = 3apostrophe
|
// ml-literal-string-delim = 3apostrophe
|
||||||
//ml-literal-body = *mll-content *( mll-quotes 1*mll-content ) [ mll-quotes ]
|
// ml-literal-body = *mll-content *( mll-quotes 1*mll-content ) [ mll-quotes ]
|
||||||
//
|
//
|
||||||
//mll-content = mll-char / newline
|
// mll-content = mll-char / newline
|
||||||
//mll-char = %x09 / %x20-26 / %x28-7E / non-ascii
|
// mll-char = %x09 / %x20-26 / %x28-7E / non-ascii
|
||||||
//mll-quotes = 1*2apostrophe
|
// mll-quotes = 1*2apostrophe
|
||||||
for i := 3; i < len(b); i++ {
|
for i := 3; i < len(b); i++ {
|
||||||
switch b[i] {
|
if b[i] == '\'' && scanFollowsMultilineLiteralStringDelimiter(b[i:]) {
|
||||||
case '\'':
|
return b[:i+3], b[i+3:], nil
|
||||||
if scanFollowsMultilineLiteralStringDelimiter(b[i:]) {
|
|
||||||
return b[:i+3], b[i+3:], nil
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, nil, newDecodeError(b[len(b):], `multiline literal string not terminated by '''`)
|
return nil, nil, newDecodeError(b[len(b):], `multiline literal string not terminated by '''`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
errWindowsNewLineMissing = errors.New(`windows new line missing \n`)
|
||||||
|
errWindowsNewLineCRLF = errors.New(`windows new line should be \r\n`)
|
||||||
|
)
|
||||||
|
|
||||||
func scanWindowsNewline(b []byte) ([]byte, []byte, error) {
|
func scanWindowsNewline(b []byte) ([]byte, []byte, error) {
|
||||||
if len(b) < 2 {
|
const lenLF = 2
|
||||||
return nil, nil, fmt.Errorf(`windows new line missing \n`)
|
if len(b) < lenLF {
|
||||||
|
return nil, nil, errWindowsNewLineMissing
|
||||||
}
|
}
|
||||||
|
|
||||||
if b[1] != '\n' {
|
if b[1] != '\n' {
|
||||||
return nil, nil, fmt.Errorf(`windows new line should be \r\n`)
|
return nil, nil, errWindowsNewLineCRLF
|
||||||
}
|
}
|
||||||
return b[:2], b[2:], nil
|
|
||||||
|
return b[:lenLF], b[lenLF:], nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func scanWhitespace(b []byte) ([]byte, []byte) {
|
func scanWhitespace(b []byte) ([]byte, []byte) {
|
||||||
@@ -100,27 +110,31 @@ func scanWhitespace(b []byte) ([]byte, []byte) {
|
|||||||
return b[:i], b[i:]
|
return b[:i], b[i:]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return b, b[len(b):]
|
return b, b[len(b):]
|
||||||
}
|
}
|
||||||
|
|
||||||
func scanComment(b []byte) ([]byte, []byte, error) {
|
//nolint:unparam
|
||||||
//;; Comment
|
func scanComment(b []byte) ([]byte, []byte) {
|
||||||
|
// ;; Comment
|
||||||
//
|
//
|
||||||
//comment-start-symbol = %x23 ; #
|
// comment-start-symbol = %x23 ; #
|
||||||
//non-ascii = %x80-D7FF / %xE000-10FFFF
|
// non-ascii = %x80-D7FF / %xE000-10FFFF
|
||||||
//non-eol = %x09 / %x20-7F / non-ascii
|
// non-eol = %x09 / %x20-7F / non-ascii
|
||||||
//
|
//
|
||||||
//comment = comment-start-symbol *non-eol
|
// comment = comment-start-symbol *non-eol
|
||||||
|
|
||||||
for i := 1; i < len(b); i++ {
|
for i := 1; i < len(b); i++ {
|
||||||
switch b[i] {
|
if b[i] == '\n' {
|
||||||
case '\n':
|
return b[:i], b[i:]
|
||||||
return b[:i], b[i:], nil
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return b, nil, nil
|
|
||||||
|
return b, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var errBasicLineNotTerminatedByQuote = errors.New(`basic string not terminated by "`)
|
||||||
|
|
||||||
|
//nolint:godox
|
||||||
// TODO perform validation on the string?
|
// TODO perform validation on the string?
|
||||||
func scanBasicString(b []byte) ([]byte, []byte, error) {
|
func scanBasicString(b []byte) ([]byte, []byte, error) {
|
||||||
// basic-string = quotation-mark *basic-char quotation-mark
|
// basic-string = quotation-mark *basic-char quotation-mark
|
||||||
@@ -142,22 +156,22 @@ func scanBasicString(b []byte) ([]byte, []byte, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, nil, fmt.Errorf(`basic string not terminated by "`)
|
return nil, nil, errBasicLineNotTerminatedByQuote
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//nolint:godox
|
||||||
// TODO perform validation on the string?
|
// TODO perform validation on the string?
|
||||||
func scanMultilineBasicString(b []byte) ([]byte, []byte, error) {
|
func scanMultilineBasicString(b []byte) ([]byte, []byte, error) {
|
||||||
//ml-basic-string = ml-basic-string-delim [ newline ] ml-basic-body
|
// ml-basic-string = ml-basic-string-delim [ newline ] ml-basic-body
|
||||||
//ml-basic-string-delim
|
// ml-basic-string-delim
|
||||||
//ml-basic-string-delim = 3quotation-mark
|
// ml-basic-string-delim = 3quotation-mark
|
||||||
//ml-basic-body = *mlb-content *( mlb-quotes 1*mlb-content ) [ mlb-quotes ]
|
// ml-basic-body = *mlb-content *( mlb-quotes 1*mlb-content ) [ mlb-quotes ]
|
||||||
//
|
//
|
||||||
//mlb-content = mlb-char / newline / mlb-escaped-nl
|
// mlb-content = mlb-char / newline / mlb-escaped-nl
|
||||||
//mlb-char = mlb-unescaped / escaped
|
// mlb-char = mlb-unescaped / escaped
|
||||||
//mlb-quotes = 1*2quotation-mark
|
// mlb-quotes = 1*2quotation-mark
|
||||||
//mlb-unescaped = wschar / %x21 / %x23-5B / %x5D-7E / non-ascii
|
// mlb-unescaped = wschar / %x21 / %x23-5B / %x5D-7E / non-ascii
|
||||||
//mlb-escaped-nl = escape ws newline *( wschar / newline )
|
// mlb-escaped-nl = escape ws newline *( wschar / newline )
|
||||||
|
|
||||||
for i := 3; i < len(b); i++ {
|
for i := 3; i < len(b); i++ {
|
||||||
switch b[i] {
|
switch b[i] {
|
||||||
case '"':
|
case '"':
|
||||||
|
|||||||
+84
-23
@@ -2,6 +2,7 @@ package toml
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding"
|
"encoding"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
@@ -17,6 +18,7 @@ func Unmarshal(data []byte, v interface{}) error {
|
|||||||
p := parser{}
|
p := parser{}
|
||||||
p.Reset(data)
|
p.Reset(data)
|
||||||
d := decoder{}
|
d := decoder{}
|
||||||
|
|
||||||
return d.FromParser(&p, v)
|
return d.FromParser(&p, v)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -54,8 +56,9 @@ func (d *Decoder) SetStrict(strict bool) {
|
|||||||
func (d *Decoder) Decode(v interface{}) error {
|
func (d *Decoder) Decode(v interface{}) error {
|
||||||
b, err := ioutil.ReadAll(d.r)
|
b, err := ioutil.ReadAll(d.r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return fmt.Errorf("Decode: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
p := parser{}
|
p := parser{}
|
||||||
p.Reset(b)
|
p.Reset(b)
|
||||||
dec := decoder{
|
dec := decoder{
|
||||||
@@ -63,6 +66,7 @@ func (d *Decoder) Decode(v interface{}) error {
|
|||||||
Enabled: d.strict,
|
Enabled: d.strict,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
return dec.FromParser(&p, v)
|
return dec.FromParser(&p, v)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -90,19 +94,19 @@ func (d *decoder) arrayIndex(append bool, v reflect.Value) int {
|
|||||||
idx++
|
idx++
|
||||||
d.arrayIndexes[v] = idx
|
d.arrayIndexes[v] = idx
|
||||||
}
|
}
|
||||||
|
|
||||||
return idx
|
return idx
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *decoder) FromParser(p *parser, v interface{}) error {
|
func (d *decoder) FromParser(p *parser, v interface{}) error {
|
||||||
err := d.fromParser(p, v)
|
err := d.fromParser(p, v)
|
||||||
if err != nil {
|
|
||||||
de, ok := err.(*decodeError)
|
|
||||||
if ok {
|
|
||||||
err = wrapDecodeError(p.data, de)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if err == nil {
|
if err == nil {
|
||||||
err = d.strict.Error(p.data)
|
return d.strict.Error(p.data)
|
||||||
|
}
|
||||||
|
|
||||||
|
var e *decodeError
|
||||||
|
if errors.As(err, &e) {
|
||||||
|
return wrapDecodeError(p.data, e)
|
||||||
}
|
}
|
||||||
|
|
||||||
return err
|
return err
|
||||||
@@ -110,29 +114,43 @@ func (d *decoder) FromParser(p *parser, v interface{}) error {
|
|||||||
|
|
||||||
func keyLocation(node ast.Node) []byte {
|
func keyLocation(node ast.Node) []byte {
|
||||||
k := node.Key()
|
k := node.Key()
|
||||||
|
|
||||||
hasOne := k.Next()
|
hasOne := k.Next()
|
||||||
if !hasOne {
|
if !hasOne {
|
||||||
panic("should not be called with empty key")
|
panic("should not be called with empty key")
|
||||||
}
|
}
|
||||||
|
|
||||||
start := k.Node().Data
|
start := k.Node().Data
|
||||||
end := k.Node().Data
|
end := k.Node().Data
|
||||||
|
|
||||||
for k.Next() {
|
for k.Next() {
|
||||||
end = k.Node().Data
|
end = k.Node().Data
|
||||||
}
|
}
|
||||||
|
|
||||||
return unsafe.BytesRange(start, end)
|
return unsafe.BytesRange(start, end)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
errFromParserExpectingPointer = errors.New("expecting a pointer as target")
|
||||||
|
errFromParserExpectingNonNilPointer = errors.New("expecting non nil pointer as target")
|
||||||
|
)
|
||||||
|
|
||||||
|
//nolint:funlen,cyclop
|
||||||
func (d *decoder) fromParser(p *parser, v interface{}) error {
|
func (d *decoder) fromParser(p *parser, v interface{}) error {
|
||||||
r := reflect.ValueOf(v)
|
r := reflect.ValueOf(v)
|
||||||
if r.Kind() != reflect.Ptr {
|
if r.Kind() != reflect.Ptr {
|
||||||
return fmt.Errorf("need to target a pointer, not %s", r.Kind())
|
return fmt.Errorf("fromParser: %w, not %s", errFromParserExpectingPointer, r.Kind())
|
||||||
}
|
|
||||||
if r.IsNil() {
|
|
||||||
return fmt.Errorf("target pointer must be non-nil")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var skipUntilTable bool
|
if r.IsNil() {
|
||||||
var root target = valueTarget(r.Elem())
|
return errFromParserExpectingNonNilPointer
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
skipUntilTable bool
|
||||||
|
root target = valueTarget(r.Elem())
|
||||||
|
)
|
||||||
|
|
||||||
current := root
|
current := root
|
||||||
|
|
||||||
for p.NextExpression() {
|
for p.NextExpression() {
|
||||||
@@ -144,10 +162,11 @@ func (d *decoder) fromParser(p *parser, v interface{}) error {
|
|||||||
|
|
||||||
err := d.seen.CheckExpression(node)
|
err := d.seen.CheckExpression(node)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return fmt.Errorf("fromParser: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
var found bool
|
var found bool
|
||||||
|
|
||||||
switch node.Kind {
|
switch node.Kind {
|
||||||
case ast.KeyValue:
|
case ast.KeyValue:
|
||||||
err = d.unmarshalKeyValue(current, node)
|
err = d.unmarshalKeyValue(current, node)
|
||||||
@@ -167,7 +186,7 @@ func (d *decoder) fromParser(p *parser, v interface{}) error {
|
|||||||
d.strict.EnterArrayTable(node)
|
d.strict.EnterArrayTable(node)
|
||||||
current, found, err = d.scopeWithArrayTable(root, node.Key())
|
current, found, err = d.scopeWithArrayTable(root, node.Key())
|
||||||
default:
|
default:
|
||||||
panic(fmt.Errorf("this should not be a top level node type: %s", node.Kind))
|
panic(fmt.Sprintf("fromParser: this should not be a top level node type: %s", node.Kind))
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -176,6 +195,7 @@ func (d *decoder) fromParser(p *parser, v interface{}) error {
|
|||||||
|
|
||||||
if !found {
|
if !found {
|
||||||
skipUntilTable = true
|
skipUntilTable = true
|
||||||
|
|
||||||
d.strict.MissingTable(node)
|
d.strict.MissingTable(node)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -192,38 +212,49 @@ func (d *decoder) fromParser(p *parser, v interface{}) error {
|
|||||||
// When encountering slices, it should always use its last element, and error
|
// When encountering slices, it should always use its last element, and error
|
||||||
// if the slice does not have any.
|
// if the slice does not have any.
|
||||||
func (d *decoder) scopeWithKey(x target, key ast.Iterator) (target, bool, error) {
|
func (d *decoder) scopeWithKey(x target, key ast.Iterator) (target, bool, error) {
|
||||||
var err error
|
var (
|
||||||
found := true
|
err error
|
||||||
|
found bool
|
||||||
|
)
|
||||||
|
|
||||||
for key.Next() {
|
for key.Next() {
|
||||||
n := key.Node()
|
n := key.Node()
|
||||||
|
|
||||||
x, found, err = d.scopeTableTarget(false, x, string(n.Data))
|
x, found, err = d.scopeTableTarget(false, x, string(n.Data))
|
||||||
if err != nil || !found {
|
if err != nil || !found {
|
||||||
return nil, found, err
|
return nil, found, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return x, true, nil
|
return x, true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//nolint:cyclop
|
||||||
// scopeWithArrayTable performs target scoping when unmarshaling an
|
// scopeWithArrayTable performs target scoping when unmarshaling an
|
||||||
// ast.ArrayTable node.
|
// ast.ArrayTable node.
|
||||||
//
|
//
|
||||||
// It is the same as scopeWithKey, but when scoping the last part of the key
|
// It is the same as scopeWithKey, but when scoping the last part of the key
|
||||||
// it creates a new element in the array instead of using the last one.
|
// it creates a new element in the array instead of using the last one.
|
||||||
func (d *decoder) scopeWithArrayTable(x target, key ast.Iterator) (target, bool, error) {
|
func (d *decoder) scopeWithArrayTable(x target, key ast.Iterator) (target, bool, error) {
|
||||||
var err error
|
var (
|
||||||
found := true
|
err error
|
||||||
|
found bool
|
||||||
|
)
|
||||||
|
|
||||||
for key.Next() {
|
for key.Next() {
|
||||||
n := key.Node()
|
n := key.Node()
|
||||||
if !n.Next().Valid() { // want to stop at one before last
|
if !n.Next().Valid() { // want to stop at one before last
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
x, found, err = d.scopeTableTarget(false, x, string(n.Data))
|
x, found, err = d.scopeTableTarget(false, x, string(n.Data))
|
||||||
if err != nil || !found {
|
if err != nil || !found {
|
||||||
return nil, found, err
|
return nil, found, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
n := key.Node()
|
n := key.Node()
|
||||||
|
|
||||||
x, found, err = d.scopeTableTarget(false, x, string(n.Data))
|
x, found, err = d.scopeTableTarget(false, x, string(n.Data))
|
||||||
if err != nil || !found {
|
if err != nil || !found {
|
||||||
return x, found, err
|
return x, found, err
|
||||||
@@ -236,6 +267,7 @@ func (d *decoder) scopeWithArrayTable(x target, key ast.Iterator) (target, bool,
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return x, false, err
|
return x, false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
v = x.get()
|
v = x.get()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -244,6 +276,7 @@ func (d *decoder) scopeWithArrayTable(x target, key ast.Iterator) (target, bool,
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return x, found, err
|
return x, found, err
|
||||||
}
|
}
|
||||||
|
|
||||||
v = x.get()
|
v = x.get()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -252,6 +285,7 @@ func (d *decoder) scopeWithArrayTable(x target, key ast.Iterator) (target, bool,
|
|||||||
x, err = scopeSlice(true, x)
|
x, err = scopeSlice(true, x)
|
||||||
case reflect.Array:
|
case reflect.Array:
|
||||||
x, err = d.scopeArray(true, x)
|
x, err = d.scopeArray(true, x)
|
||||||
|
default:
|
||||||
}
|
}
|
||||||
|
|
||||||
return x, found, err
|
return x, found, err
|
||||||
@@ -295,22 +329,28 @@ func tryTextUnmarshaler(x target, node ast.Node) (bool, error) {
|
|||||||
if v.Type().Implements(textUnmarshalerType) {
|
if v.Type().Implements(textUnmarshalerType) {
|
||||||
return true, v.Interface().(encoding.TextUnmarshaler).UnmarshalText(node.Data)
|
return true, v.Interface().(encoding.TextUnmarshaler).UnmarshalText(node.Data)
|
||||||
}
|
}
|
||||||
|
|
||||||
if v.CanAddr() && v.Addr().Type().Implements(textUnmarshalerType) {
|
if v.CanAddr() && v.Addr().Type().Implements(textUnmarshalerType) {
|
||||||
return true, v.Addr().Interface().(encoding.TextUnmarshaler).UnmarshalText(node.Data)
|
return true, v.Addr().Interface().(encoding.TextUnmarshaler).UnmarshalText(node.Data)
|
||||||
}
|
}
|
||||||
|
|
||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//nolint:cyclop
|
||||||
func (d *decoder) unmarshalValue(x target, node ast.Node) error {
|
func (d *decoder) unmarshalValue(x target, node ast.Node) error {
|
||||||
v := x.get()
|
v := x.get()
|
||||||
|
|
||||||
if v.Kind() == reflect.Ptr {
|
if v.Kind() == reflect.Ptr {
|
||||||
if !v.Elem().IsValid() {
|
if !v.Elem().IsValid() {
|
||||||
err := x.set(reflect.New(v.Type().Elem()))
|
err := x.set(reflect.New(v.Type().Elem()))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
v = x.get()
|
v = x.get()
|
||||||
}
|
}
|
||||||
|
|
||||||
return d.unmarshalValue(valueTarget(v.Elem()), node)
|
return d.unmarshalValue(valueTarget(v.Elem()), node)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -339,37 +379,44 @@ func (d *decoder) unmarshalValue(x target, node ast.Node) error {
|
|||||||
case ast.LocalDate:
|
case ast.LocalDate:
|
||||||
return unmarshalLocalDate(x, node)
|
return unmarshalLocalDate(x, node)
|
||||||
default:
|
default:
|
||||||
panic(fmt.Errorf("unhandled unmarshalValue kind %s", node.Kind))
|
panic(fmt.Sprintf("unmarshalValue: unhandled unmarshalValue kind %s", node.Kind))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func unmarshalLocalDate(x target, node ast.Node) error {
|
func unmarshalLocalDate(x target, node ast.Node) error {
|
||||||
assertNode(ast.LocalDate, node)
|
assertNode(ast.LocalDate, node)
|
||||||
|
|
||||||
v, err := parseLocalDate(node.Data)
|
v, err := parseLocalDate(node.Data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return setDate(x, v)
|
return setDate(x, v)
|
||||||
}
|
}
|
||||||
|
|
||||||
func unmarshalLocalDateTime(x target, node ast.Node) error {
|
func unmarshalLocalDateTime(x target, node ast.Node) error {
|
||||||
assertNode(ast.LocalDateTime, node)
|
assertNode(ast.LocalDateTime, node)
|
||||||
|
|
||||||
v, rest, err := parseLocalDateTime(node.Data)
|
v, rest, err := parseLocalDateTime(node.Data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(rest) > 0 {
|
if len(rest) > 0 {
|
||||||
return newDecodeError(rest, "extra characters at the end of a local date time")
|
return newDecodeError(rest, "extra characters at the end of a local date time")
|
||||||
}
|
}
|
||||||
|
|
||||||
return setLocalDateTime(x, v)
|
return setLocalDateTime(x, v)
|
||||||
}
|
}
|
||||||
|
|
||||||
func unmarshalDateTime(x target, node ast.Node) error {
|
func unmarshalDateTime(x target, node ast.Node) error {
|
||||||
assertNode(ast.DateTime, node)
|
assertNode(ast.DateTime, node)
|
||||||
|
|
||||||
v, err := parseDateTime(node.Data)
|
v, err := parseDateTime(node.Data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return setDateTime(x, v)
|
return setDateTime(x, v)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -378,6 +425,7 @@ func setLocalDateTime(x target, v LocalDateTime) error {
|
|||||||
cast := v.In(time.Local)
|
cast := v.In(time.Local)
|
||||||
return setDateTime(x, cast)
|
return setDateTime(x, cast)
|
||||||
}
|
}
|
||||||
|
|
||||||
return x.set(reflect.ValueOf(v))
|
return x.set(reflect.ValueOf(v))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -398,21 +446,25 @@ func setDate(x target, v LocalDate) error {
|
|||||||
|
|
||||||
func unmarshalString(x target, node ast.Node) error {
|
func unmarshalString(x target, node ast.Node) error {
|
||||||
assertNode(ast.String, node)
|
assertNode(ast.String, node)
|
||||||
|
|
||||||
return setString(x, string(node.Data))
|
return setString(x, string(node.Data))
|
||||||
}
|
}
|
||||||
|
|
||||||
func unmarshalBool(x target, node ast.Node) error {
|
func unmarshalBool(x target, node ast.Node) error {
|
||||||
assertNode(ast.Bool, node)
|
assertNode(ast.Bool, node)
|
||||||
v := node.Data[0] == 't'
|
v := node.Data[0] == 't'
|
||||||
|
|
||||||
return setBool(x, v)
|
return setBool(x, v)
|
||||||
}
|
}
|
||||||
|
|
||||||
func unmarshalInteger(x target, node ast.Node) error {
|
func unmarshalInteger(x target, node ast.Node) error {
|
||||||
assertNode(ast.Integer, node)
|
assertNode(ast.Integer, node)
|
||||||
|
|
||||||
v, err := parseInteger(node.Data)
|
v, err := parseInteger(node.Data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return setInt64(x, v)
|
return setInt64(x, v)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -422,6 +474,7 @@ func unmarshalFloat(x target, node ast.Node) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return setFloat64(x, v)
|
return setFloat64(x, v)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -433,11 +486,13 @@ func (d *decoder) unmarshalInlineTable(x target, node ast.Node) error {
|
|||||||
it := node.Children()
|
it := node.Children()
|
||||||
for it.Next() {
|
for it.Next() {
|
||||||
n := it.Node()
|
n := it.Node()
|
||||||
|
|
||||||
err := d.unmarshalKeyValue(x, n)
|
err := d.unmarshalKeyValue(x, n)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -449,30 +504,36 @@ func (d *decoder) unmarshalArray(x target, node ast.Node) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
it := node.Children()
|
|
||||||
idx := 0
|
idx := 0
|
||||||
|
|
||||||
|
it := node.Children()
|
||||||
for it.Next() {
|
for it.Next() {
|
||||||
n := it.Node()
|
n := it.Node()
|
||||||
|
|
||||||
v, err := elementAt(x, idx)
|
v, err := elementAt(x, idx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if v == nil {
|
if v == nil {
|
||||||
// when we go out of bound for an array just stop processing it to
|
// when we go out of bound for an array just stop processing it to
|
||||||
// mimic encoding/json
|
// mimic encoding/json
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
err = d.unmarshalValue(v, n)
|
err = d.unmarshalValue(v, n)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
idx++
|
idx++
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func assertNode(expected ast.Kind, node ast.Node) {
|
func assertNode(expected ast.Kind, node ast.Node) {
|
||||||
if node.Kind != expected {
|
if node.Kind != expected {
|
||||||
panic(fmt.Errorf("expected node of kind %s, not %s", expected, node.Kind))
|
panic(fmt.Sprintf("expected node of kind %s, not %s", expected, node.Kind))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+85
-14
@@ -1,6 +1,7 @@
|
|||||||
package toml_test
|
package toml_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
"strconv"
|
"strconv"
|
||||||
@@ -14,6 +15,8 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestUnmarshal_Integers(t *testing.T) {
|
func TestUnmarshal_Integers(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
examples := []struct {
|
examples := []struct {
|
||||||
desc string
|
desc string
|
||||||
input string
|
input string
|
||||||
@@ -62,7 +65,10 @@ func TestUnmarshal_Integers(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, e := range examples {
|
for _, e := range examples {
|
||||||
|
e := e
|
||||||
t.Run(e.desc, func(t *testing.T) {
|
t.Run(e.desc, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
doc := doc{}
|
doc := doc{}
|
||||||
err := toml.Unmarshal([]byte(`A = `+e.input), &doc)
|
err := toml.Unmarshal([]byte(`A = `+e.input), &doc)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
@@ -71,7 +77,10 @@ func TestUnmarshal_Integers(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//nolint:funlen
|
||||||
func TestUnmarshal_Floats(t *testing.T) {
|
func TestUnmarshal_Floats(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
examples := []struct {
|
examples := []struct {
|
||||||
desc string
|
desc string
|
||||||
input string
|
input string
|
||||||
@@ -161,7 +170,10 @@ func TestUnmarshal_Floats(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, e := range examples {
|
for _, e := range examples {
|
||||||
|
e := e
|
||||||
t.Run(e.desc, func(t *testing.T) {
|
t.Run(e.desc, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
doc := doc{}
|
doc := doc{}
|
||||||
err := toml.Unmarshal([]byte(`A = `+e.input), &doc)
|
err := toml.Unmarshal([]byte(`A = `+e.input), &doc)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
@@ -174,7 +186,10 @@ func TestUnmarshal_Floats(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//nolint:funlen
|
||||||
func TestUnmarshal(t *testing.T) {
|
func TestUnmarshal(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
type test struct {
|
type test struct {
|
||||||
target interface{}
|
target interface{}
|
||||||
expected interface{}
|
expected interface{}
|
||||||
@@ -193,6 +208,7 @@ func TestUnmarshal(t *testing.T) {
|
|||||||
type doc struct {
|
type doc struct {
|
||||||
A string
|
A string
|
||||||
}
|
}
|
||||||
|
|
||||||
return test{
|
return test{
|
||||||
target: &doc{},
|
target: &doc{},
|
||||||
expected: &doc{A: "foo"},
|
expected: &doc{A: "foo"},
|
||||||
@@ -205,6 +221,7 @@ func TestUnmarshal(t *testing.T) {
|
|||||||
fruit . flavor = "banana"`,
|
fruit . flavor = "banana"`,
|
||||||
gen: func() test {
|
gen: func() test {
|
||||||
m := map[string]interface{}{}
|
m := map[string]interface{}{}
|
||||||
|
|
||||||
return test{
|
return test{
|
||||||
target: &m,
|
target: &m,
|
||||||
expected: &map[string]interface{}{
|
expected: &map[string]interface{}{
|
||||||
@@ -222,6 +239,7 @@ func TestUnmarshal(t *testing.T) {
|
|||||||
"\"b\"" = 2`,
|
"\"b\"" = 2`,
|
||||||
gen: func() test {
|
gen: func() test {
|
||||||
m := map[string]interface{}{}
|
m := map[string]interface{}{}
|
||||||
|
|
||||||
return test{
|
return test{
|
||||||
target: &m,
|
target: &m,
|
||||||
expected: &map[string]interface{}{
|
expected: &map[string]interface{}{
|
||||||
@@ -239,6 +257,7 @@ func TestUnmarshal(t *testing.T) {
|
|||||||
type doc struct {
|
type doc struct {
|
||||||
A string
|
A string
|
||||||
}
|
}
|
||||||
|
|
||||||
return test{
|
return test{
|
||||||
target: &doc{},
|
target: &doc{},
|
||||||
expected: &doc{A: "Test"},
|
expected: &doc{A: "Test"},
|
||||||
@@ -252,6 +271,7 @@ func TestUnmarshal(t *testing.T) {
|
|||||||
type doc struct {
|
type doc struct {
|
||||||
A bool
|
A bool
|
||||||
}
|
}
|
||||||
|
|
||||||
return test{
|
return test{
|
||||||
target: &doc{},
|
target: &doc{},
|
||||||
expected: &doc{A: true},
|
expected: &doc{A: true},
|
||||||
@@ -265,6 +285,7 @@ func TestUnmarshal(t *testing.T) {
|
|||||||
type doc struct {
|
type doc struct {
|
||||||
A bool
|
A bool
|
||||||
}
|
}
|
||||||
|
|
||||||
return test{
|
return test{
|
||||||
target: &doc{A: true},
|
target: &doc{A: true},
|
||||||
expected: &doc{A: false},
|
expected: &doc{A: false},
|
||||||
@@ -278,6 +299,7 @@ func TestUnmarshal(t *testing.T) {
|
|||||||
type doc struct {
|
type doc struct {
|
||||||
A []string
|
A []string
|
||||||
}
|
}
|
||||||
|
|
||||||
return test{
|
return test{
|
||||||
target: &doc{},
|
target: &doc{},
|
||||||
expected: &doc{A: []string{"foo", "bar"}},
|
expected: &doc{A: []string{"foo", "bar"}},
|
||||||
@@ -295,6 +317,7 @@ B = "data"`,
|
|||||||
type doc struct {
|
type doc struct {
|
||||||
A A
|
A A
|
||||||
}
|
}
|
||||||
|
|
||||||
return test{
|
return test{
|
||||||
target: &doc{},
|
target: &doc{},
|
||||||
expected: &doc{A: A{B: "data"}},
|
expected: &doc{A: A{B: "data"}},
|
||||||
@@ -306,6 +329,7 @@ B = "data"`,
|
|||||||
input: `[A]`,
|
input: `[A]`,
|
||||||
gen: func() test {
|
gen: func() test {
|
||||||
var v map[string]interface{}
|
var v map[string]interface{}
|
||||||
|
|
||||||
return test{
|
return test{
|
||||||
target: &v,
|
target: &v,
|
||||||
expected: &map[string]interface{}{`A`: map[string]interface{}{}},
|
expected: &map[string]interface{}{`A`: map[string]interface{}{}},
|
||||||
@@ -323,6 +347,7 @@ B = "data"`,
|
|||||||
type doc struct {
|
type doc struct {
|
||||||
Name name
|
Name name
|
||||||
}
|
}
|
||||||
|
|
||||||
return test{
|
return test{
|
||||||
target: &doc{},
|
target: &doc{},
|
||||||
expected: &doc{Name: name{
|
expected: &doc{Name: name{
|
||||||
@@ -337,6 +362,7 @@ B = "data"`,
|
|||||||
input: `A = {}`,
|
input: `A = {}`,
|
||||||
gen: func() test {
|
gen: func() test {
|
||||||
var v map[string]interface{}
|
var v map[string]interface{}
|
||||||
|
|
||||||
return test{
|
return test{
|
||||||
target: &v,
|
target: &v,
|
||||||
expected: &map[string]interface{}{`A`: map[string]interface{}{}},
|
expected: &map[string]interface{}{`A`: map[string]interface{}{}},
|
||||||
@@ -354,6 +380,7 @@ B = "data"`,
|
|||||||
type doc struct {
|
type doc struct {
|
||||||
Names []name
|
Names []name
|
||||||
}
|
}
|
||||||
|
|
||||||
return test{
|
return test{
|
||||||
target: &doc{},
|
target: &doc{},
|
||||||
expected: &doc{
|
expected: &doc{
|
||||||
@@ -376,6 +403,7 @@ B = "data"`,
|
|||||||
input: `A = "foo"`,
|
input: `A = "foo"`,
|
||||||
gen: func() test {
|
gen: func() test {
|
||||||
doc := map[string]interface{}{}
|
doc := map[string]interface{}{}
|
||||||
|
|
||||||
return test{
|
return test{
|
||||||
target: &doc,
|
target: &doc,
|
||||||
expected: &map[string]interface{}{
|
expected: &map[string]interface{}{
|
||||||
@@ -390,6 +418,7 @@ B = "data"`,
|
|||||||
B = 42`,
|
B = 42`,
|
||||||
gen: func() test {
|
gen: func() test {
|
||||||
doc := map[string]interface{}{}
|
doc := map[string]interface{}{}
|
||||||
|
|
||||||
return test{
|
return test{
|
||||||
target: &doc,
|
target: &doc,
|
||||||
expected: &map[string]interface{}{
|
expected: &map[string]interface{}{
|
||||||
@@ -404,6 +433,7 @@ B = "data"`,
|
|||||||
input: `A = ["foo", "bar"]`,
|
input: `A = ["foo", "bar"]`,
|
||||||
gen: func() test {
|
gen: func() test {
|
||||||
doc := map[string]interface{}{}
|
doc := map[string]interface{}{}
|
||||||
|
|
||||||
return test{
|
return test{
|
||||||
target: &doc,
|
target: &doc,
|
||||||
expected: &map[string]interface{}{
|
expected: &map[string]interface{}{
|
||||||
@@ -417,6 +447,7 @@ B = "data"`,
|
|||||||
input: `A = "foo"`,
|
input: `A = "foo"`,
|
||||||
gen: func() test {
|
gen: func() test {
|
||||||
doc := map[string]string{}
|
doc := map[string]string{}
|
||||||
|
|
||||||
return test{
|
return test{
|
||||||
target: &doc,
|
target: &doc,
|
||||||
expected: &map[string]string{
|
expected: &map[string]string{
|
||||||
@@ -430,6 +461,7 @@ B = "data"`,
|
|||||||
input: `A = 42.0`,
|
input: `A = 42.0`,
|
||||||
gen: func() test {
|
gen: func() test {
|
||||||
doc := map[string]string{}
|
doc := map[string]string{}
|
||||||
|
|
||||||
return test{
|
return test{
|
||||||
target: &doc,
|
target: &doc,
|
||||||
err: true,
|
err: true,
|
||||||
@@ -447,6 +479,7 @@ B = "data"`,
|
|||||||
type Doc struct {
|
type Doc struct {
|
||||||
First []First
|
First []First
|
||||||
}
|
}
|
||||||
|
|
||||||
return test{
|
return test{
|
||||||
target: &Doc{},
|
target: &Doc{},
|
||||||
expected: &Doc{
|
expected: &Doc{
|
||||||
@@ -464,13 +497,13 @@ B = "data"`,
|
|||||||
input: `[[Products]]
|
input: `[[Products]]
|
||||||
Name = "Hammer"
|
Name = "Hammer"
|
||||||
Sku = 738594937
|
Sku = 738594937
|
||||||
|
|
||||||
[[Products]] # empty table within the array
|
[[Products]] # empty table within the array
|
||||||
|
|
||||||
[[Products]]
|
[[Products]]
|
||||||
Name = "Nail"
|
Name = "Nail"
|
||||||
Sku = 284758393
|
Sku = 284758393
|
||||||
|
|
||||||
Color = "gray"`,
|
Color = "gray"`,
|
||||||
gen: func() test {
|
gen: func() test {
|
||||||
type Product struct {
|
type Product struct {
|
||||||
@@ -481,6 +514,7 @@ B = "data"`,
|
|||||||
type Doc struct {
|
type Doc struct {
|
||||||
Products []Product
|
Products []Product
|
||||||
}
|
}
|
||||||
|
|
||||||
return test{
|
return test{
|
||||||
target: &Doc{},
|
target: &Doc{},
|
||||||
expected: &Doc{
|
expected: &Doc{
|
||||||
@@ -498,13 +532,13 @@ B = "data"`,
|
|||||||
input: `[[Products]]
|
input: `[[Products]]
|
||||||
Name = "Hammer"
|
Name = "Hammer"
|
||||||
Sku = 738594937
|
Sku = 738594937
|
||||||
|
|
||||||
[[Products]] # empty table within the array
|
[[Products]] # empty table within the array
|
||||||
|
|
||||||
[[Products]]
|
[[Products]]
|
||||||
Name = "Nail"
|
Name = "Nail"
|
||||||
Sku = 284758393
|
Sku = 284758393
|
||||||
|
|
||||||
Color = "gray"`,
|
Color = "gray"`,
|
||||||
gen: func() test {
|
gen: func() test {
|
||||||
return test{
|
return test{
|
||||||
@@ -654,6 +688,7 @@ B = "data"`,
|
|||||||
A *[]*string
|
A *[]*string
|
||||||
}
|
}
|
||||||
hello := "Hello"
|
hello := "Hello"
|
||||||
|
|
||||||
return test{
|
return test{
|
||||||
target: &doc{},
|
target: &doc{},
|
||||||
expected: &doc{
|
expected: &doc{
|
||||||
@@ -673,6 +708,7 @@ B = "data"`,
|
|||||||
type doc struct {
|
type doc struct {
|
||||||
A interface{}
|
A interface{}
|
||||||
}
|
}
|
||||||
|
|
||||||
return test{
|
return test{
|
||||||
target: &doc{
|
target: &doc{
|
||||||
A: inner{
|
A: inner{
|
||||||
@@ -700,6 +736,7 @@ B = "data"`,
|
|||||||
type doc struct {
|
type doc struct {
|
||||||
A [4]inner
|
A [4]inner
|
||||||
}
|
}
|
||||||
|
|
||||||
return test{
|
return test{
|
||||||
target: &doc{},
|
target: &doc{},
|
||||||
expected: &doc{
|
expected: &doc{
|
||||||
@@ -716,6 +753,7 @@ B = "data"`,
|
|||||||
input: "A = 1\r\n\r\nB = 2",
|
input: "A = 1\r\n\r\nB = 2",
|
||||||
gen: func() test {
|
gen: func() test {
|
||||||
doc := map[string]interface{}{}
|
doc := map[string]interface{}{}
|
||||||
|
|
||||||
return test{
|
return test{
|
||||||
target: &doc,
|
target: &doc,
|
||||||
expected: &map[string]interface{}{
|
expected: &map[string]interface{}{
|
||||||
@@ -730,6 +768,7 @@ B = "data"`,
|
|||||||
input: "A = 1\r",
|
input: "A = 1\r",
|
||||||
gen: func() test {
|
gen: func() test {
|
||||||
doc := map[string]interface{}{}
|
doc := map[string]interface{}{}
|
||||||
|
|
||||||
return test{
|
return test{
|
||||||
target: &doc,
|
target: &doc,
|
||||||
err: true,
|
err: true,
|
||||||
@@ -741,6 +780,7 @@ B = "data"`,
|
|||||||
input: "A = 1\rB = 2",
|
input: "A = 1\rB = 2",
|
||||||
gen: func() test {
|
gen: func() test {
|
||||||
doc := map[string]interface{}{}
|
doc := map[string]interface{}{}
|
||||||
|
|
||||||
return test{
|
return test{
|
||||||
target: &doc,
|
target: &doc,
|
||||||
err: true,
|
err: true,
|
||||||
@@ -752,6 +792,7 @@ B = "data"`,
|
|||||||
input: `a = 1z = 2`,
|
input: `a = 1z = 2`,
|
||||||
gen: func() test {
|
gen: func() test {
|
||||||
m := map[string]interface{}{}
|
m := map[string]interface{}{}
|
||||||
|
|
||||||
return test{
|
return test{
|
||||||
target: &m,
|
target: &m,
|
||||||
err: true,
|
err: true,
|
||||||
@@ -761,7 +802,10 @@ B = "data"`,
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, e := range examples {
|
for _, e := range examples {
|
||||||
|
e := e
|
||||||
t.Run(e.desc, func(t *testing.T) {
|
t.Run(e.desc, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
if e.skip {
|
if e.skip {
|
||||||
t.Skip()
|
t.Skip()
|
||||||
}
|
}
|
||||||
@@ -791,7 +835,7 @@ func (i Integer484) MarshalText() ([]byte, error) {
|
|||||||
func (i *Integer484) UnmarshalText(data []byte) error {
|
func (i *Integer484) UnmarshalText(data []byte) error {
|
||||||
conv, err := strconv.Atoi(string(data))
|
conv, err := strconv.Atoi(string(data))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return fmt.Errorf("UnmarshalText: %w", err)
|
||||||
}
|
}
|
||||||
i.Value = conv
|
i.Value = conv
|
||||||
return nil
|
return nil
|
||||||
@@ -803,6 +847,7 @@ type Config484 struct {
|
|||||||
|
|
||||||
func TestIssue484(t *testing.T) {
|
func TestIssue484(t *testing.T) {
|
||||||
raw := []byte(`integers = ["1","2","3","100"]`)
|
raw := []byte(`integers = ["1","2","3","100"]`)
|
||||||
|
|
||||||
var cfg Config484
|
var cfg Config484
|
||||||
err := toml.Unmarshal(raw, &cfg)
|
err := toml.Unmarshal(raw, &cfg)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
@@ -864,6 +909,7 @@ func TestIssue494(t *testing.T) {
|
|||||||
foo = 2021-04-08
|
foo = 2021-04-08
|
||||||
bar = 2021-04-08
|
bar = 2021-04-08
|
||||||
`
|
`
|
||||||
|
|
||||||
type s struct {
|
type s struct {
|
||||||
Foo time.Time `toml:"foo"`
|
Foo time.Time `toml:"foo"`
|
||||||
Bar time.Time `toml:"bar"`
|
Bar time.Time `toml:"bar"`
|
||||||
@@ -880,7 +926,10 @@ func TestIssue507(t *testing.T) {
|
|||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//nolint:funlen
|
||||||
func TestUnmarshalDecodeErrors(t *testing.T) {
|
func TestUnmarshalDecodeErrors(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
examples := []struct {
|
examples := []struct {
|
||||||
desc string
|
desc string
|
||||||
data string
|
data string
|
||||||
@@ -955,14 +1004,19 @@ world'`,
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, e := range examples {
|
for _, e := range examples {
|
||||||
|
e := e
|
||||||
t.Run(e.desc, func(t *testing.T) {
|
t.Run(e.desc, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
m := map[string]interface{}{}
|
m := map[string]interface{}{}
|
||||||
err := toml.Unmarshal([]byte(e.data), &m)
|
err := toml.Unmarshal([]byte(e.data), &m)
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
de, ok := err.(*toml.DecodeError)
|
|
||||||
if !ok {
|
var de *toml.DecodeError
|
||||||
|
if !errors.As(err, &de) {
|
||||||
t.Fatalf("err should have been a *toml.DecodeError, but got %s (%T)", err, err)
|
t.Fatalf("err should have been a *toml.DecodeError, but got %s (%T)", err, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if e.msg != "" {
|
if e.msg != "" {
|
||||||
t.Log("\n" + de.String())
|
t.Log("\n" + de.String())
|
||||||
require.Equal(t, e.msg, de.Error())
|
require.Equal(t, e.msg, de.Error())
|
||||||
@@ -971,6 +1025,7 @@ world'`,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//nolint:funlen
|
||||||
func TestLocalDateTime(t *testing.T) {
|
func TestLocalDateTime(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
@@ -1058,6 +1113,7 @@ func TestIssue508(t *testing.T) {
|
|||||||
type head struct {
|
type head struct {
|
||||||
Title string `toml:"title"`
|
Title string `toml:"title"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type text struct {
|
type text struct {
|
||||||
head
|
head
|
||||||
}
|
}
|
||||||
@@ -1070,7 +1126,10 @@ func TestIssue508(t *testing.T) {
|
|||||||
require.Equal(t, "This is a title", t1.head.Title)
|
require.Equal(t, "This is a title", t1.head.Title)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//nolint:funlen
|
||||||
func TestDecoderStrict(t *testing.T) {
|
func TestDecoderStrict(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
examples := []struct {
|
examples := []struct {
|
||||||
desc string
|
desc string
|
||||||
input string
|
input string
|
||||||
@@ -1139,7 +1198,10 @@ bar = 42
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, e := range examples {
|
for _, e := range examples {
|
||||||
|
e := e
|
||||||
t.Run(e.desc, func(t *testing.T) {
|
t.Run(e.desc, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
r := strings.NewReader(e.input)
|
r := strings.NewReader(e.input)
|
||||||
d := toml.NewDecoder(r)
|
d := toml.NewDecoder(r)
|
||||||
d.SetStrict(true)
|
d.SetStrict(true)
|
||||||
@@ -1148,8 +1210,13 @@ bar = 42
|
|||||||
x = &struct{}{}
|
x = &struct{}{}
|
||||||
}
|
}
|
||||||
err := d.Decode(x)
|
err := d.Decode(x)
|
||||||
details := err.(*toml.StrictMissingError)
|
|
||||||
equalStringsIgnoreNewlines(t, e.expected, details.String())
|
var tsm *toml.StrictMissingError
|
||||||
|
if errors.As(err, &tsm) {
|
||||||
|
equalStringsIgnoreNewlines(t, e.expected, tsm.String())
|
||||||
|
} else {
|
||||||
|
t.Fatalf("err should have been a *toml.StrictMissingError, but got %s (%T)", err, err)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1171,11 +1238,15 @@ key3 = "value3"
|
|||||||
err := d.Decode(&s)
|
err := d.Decode(&s)
|
||||||
|
|
||||||
fmt.Println(err.Error())
|
fmt.Println(err.Error())
|
||||||
// Output: strict mode: fields in the document are missing in the target struct
|
|
||||||
|
|
||||||
details := err.(*toml.StrictMissingError)
|
var details *toml.StrictMissingError
|
||||||
|
if !errors.As(err, &details) {
|
||||||
|
panic(fmt.Sprintf("err should have been a *toml.StrictMissingError, but got %s (%T)", err, err))
|
||||||
|
}
|
||||||
|
|
||||||
fmt.Println(details.String())
|
fmt.Println(details.String())
|
||||||
// Ouput:
|
// Output:
|
||||||
|
// strict mode: fields in the document are missing in the target struct
|
||||||
// 2| key1 = "value1"
|
// 2| key1 = "value1"
|
||||||
// 3| key2 = "value2"
|
// 3| key2 = "value2"
|
||||||
// | ~~~~ missing field
|
// | ~~~~ missing field
|
||||||
|
|||||||
Reference in New Issue
Block a user