golangci-lint (#530)

This commit is contained in:
Vincent Serpoul
2021-05-07 10:29:21 +08:00
committed by GitHub
parent 201d5dd422
commit 3f2bb0b363
9 changed files with 611 additions and 118 deletions
+1 -1
View File
@@ -79,6 +79,6 @@ enable = [
"varcheck", "varcheck",
"wastedassign", "wastedassign",
"whitespace", "whitespace",
"wrapcheck", # "wrapcheck",
"wsl" "wsl"
] ]
+11
View File
@@ -56,6 +56,7 @@ func TestDates(t *testing.T) {
if got := test.date.String(); got != test.wantStr { if got := test.date.String(); got != test.wantStr {
t.Errorf("%#v.String() = %q, want %q", test.date, got, test.wantStr) t.Errorf("%#v.String() = %q, want %q", test.date, got, test.wantStr)
} }
if got := test.date.In(test.loc); !got.Equal(test.wantTime) { if got := test.date.In(test.loc); !got.Equal(test.wantTime) {
t.Errorf("%#v.In(%v) = %v, want %v", test.date, test.loc, got, test.wantTime) t.Errorf("%#v.In(%v) = %v, want %v", test.date, test.loc, got, test.wantTime)
} }
@@ -109,6 +110,7 @@ func TestParseDate(t *testing.T) {
if got != test.want { if got != test.want {
t.Errorf("ParseLocalDate(%q) = %+v, want %+v", test.str, got, test.want) t.Errorf("ParseLocalDate(%q) = %+v, want %+v", test.str, got, test.want)
} }
if err != nil && test.want != (emptyDate) { if err != nil && test.want != (emptyDate) {
t.Errorf("Unexpected error %v from ParseLocalDate(%q)", err, test.str) t.Errorf("Unexpected error %v from ParseLocalDate(%q)", err, test.str)
} }
@@ -170,6 +172,7 @@ func TestDateArithmetic(t *testing.T) {
if got := test.start.AddDays(test.days); got != test.end { if got := test.start.AddDays(test.days); got != test.end {
t.Errorf("[%s] %#v.AddDays(%v) = %#v, want %#v", test.desc, test.start, test.days, got, test.end) t.Errorf("[%s] %#v.AddDays(%v) = %#v, want %#v", test.desc, test.start, test.days, got, test.end)
} }
if got := test.end.DaysSince(test.start); got != test.days { if got := test.end.DaysSince(test.start); got != test.days {
t.Errorf("[%s] %#v.Sub(%#v) = %v, want %v", test.desc, test.end, test.start, got, test.days) t.Errorf("[%s] %#v.Sub(%#v) = %v, want %v", test.desc, test.end, test.start, got, test.days)
} }
@@ -231,9 +234,11 @@ func TestTimeToString(t *testing.T) {
continue continue
} }
if gotTime != test.time { if gotTime != test.time {
t.Errorf("ParseLocalTime(%q) = %+v, want %+v", test.str, gotTime, test.time) t.Errorf("ParseLocalTime(%q) = %+v, want %+v", test.str, gotTime, test.time)
} }
if test.roundTrip { if test.roundTrip {
gotStr := test.time.String() gotStr := test.time.String()
if gotStr != test.str { if gotStr != test.str {
@@ -303,9 +308,11 @@ func TestDateTimeToString(t *testing.T) {
continue continue
} }
if gotDateTime != test.dateTime { if gotDateTime != test.dateTime {
t.Errorf("ParseLocalDateTime(%q) = %+v, want %+v", test.str, gotDateTime, test.dateTime) t.Errorf("ParseLocalDateTime(%q) = %+v, want %+v", test.str, gotDateTime, test.dateTime)
} }
if test.roundTrip { if test.roundTrip {
gotStr := test.dateTime.String() gotStr := test.dateTime.String()
if gotStr != test.str { if gotStr != test.str {
@@ -444,6 +451,7 @@ func TestMarshalJSON(t *testing.T) {
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
if got := string(bgot); got != test.want { if got := string(bgot); got != test.want {
t.Errorf("%#v: got %s, want %s", test.value, got, test.want) t.Errorf("%#v: got %s, want %s", test.value, got, test.want)
} }
@@ -472,6 +480,7 @@ func TestUnmarshalJSON(t *testing.T) {
if err := json.Unmarshal([]byte(test.data), test.ptr); err != nil { if err := json.Unmarshal([]byte(test.data), test.ptr); err != nil {
t.Fatalf("%s: %v", test.data, err) t.Fatalf("%s: %v", test.data, err)
} }
if !cmpEqual(test.ptr, test.want) { if !cmpEqual(test.ptr, test.want) {
t.Errorf("%s: got %#v, want %#v", test.data, test.ptr, test.want) t.Errorf("%s: got %#v, want %#v", test.data, test.ptr, test.want)
} }
@@ -486,9 +495,11 @@ func TestUnmarshalJSON(t *testing.T) {
if json.Unmarshal([]byte(bad), &d) == nil { if json.Unmarshal([]byte(bad), &d) == nil {
t.Errorf("%q, LocalDate: got nil, want error", bad) t.Errorf("%q, LocalDate: got nil, want error", bad)
} }
if json.Unmarshal([]byte(bad), &tm) == nil { if json.Unmarshal([]byte(bad), &tm) == nil {
t.Errorf("%q, LocalTime: got nil, want error", bad) t.Errorf("%q, LocalTime: got nil, want error", bad)
} }
if json.Unmarshal([]byte(bad), &dt) == nil { if json.Unmarshal([]byte(bad), &dt) == nil {
t.Errorf("%q, LocalDateTime: got nil, want error", bad) t.Errorf("%q, LocalDateTime: got nil, want error", bad)
} }
+2 -2
View File
@@ -370,7 +370,7 @@ func (p *parser) parseInlineTable(b []byte) (ast.Reference, []byte, error) {
return parent, rest, err return parent, rest, err
} }
var errArrayCanNotStartWithComma = errors.New("array cannot start with comma") var errArrayCannotStartWithComma = errors.New("array cannot start with comma")
//nolint:funlen,cyclop //nolint:funlen,cyclop
func (p *parser) parseValArray(b []byte) (ast.Reference, []byte, error) { func (p *parser) parseValArray(b []byte) (ast.Reference, []byte, error) {
@@ -409,7 +409,7 @@ func (p *parser) parseValArray(b []byte) (ast.Reference, []byte, error) {
if b[0] == ',' { if b[0] == ',' {
if first { if first {
return parent, nil, errArrayCanNotStartWithComma return parent, nil, errArrayCannotStartWithComma
} }
b = b[1:] b = b[1:]
+321 -87
View File
@@ -1,6 +1,7 @@
package toml package toml
import ( import (
"errors"
"fmt" "fmt"
"math" "math"
"reflect" "reflect"
@@ -38,26 +39,31 @@ func (t valueTarget) get() reflect.Value {
func (t valueTarget) set(v reflect.Value) error { func (t valueTarget) set(v reflect.Value) error {
reflect.Value(t).Set(v) reflect.Value(t).Set(v)
return nil return nil
} }
func (t valueTarget) setString(v string) error { func (t valueTarget) setString(v string) error {
t.get().SetString(v) t.get().SetString(v)
return nil return nil
} }
func (t valueTarget) setBool(v bool) error { func (t valueTarget) setBool(v bool) error {
t.get().SetBool(v) t.get().SetBool(v)
return nil return nil
} }
func (t valueTarget) setInt64(v int64) error { func (t valueTarget) setInt64(v int64) error {
t.get().SetInt(v) t.get().SetInt(v)
return nil return nil
} }
func (t valueTarget) setFloat64(v float64) error { func (t valueTarget) setFloat64(v float64) error {
t.get().SetFloat(v) t.get().SetFloat(v)
return nil return nil
} }
@@ -71,23 +77,48 @@ func (t interfaceTarget) get() reflect.Value {
} }
func (t interfaceTarget) set(v reflect.Value) error { func (t interfaceTarget) set(v reflect.Value) error {
return t.x.set(v) err := t.x.set(v)
if err != nil {
return fmt.Errorf("interfaceTarget set: %w", err)
}
return nil
} }
func (t interfaceTarget) setString(v string) error { func (t interfaceTarget) setString(v string) error {
return t.x.setString(v) err := t.x.setString(v)
if err != nil {
return fmt.Errorf("interfaceTarget setString: %w", err)
}
return nil
} }
func (t interfaceTarget) setBool(v bool) error { func (t interfaceTarget) setBool(v bool) error {
return t.x.setBool(v) err := t.x.setBool(v)
if err != nil {
return fmt.Errorf("interfaceTarget setBool: %w", err)
}
return nil
} }
func (t interfaceTarget) setInt64(v int64) error { func (t interfaceTarget) setInt64(v int64) error {
return t.x.setInt64(v) err := t.x.setInt64(v)
if err != nil {
return fmt.Errorf("interfaceTarget setInt64: %w", err)
}
return nil
} }
func (t interfaceTarget) setFloat64(v float64) error { func (t interfaceTarget) setFloat64(v float64) error {
return t.x.setFloat64(v) err := t.x.setFloat64(v)
if err != nil {
return fmt.Errorf("interfaceTarget setFloat64: %w", err)
}
return nil
} }
// mapTarget targets a specific key of a map. // mapTarget targets a specific key of a map.
@@ -102,6 +133,7 @@ func (t mapTarget) get() reflect.Value {
func (t mapTarget) set(v reflect.Value) error { func (t mapTarget) set(v reflect.Value) error {
t.v.SetMapIndex(t.k, v) t.v.SetMapIndex(t.k, v)
return nil return nil
} }
@@ -121,6 +153,12 @@ func (t mapTarget) setFloat64(v float64) error {
return t.set(reflect.ValueOf(v)) return t.set(reflect.ValueOf(v))
} }
var (
errValIndexExpectingSlice = errors.New("expecting a slice")
errValIndexCannotInitSlice = errors.New("cannot initialize a slice")
)
//nolint:cyclop
// makes sure that the value pointed at by t is indexable (Slice, Array), or // makes sure that the value pointed at by t is indexable (Slice, Array), or
// dereferences to an indexable (Ptr, Interface). // dereferences to an indexable (Ptr, Interface).
func ensureValueIndexable(t target) error { func ensureValueIndexable(t target) error {
@@ -129,159 +167,319 @@ func ensureValueIndexable(t target) error {
switch f.Type().Kind() { switch f.Type().Kind() {
case reflect.Slice: case reflect.Slice:
if f.IsNil() { if f.IsNil() {
return t.set(reflect.MakeSlice(f.Type(), 0, 0)) err := t.set(reflect.MakeSlice(f.Type(), 0, 0))
if err != nil {
return fmt.Errorf("ensureValueIndexable: %w", err)
}
return nil
} }
case reflect.Interface: case reflect.Interface:
if f.IsNil() || f.Elem().Type() != sliceInterfaceType { if f.IsNil() || f.Elem().Type() != sliceInterfaceType {
return t.set(reflect.MakeSlice(sliceInterfaceType, 0, 0)) err := t.set(reflect.MakeSlice(sliceInterfaceType, 0, 0))
if err != nil {
return fmt.Errorf("ensureValueIndexable: %w", err)
}
return nil
} }
if f.Elem().Type().Kind() != reflect.Slice { if f.Elem().Type().Kind() != reflect.Slice {
return fmt.Errorf("interface is pointing to a %s, not a slice", f.Kind()) return fmt.Errorf("ensureValueIndexable: %w, not a %s", errValIndexExpectingSlice, f.Kind())
} }
case reflect.Ptr: case reflect.Ptr:
if f.IsNil() { if f.IsNil() {
ptr := reflect.New(f.Type().Elem()) ptr := reflect.New(f.Type().Elem())
err := t.set(ptr) err := t.set(ptr)
if err != nil { if err != nil {
return err return fmt.Errorf("ensureValueIndexable: %w", err)
} }
f = t.get() f = t.get()
} }
return ensureValueIndexable(valueTarget(f.Elem())) return ensureValueIndexable(valueTarget(f.Elem()))
case reflect.Array: case reflect.Array:
// arrays are always initialized. // arrays are always initialized.
default: default:
return fmt.Errorf("cannot initialize a slice in %s", f.Kind()) return fmt.Errorf("ensureValueIndexable: %w with %s", errValIndexCannotInitSlice, f.Kind())
} }
return nil return nil
} }
var sliceInterfaceType = reflect.TypeOf([]interface{}{}) var (
var mapStringInterfaceType = reflect.TypeOf(map[string]interface{}{}) sliceInterfaceType = reflect.TypeOf([]interface{}{})
mapStringInterfaceType = reflect.TypeOf(map[string]interface{}{})
)
func ensureMapIfInterface(x target) { func ensureMapIfInterface(x target) error {
v := x.get() v := x.get()
if v.Kind() == reflect.Interface && v.IsNil() { if v.Kind() == reflect.Interface && v.IsNil() {
newElement := reflect.MakeMap(mapStringInterfaceType) newElement := reflect.MakeMap(mapStringInterfaceType)
x.set(newElement)
err := x.set(newElement)
if err != nil {
return fmt.Errorf("ensureMapIfInterface: %w", err)
}
} }
return nil
} }
var errSetStringCannotAssignString = errors.New("cannot assign string")
func setString(t target, v string) error { func setString(t target, v string) error {
f := t.get() f := t.get()
switch f.Kind() { switch f.Kind() {
case reflect.String: case reflect.String:
return t.setString(v) err := t.setString(v)
if err != nil {
return fmt.Errorf("setString: %w", err)
}
return nil
case reflect.Interface: case reflect.Interface:
return t.set(reflect.ValueOf(v)) err := t.set(reflect.ValueOf(v))
if err != nil {
return fmt.Errorf("setString: %w", err)
}
return nil
default: default:
return fmt.Errorf("cannot assign string to a %s", f.Kind()) return fmt.Errorf("setString: %w to a %s", errSetStringCannotAssignString, f.Kind())
} }
} }
var errSetBoolCannotAssignBool = errors.New("cannot assign bool")
func setBool(t target, v bool) error { func setBool(t target, v bool) error {
f := t.get() f := t.get()
switch f.Kind() { switch f.Kind() {
case reflect.Bool: case reflect.Bool:
return t.setBool(v) err := t.setBool(v)
if err != nil {
return fmt.Errorf("setBool: %w", err)
}
return nil
case reflect.Interface: case reflect.Interface:
return t.set(reflect.ValueOf(v)) err := t.set(reflect.ValueOf(v))
if err != nil {
return fmt.Errorf("setBool: %w", err)
}
return nil
default: default:
return fmt.Errorf("cannot assign bool to a %s", f.String()) return fmt.Errorf("setBool: %w to a %s", errSetBoolCannotAssignBool, f.String())
} }
} }
const maxInt = int64(^uint(0) >> 1) const (
const minInt = -maxInt - 1 maxInt = int64(^uint(0) >> 1)
minInt = -maxInt - 1
)
var (
errSetInt64InInt32 = errors.New("does not fit in an int32")
errSetInt64InInt16 = errors.New("does not fit in an int16")
errSetInt64InInt8 = errors.New("does not fit in an int8")
errSetInt64InInt = errors.New("does not fit in an int")
errSetInt64InUint64 = errors.New("negative integer does not fit in an uint64")
errSetInt64InUint32 = errors.New("negative integer does not fit in an uint32")
errSetInt64InUint32Max = errors.New("integer does not fit in an uint32")
errSetInt64InUint16 = errors.New("negative integer does not fit in an uint16")
errSetInt64InUint16Max = errors.New("integer does not fit in an uint16")
errSetInt64InUint8 = errors.New("negative integer does not fit in an uint8")
errSetInt64InUint8Max = errors.New("integer does not fit in an uint8")
errSetInt64InUint = errors.New("negative integer does not fit in an uint")
errSetInt64Unknown = errors.New("does not fit in an uint")
)
//nolint:funlen,gocognit,cyclop,gocyclo
func setInt64(t target, v int64) error { func setInt64(t target, v int64) error {
f := t.get() f := t.get()
switch f.Kind() { switch f.Kind() {
case reflect.Int64: case reflect.Int64:
return t.setInt64(v) err := t.setInt64(v)
if err != nil {
return fmt.Errorf("setInt64: %w", err)
}
return nil
case reflect.Int32: case reflect.Int32:
if v < math.MinInt32 || v > math.MaxInt32 { if v < math.MinInt32 || v > math.MaxInt32 {
return fmt.Errorf("integer %d does not fit in an int32", v) return fmt.Errorf("setInt64: integer %d %w", v, errSetInt64InInt32)
} }
return t.set(reflect.ValueOf(int32(v)))
err := t.set(reflect.ValueOf(int32(v)))
if err != nil {
return fmt.Errorf("setInt64: %w", err)
}
return nil
case reflect.Int16: case reflect.Int16:
if v < math.MinInt16 || v > math.MaxInt16 { if v < math.MinInt16 || v > math.MaxInt16 {
return fmt.Errorf("integer %d does not fit in an int16", v) return fmt.Errorf("setInt64: integer %d %w", v, errSetInt64InInt16)
} }
return t.set(reflect.ValueOf(int16(v)))
err := t.set(reflect.ValueOf(int16(v)))
if err != nil {
return fmt.Errorf("setInt64: %w", err)
}
return nil
case reflect.Int8: case reflect.Int8:
if v < math.MinInt8 || v > math.MaxInt8 { if v < math.MinInt8 || v > math.MaxInt8 {
return fmt.Errorf("integer %d does not fit in an int8", v) return fmt.Errorf("setInt64: integer %d %w", v, errSetInt64InInt8)
} }
return t.set(reflect.ValueOf(int8(v)))
err := t.set(reflect.ValueOf(int8(v)))
if err != nil {
return fmt.Errorf("setInt64: %w", err)
}
return nil
case reflect.Int: case reflect.Int:
if v < minInt || v > maxInt { if v < minInt || v > maxInt {
return fmt.Errorf("integer %d does not fit in an int", v) return fmt.Errorf("setInt64: integer %d %w", v, errSetInt64InInt)
} }
return t.set(reflect.ValueOf(int(v)))
err := t.set(reflect.ValueOf(int(v)))
if err != nil {
return fmt.Errorf("setInt64: %w", err)
}
return nil
case reflect.Uint64: case reflect.Uint64:
if v < 0 { if v < 0 {
return fmt.Errorf("negative integer %d cannot be stored in an uint64", v) return fmt.Errorf("setInt64: %d, %w", v, errSetInt64InUint64)
} }
return t.set(reflect.ValueOf(uint64(v)))
err := t.set(reflect.ValueOf(uint64(v)))
if err != nil {
return fmt.Errorf("setInt64: %w", err)
}
return nil
case reflect.Uint32: case reflect.Uint32:
if v < 0 { if v < 0 {
return fmt.Errorf("negative integer %d cannot be stored in an uint32", v) return fmt.Errorf("setInt64: %d, %w", v, errSetInt64InUint32)
} }
if v > math.MaxUint32 { if v > math.MaxUint32 {
return fmt.Errorf("integer %d cannot be stored in an uint32", v) return fmt.Errorf("setInt64: %d, %w", v, errSetInt64InUint32Max)
} }
return t.set(reflect.ValueOf(uint32(v)))
err := t.set(reflect.ValueOf(uint32(v)))
if err != nil {
return fmt.Errorf("setInt64: %w", err)
}
return nil
case reflect.Uint16: case reflect.Uint16:
if v < 0 { if v < 0 {
return fmt.Errorf("negative integer %d cannot be stored in an uint16", v) return fmt.Errorf("setInt64: %d, %w", v, errSetInt64InUint16)
} }
if v > math.MaxUint16 { if v > math.MaxUint16 {
return fmt.Errorf("integer %d cannot be stored in an uint16", v) return fmt.Errorf("setInt64: %d, %w", v, errSetInt64InUint16Max)
} }
return t.set(reflect.ValueOf(uint16(v)))
err := t.set(reflect.ValueOf(uint16(v)))
if err != nil {
return fmt.Errorf("setInt64: %w", err)
}
return nil
case reflect.Uint8: case reflect.Uint8:
if v < 0 { if v < 0 {
return fmt.Errorf("negative integer %d cannot be stored in an uint8", v) return fmt.Errorf("setInt64: %d, %w", v, errSetInt64InUint8)
} }
if v > math.MaxUint8 { if v > math.MaxUint8 {
return fmt.Errorf("integer %d cannot be stored in an uint8", v) return fmt.Errorf("setInt64: %d, %w", v, errSetInt64InUint8Max)
} }
return t.set(reflect.ValueOf(uint8(v)))
err := t.set(reflect.ValueOf(uint8(v)))
if err != nil {
return fmt.Errorf("setInt64: %w", err)
}
return nil
case reflect.Uint: case reflect.Uint:
if v < 0 { if v < 0 {
return fmt.Errorf("negative integer %d cannot be stored in an uint", v) return fmt.Errorf("setInt64: %d, %w", v, errSetInt64InUint)
} }
return t.set(reflect.ValueOf(uint(v)))
err := t.set(reflect.ValueOf(uint(v)))
if err != nil {
return fmt.Errorf("setInt64: %w", err)
}
return nil
case reflect.Interface: case reflect.Interface:
return t.set(reflect.ValueOf(v)) err := t.set(reflect.ValueOf(v))
if err != nil {
return fmt.Errorf("setInt64: %w", err)
}
return nil
default: default:
return fmt.Errorf("cannot assign int64 to a %s", f.String()) return fmt.Errorf("setInt64: %s, %w", f.String(), errSetInt64Unknown)
} }
} }
var (
errSetFloat64InFloat32Max = errors.New("does not fit in an float32")
errSetFloat64Unknown = errors.New("does not fit in an float32")
)
func setFloat64(t target, v float64) error { func setFloat64(t target, v float64) error {
f := t.get() f := t.get()
switch f.Kind() { switch f.Kind() {
case reflect.Float64: case reflect.Float64:
return t.setFloat64(v) err := t.setFloat64(v)
if err != nil {
return fmt.Errorf("setFloat64: %w", err)
}
return nil
case reflect.Float32: case reflect.Float32:
if v > math.MaxFloat32 { if v > math.MaxFloat32 {
return fmt.Errorf("float %f cannot be stored in a float32", v) return fmt.Errorf("setFloat64: %f %w", v, errSetFloat64InFloat32Max)
} }
return t.set(reflect.ValueOf(float32(v)))
err := t.set(reflect.ValueOf(float32(v)))
if err != nil {
return fmt.Errorf("setFloat64: %w", err)
}
return nil
case reflect.Interface: case reflect.Interface:
return t.set(reflect.ValueOf(v)) err := t.set(reflect.ValueOf(v))
if err != nil {
return fmt.Errorf("setFloat64: %w", err)
}
return nil
default: default:
return fmt.Errorf("cannot assign float64 to a %s", f.String()) return fmt.Errorf("setFloat64: %s %w", f.String(), errSetFloat64Unknown)
} }
} }
var (
errElementAtCannotOn = errors.New("cannot elementAt")
errElementAtCannotOnUnknown = errors.New("cannot elementAt")
)
//nolint:cyclop
// Returns the element at idx of the value pointed at by target, or an error if // Returns the element at idx of the value pointed at by target, or an error if
// t does not point to an indexable. // t does not point to an indexable.
// If the target points to an Array and idx is out of bounds, it returns // If the target points to an Array and idx is out of bounds, it returns
@@ -291,95 +489,111 @@ func elementAt(t target, idx int) (target, error) {
switch f.Kind() { switch f.Kind() {
case reflect.Slice: case reflect.Slice:
//nolint:godox
// TODO: use the idx function argument and avoid alloc if possible. // TODO: use the idx function argument and avoid alloc if possible.
idx := f.Len() idx := f.Len()
err := t.set(reflect.Append(f, reflect.New(f.Type().Elem()).Elem())) err := t.set(reflect.Append(f, reflect.New(f.Type().Elem()).Elem()))
if err != nil { if err != nil {
return nil, err return nil, fmt.Errorf("elementAt: %w", err)
} }
return valueTarget(t.get().Index(idx)), nil return valueTarget(t.get().Index(idx)), nil
case reflect.Array: case reflect.Array:
if idx >= f.Len() { if idx >= f.Len() {
return nil, nil return nil, nil
} }
return valueTarget(f.Index(idx)), nil return valueTarget(f.Index(idx)), nil
case reflect.Interface: case reflect.Interface:
if f.IsNil() { if f.IsNil() {
panic("interface should have been initialized") panic("interface should have been initialized")
} }
ifaceElem := f.Elem() ifaceElem := f.Elem()
if ifaceElem.Kind() != reflect.Slice { if ifaceElem.Kind() != reflect.Slice {
return nil, fmt.Errorf("cannot elementAt on a %s", f.Kind()) return nil, fmt.Errorf("elementAt: %w on a %s", errElementAtCannotOn, f.Kind())
} }
idx := ifaceElem.Len() idx := ifaceElem.Len()
newElem := reflect.New(ifaceElem.Type().Elem()).Elem() newElem := reflect.New(ifaceElem.Type().Elem()).Elem()
newSlice := reflect.Append(ifaceElem, newElem) newSlice := reflect.Append(ifaceElem, newElem)
err := t.set(newSlice) err := t.set(newSlice)
if err != nil { if err != nil {
return nil, err return nil, fmt.Errorf("elementAt: %w", err)
} }
return valueTarget(t.get().Elem().Index(idx)), nil return valueTarget(t.get().Elem().Index(idx)), nil
case reflect.Ptr: case reflect.Ptr:
return elementAt(valueTarget(f.Elem()), idx) return elementAt(valueTarget(f.Elem()), idx)
default: default:
return nil, fmt.Errorf("cannot elementAt on a %s", f.Kind()) return nil, fmt.Errorf("elementAt: %w on a %s", errElementAtCannotOnUnknown, f.Kind())
} }
} }
func (d *decoder) scopeTableTarget(append bool, t target, name string) (target, bool, error) { //nolint:cyclop
func (d *decoder) scopeTableTarget(shouldAppend bool, t target, name string) (target, bool, error) {
x := t.get() x := t.get()
switch x.Kind() { switch x.Kind() {
// Kinds that need to recurse // Kinds that need to recurse
case reflect.Interface: case reflect.Interface:
t, err := scopeInterface(append, t) t, err := scopeInterface(shouldAppend, t)
if err != nil { if err != nil {
return t, false, err return t, false, fmt.Errorf("scopeTableTarget: %w", err)
} }
return d.scopeTableTarget(append, t, name)
return d.scopeTableTarget(shouldAppend, t, name)
case reflect.Ptr: case reflect.Ptr:
t, err := scopePtr(t) t, err := scopePtr(t)
if err != nil { if err != nil {
return t, false, err return t, false, fmt.Errorf("scopeTableTarget: %w", err)
} }
return d.scopeTableTarget(append, t, name)
return d.scopeTableTarget(shouldAppend, t, name)
case reflect.Slice: case reflect.Slice:
t, err := scopeSlice(append, t) t, err := scopeSlice(shouldAppend, t)
if err != nil { if err != nil {
return t, false, err return t, false, fmt.Errorf("scopeTableTarget: %w", err)
} }
append = false shouldAppend = false
return d.scopeTableTarget(append, t, name)
return d.scopeTableTarget(shouldAppend, t, name)
case reflect.Array: case reflect.Array:
t, err := d.scopeArray(append, t) t, err := d.scopeArray(shouldAppend, t)
if err != nil { if err != nil {
return t, false, err return t, false, fmt.Errorf("scopeTableTarget: %w", err)
} }
append = false shouldAppend = false
return d.scopeTableTarget(append, t, name)
return d.scopeTableTarget(shouldAppend, t, name)
// Terminal kinds // Terminal kinds
case reflect.Struct: case reflect.Struct:
return scopeStruct(x, name) return scopeStruct(x, name)
case reflect.Map: case reflect.Map:
if x.IsNil() { if x.IsNil() {
t.set(reflect.MakeMap(x.Type())) err := t.set(reflect.MakeMap(x.Type()))
if err != nil {
return t, false, fmt.Errorf("scopeTableTarget: %w", err)
}
x = t.get() x = t.get()
} }
return scopeMap(x, name) return scopeMap(x, name)
default: default:
panic(fmt.Errorf("can't scope on a %s", x.Kind())) panic(fmt.Sprintf("can't scope on a %s", x.Kind()))
} }
} }
func scopeInterface(append bool, t target) (target, error) { func scopeInterface(shouldAppend bool, t target) (target, error) {
err := initInterface(append, t) err := initInterface(shouldAppend, t)
if err != nil { if err != nil {
return t, err return t, err
} }
return interfaceTarget{t}, nil return interfaceTarget{t}, nil
} }
@@ -388,6 +602,7 @@ func scopePtr(t target) (target, error) {
if err != nil { if err != nil {
return t, err return t, err
} }
return valueTarget(t.get().Elem()), nil return valueTarget(t.get().Elem()), nil
} }
@@ -396,13 +611,19 @@ func initPtr(t target) error {
if !x.IsNil() { if !x.IsNil() {
return nil return nil
} }
return t.set(reflect.New(x.Type().Elem()))
err := t.set(reflect.New(x.Type().Elem()))
if err != nil {
return fmt.Errorf("initPtr: %w", err)
}
return nil
} }
// initInterface makes sure that the interface pointed at by the target is not // initInterface makes sure that the interface pointed at by the target is not
// nil. // nil.
// Returns the target to the initialized value of the target. // Returns the target to the initialized value of the target.
func initInterface(append bool, t target) error { func initInterface(shouldAppend bool, t target) error {
x := t.get() x := t.get()
if x.Kind() != reflect.Interface { if x.Kind() != reflect.Interface {
@@ -414,54 +635,63 @@ func initInterface(append bool, t target) error {
} }
var newElement reflect.Value var newElement reflect.Value
if append { if shouldAppend {
newElement = reflect.MakeSlice(sliceInterfaceType, 0, 0) newElement = reflect.MakeSlice(sliceInterfaceType, 0, 0)
} else { } else {
newElement = reflect.MakeMap(mapStringInterfaceType) newElement = reflect.MakeMap(mapStringInterfaceType)
} }
err := t.set(newElement) err := t.set(newElement)
if err != nil { if err != nil {
return err return fmt.Errorf("initInterface: %w", err)
} }
return nil return nil
} }
func scopeSlice(append bool, t target) (target, error) { func scopeSlice(shouldAppend bool, t target) (target, error) {
v := t.get() v := t.get()
if append { if shouldAppend {
newElem := reflect.New(v.Type().Elem()) newElem := reflect.New(v.Type().Elem())
newSlice := reflect.Append(v, newElem.Elem()) newSlice := reflect.Append(v, newElem.Elem())
err := t.set(newSlice) err := t.set(newSlice)
if err != nil { if err != nil {
return t, err return t, fmt.Errorf("scopeSlice: %w", err)
} }
v = t.get() v = t.get()
} }
return valueTarget(v.Index(v.Len() - 1)), nil return valueTarget(v.Index(v.Len() - 1)), nil
} }
func (d *decoder) scopeArray(append bool, t target) (target, error) { var errScopeArrayNotEnoughSpace = errors.New("not enough space in the array")
func (d *decoder) scopeArray(shouldAppend bool, t target) (target, error) {
v := t.get() v := t.get()
idx := d.arrayIndex(append, v) idx := d.arrayIndex(shouldAppend, v)
if idx >= v.Len() { if idx >= v.Len() {
return nil, fmt.Errorf("not enough space in the array") return nil, errScopeArrayNotEnoughSpace
} }
return valueTarget(v.Index(idx)), nil return valueTarget(v.Index(idx)), nil
} }
var errScopeMapCannotConvertStringToKey = errors.New("cannot convert string into map key type")
func scopeMap(v reflect.Value, name string) (target, bool, error) { func scopeMap(v reflect.Value, name string) (target, bool, error) {
k := reflect.ValueOf(name) k := reflect.ValueOf(name)
keyType := v.Type().Key() keyType := v.Type().Key()
if !k.Type().AssignableTo(keyType) { if !k.Type().AssignableTo(keyType) {
if !k.Type().ConvertibleTo(keyType) { if !k.Type().ConvertibleTo(keyType) {
return nil, false, fmt.Errorf("cannot convert string into map key type %s", keyType) return nil, false, fmt.Errorf("scopeMap: %w %s", errScopeMapCannotConvertStringToKey, keyType)
} }
k = k.Convert(keyType) k = k.Convert(keyType)
} }
@@ -487,6 +717,7 @@ func (c *fieldPathsCache) get(t reflect.Type) (fieldPathsMap, bool) {
c.l.RLock() c.l.RLock()
paths, ok := c.m[t] paths, ok := c.m[t]
c.l.RUnlock() c.l.RUnlock()
return paths, ok return paths, ok
} }
@@ -502,13 +733,14 @@ var globalFieldPathsCache = fieldPathsCache{
} }
func scopeStruct(v reflect.Value, name string) (target, bool, error) { func scopeStruct(v reflect.Value, name string) (target, bool, error) {
//nolint:godox
// TODO: cache this, and reduce allocations // TODO: cache this, and reduce allocations
fieldPaths, ok := globalFieldPathsCache.get(v.Type()) fieldPaths, ok := globalFieldPathsCache.get(v.Type())
if !ok { if !ok {
fieldPaths = map[string][]int{} fieldPaths = map[string][]int{}
path := make([]int, 0, 16) path := make([]int, 0, 16)
var walk func(reflect.Value) var walk func(reflect.Value)
walk = func(v reflect.Value) { walk = func(v reflect.Value) {
t := v.Type() t := v.Type()
@@ -516,6 +748,7 @@ func scopeStruct(v reflect.Value, name string) (target, bool, error) {
l := len(path) l := len(path)
path = append(path, i) path = append(path, i)
f := t.Field(i) f := t.Field(i)
if f.Anonymous { if f.Anonymous {
walk(v.Field(i)) walk(v.Field(i))
} else if f.PkgPath == "" { } else if f.PkgPath == "" {
@@ -545,6 +778,7 @@ func scopeStruct(v reflect.Value, name string) (target, bool, error) {
if !ok { if !ok {
path, ok = fieldPaths[strings.ToLower(name)] path, ok = fieldPaths[strings.ToLower(name)]
} }
if !ok { if !ok {
return nil, false, nil return nil, false, nil
} }
+28 -1
View File
@@ -9,6 +9,8 @@ import (
) )
func TestStructTarget_Ensure(t *testing.T) { func TestStructTarget_Ensure(t *testing.T) {
t.Parallel()
examples := []struct { examples := []struct {
desc string desc string
input reflect.Value input reflect.Value
@@ -31,14 +33,23 @@ func TestStructTarget_Ensure(t *testing.T) {
test: func(v reflect.Value, err error) { test: func(v reflect.Value, err error) {
assert.NoError(t, err) assert.NoError(t, err)
require.False(t, v.IsNil()) require.False(t, v.IsNil())
s := v.Interface().([]string)
s, ok := v.Interface().([]string)
if !ok {
t.Errorf("interface %v should be castable into []string", s)
return
}
assert.Equal(t, []string{"foo"}, s) assert.Equal(t, []string{"foo"}, s)
}, },
}, },
} }
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()
d := decoder{} d := decoder{}
target, _, err := d.scopeTableTarget(false, valueTarget(e.input), e.name) target, _, err := d.scopeTableTarget(false, valueTarget(e.input), e.name)
require.NoError(t, err) require.NoError(t, err)
@@ -50,6 +61,8 @@ func TestStructTarget_Ensure(t *testing.T) {
} }
func TestStructTarget_SetString(t *testing.T) { func TestStructTarget_SetString(t *testing.T) {
t.Parallel()
str := "value" str := "value"
examples := []struct { examples := []struct {
@@ -86,7 +99,10 @@ func TestStructTarget_SetString(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()
d := decoder{} d := decoder{}
target, _, err := d.scopeTableTarget(false, valueTarget(e.input), e.name) target, _, err := d.scopeTableTarget(false, valueTarget(e.input), e.name)
require.NoError(t, err) require.NoError(t, err)
@@ -98,7 +114,11 @@ func TestStructTarget_SetString(t *testing.T) {
} }
func TestPushNew(t *testing.T) { func TestPushNew(t *testing.T) {
t.Parallel()
t.Run("slice of strings", func(t *testing.T) { t.Run("slice of strings", func(t *testing.T) {
t.Parallel()
type Doc struct { type Doc struct {
A []string A []string
} }
@@ -120,6 +140,8 @@ func TestPushNew(t *testing.T) {
}) })
t.Run("slice of interfaces", func(t *testing.T) { t.Run("slice of interfaces", func(t *testing.T) {
t.Parallel()
type Doc struct { type Doc struct {
A []interface{} A []interface{}
} }
@@ -142,6 +164,8 @@ func TestPushNew(t *testing.T) {
} }
func TestScope_Struct(t *testing.T) { func TestScope_Struct(t *testing.T) {
t.Parallel()
examples := []struct { examples := []struct {
desc string desc string
input reflect.Value input reflect.Value
@@ -167,7 +191,10 @@ func TestScope_Struct(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()
dec := decoder{} dec := decoder{}
x, found, err := dec.scopeTableTarget(false, valueTarget(e.input), e.name) x, found, err := dec.scopeTableTarget(false, valueTarget(e.input), e.name)
assert.Equal(t, e.found, found) assert.Equal(t, e.found, found)
+37 -15
View File
@@ -30,6 +30,7 @@ func testgenValid(t *testing.T, input string, jsonRef string) {
t.Logf("Input TOML:\n%s", input) t.Logf("Input TOML:\n%s", input)
doc := map[string]interface{}{} doc := map[string]interface{}{}
err := toml.Unmarshal([]byte(input), &doc) err := toml.Unmarshal([]byte(input), &doc)
if err != nil { if err != nil {
t.Fatalf("failed parsing toml: %s", err) t.Fatalf("failed parsing toml: %s", err)
@@ -49,25 +50,23 @@ func testgenValid(t *testing.T, input string, jsonRef string) {
require.Equal(t, refDoc, doc2) require.Equal(t, refDoc, doc2)
} }
type testGenDescNode struct {
Type string
Value interface{}
}
func testgenBuildRefDoc(jsonRef string) map[string]interface{} { func testgenBuildRefDoc(jsonRef string) map[string]interface{} {
descTree := map[string]interface{}{} descTree := map[string]interface{}{}
err := json.Unmarshal([]byte(jsonRef), &descTree) err := json.Unmarshal([]byte(jsonRef), &descTree)
if err != nil { if err != nil {
panic(fmt.Errorf("reference doc should be valid JSON: %s", err)) panic(fmt.Sprintf("reference doc should be valid JSON: %s", err))
} }
doc := testGenTranslateDesc(descTree) doc := testGenTranslateDesc(descTree)
if doc == nil { if doc == nil {
return map[string]interface{}{} return map[string]interface{}{}
} }
return doc.(map[string]interface{}) return doc.(map[string]interface{})
} }
//nolint:funlen,gocognit,cyclop
func testGenTranslateDesc(input interface{}) interface{} { func testGenTranslateDesc(input interface{}) interface{} {
a, ok := input.([]interface{}) a, ok := input.([]interface{})
if ok { if ok {
@@ -75,48 +74,69 @@ func testGenTranslateDesc(input interface{}) interface{} {
for i, v := range a { for i, v := range a {
xs[i] = testGenTranslateDesc(v) xs[i] = testGenTranslateDesc(v)
} }
return xs return xs
} }
d := input.(map[string]interface{}) d, ok := input.(map[string]interface{})
if !ok {
panic(fmt.Sprintf("input should be valid map[string]: %v", input))
}
var dtype string var (
var dvalue interface{} dtype string
dvalue interface{}
)
//nolint:nestif
if len(d) == 2 { if len(d) == 2 {
dtypeiface, ok := d["type"] dtypeiface, ok := d["type"]
if ok { if ok {
dvalue, ok = d["value"] dvalue, ok = d["value"]
if ok { if ok {
dtype = dtypeiface.(string) var okdt bool
dtype, okdt = dtypeiface.(string)
if !okdt {
panic(fmt.Sprintf("dtypeiface should be valid string: %v", dtypeiface))
}
switch dtype { switch dtype {
case "string": case "string":
return dvalue.(string) return dvalue.(string)
case "float": case "float":
v, err := strconv.ParseFloat(dvalue.(string), 64) v, err := strconv.ParseFloat(dvalue.(string), 64)
if err != nil { if err != nil {
panic(fmt.Errorf("invalid float '%s': %s", dvalue, err)) panic(fmt.Sprintf("invalid float '%s': %s", dvalue, err))
} }
return v return v
case "integer": case "integer":
v, err := strconv.ParseInt(dvalue.(string), 10, 64) v, err := strconv.ParseInt(dvalue.(string), 10, 64)
if err != nil { if err != nil {
panic(fmt.Errorf("invalid int '%s': %s", dvalue, err)) panic(fmt.Sprintf("invalid int '%s': %s", dvalue, err))
} }
return v return v
case "bool": case "bool":
return dvalue.(string) == "true" return dvalue.(string) == "true"
case "datetime": case "datetime":
dt, err := time.Parse("2006-01-02T15:04:05Z", dvalue.(string)) dt, err := time.Parse("2006-01-02T15:04:05Z", dvalue.(string))
if err != nil { if err != nil {
panic(fmt.Errorf("invalid datetime '%s': %s", dvalue, err)) panic(fmt.Sprintf("invalid datetime '%s': %s", dvalue, err))
} }
return dt return dt
case "array": case "array":
if dvalue == nil { if dvalue == nil {
return nil return nil
} }
a := dvalue.([]interface{})
a, oka := dvalue.([]interface{})
if !oka {
panic(fmt.Sprintf("a should be valid []interface{}: %v", a))
}
xs := make([]interface{}, len(a)) xs := make([]interface{}, len(a))
for i, v := range a { for i, v := range a {
@@ -125,7 +145,8 @@ func testGenTranslateDesc(input interface{}) interface{} {
return xs return xs
} }
panic(fmt.Errorf("unknown type: %s", dtype))
panic(fmt.Sprintf("unknown type: %s", dtype))
} }
} }
} }
@@ -134,5 +155,6 @@ func testGenTranslateDesc(input interface{}) interface{} {
for k, v := range d { for k, v := range d {
dest[k] = testGenTranslateDesc(v) dest[k] = testGenTranslateDesc(v)
} }
return dest return dest
} }
+150 -2
View File
@@ -6,26 +6,36 @@ import (
) )
func TestInvalidDatetimeMalformedNoLeads(t *testing.T) { func TestInvalidDatetimeMalformedNoLeads(t *testing.T) {
t.Parallel()
input := `no-leads = 1987-7-05T17:45:00Z` input := `no-leads = 1987-7-05T17:45:00Z`
testgenInvalid(t, input) testgenInvalid(t, input)
} }
func TestInvalidDatetimeMalformedNoSecs(t *testing.T) { func TestInvalidDatetimeMalformedNoSecs(t *testing.T) {
t.Parallel()
input := `no-secs = 1987-07-05T17:45Z` input := `no-secs = 1987-07-05T17:45Z`
testgenInvalid(t, input) testgenInvalid(t, input)
} }
func TestInvalidDatetimeMalformedNoT(t *testing.T) { func TestInvalidDatetimeMalformedNoT(t *testing.T) {
t.Parallel()
input := `no-t = 1987-07-0517:45:00Z` input := `no-t = 1987-07-0517:45:00Z`
testgenInvalid(t, input) testgenInvalid(t, input)
} }
func TestInvalidDatetimeMalformedWithMilli(t *testing.T) { func TestInvalidDatetimeMalformedWithMilli(t *testing.T) {
t.Parallel()
input := `with-milli = 1987-07-5T17:45:00.12Z` input := `with-milli = 1987-07-5T17:45:00.12Z`
testgenInvalid(t, input) testgenInvalid(t, input)
} }
func TestInvalidDuplicateKeyTable(t *testing.T) { func TestInvalidDuplicateKeyTable(t *testing.T) {
t.Parallel()
input := `[fruit] input := `[fruit]
type = "apple" type = "apple"
@@ -35,71 +45,97 @@ apple = "yes"`
} }
func TestInvalidDuplicateKeys(t *testing.T) { func TestInvalidDuplicateKeys(t *testing.T) {
t.Parallel()
input := `dupe = false input := `dupe = false
dupe = true` dupe = true`
testgenInvalid(t, input) testgenInvalid(t, input)
} }
func TestInvalidDuplicateTables(t *testing.T) { func TestInvalidDuplicateTables(t *testing.T) {
t.Parallel()
input := `[a] input := `[a]
[a]` [a]`
testgenInvalid(t, input) testgenInvalid(t, input)
} }
func TestInvalidEmptyImplicitTable(t *testing.T) { func TestInvalidEmptyImplicitTable(t *testing.T) {
t.Parallel()
input := `[naughty..naughty]` input := `[naughty..naughty]`
testgenInvalid(t, input) testgenInvalid(t, input)
} }
func TestInvalidEmptyTable(t *testing.T) { func TestInvalidEmptyTable(t *testing.T) {
t.Parallel()
input := `[]` input := `[]`
testgenInvalid(t, input) testgenInvalid(t, input)
} }
func TestInvalidFloatNoLeadingZero(t *testing.T) { func TestInvalidFloatNoLeadingZero(t *testing.T) {
t.Parallel()
input := `answer = .12345 input := `answer = .12345
neganswer = -.12345` neganswer = -.12345`
testgenInvalid(t, input) testgenInvalid(t, input)
} }
func TestInvalidFloatNoTrailingDigits(t *testing.T) { func TestInvalidFloatNoTrailingDigits(t *testing.T) {
t.Parallel()
input := `answer = 1. input := `answer = 1.
neganswer = -1.` neganswer = -1.`
testgenInvalid(t, input) testgenInvalid(t, input)
} }
func TestInvalidKeyEmpty(t *testing.T) { func TestInvalidKeyEmpty(t *testing.T) {
t.Parallel()
input := ` = 1` input := ` = 1`
testgenInvalid(t, input) testgenInvalid(t, input)
} }
func TestInvalidKeyHash(t *testing.T) { func TestInvalidKeyHash(t *testing.T) {
t.Parallel()
input := `a# = 1` input := `a# = 1`
testgenInvalid(t, input) testgenInvalid(t, input)
} }
func TestInvalidKeyNewline(t *testing.T) { func TestInvalidKeyNewline(t *testing.T) {
t.Parallel()
input := `a input := `a
= 1` = 1`
testgenInvalid(t, input) testgenInvalid(t, input)
} }
func TestInvalidKeyOpenBracket(t *testing.T) { func TestInvalidKeyOpenBracket(t *testing.T) {
t.Parallel()
input := `[abc = 1` input := `[abc = 1`
testgenInvalid(t, input) testgenInvalid(t, input)
} }
func TestInvalidKeySingleOpenBracket(t *testing.T) { func TestInvalidKeySingleOpenBracket(t *testing.T) {
t.Parallel()
input := `[` input := `[`
testgenInvalid(t, input) testgenInvalid(t, input)
} }
func TestInvalidKeySpace(t *testing.T) { func TestInvalidKeySpace(t *testing.T) {
t.Parallel()
input := `a b = 1` input := `a b = 1`
testgenInvalid(t, input) testgenInvalid(t, input)
} }
func TestInvalidKeyStartBracket(t *testing.T) { func TestInvalidKeyStartBracket(t *testing.T) {
t.Parallel()
input := `[a] input := `[a]
[xyz = 5 [xyz = 5
[b]` [b]`
@@ -107,31 +143,43 @@ func TestInvalidKeyStartBracket(t *testing.T) {
} }
func TestInvalidKeyTwoEquals(t *testing.T) { func TestInvalidKeyTwoEquals(t *testing.T) {
t.Parallel()
input := `key= = 1` input := `key= = 1`
testgenInvalid(t, input) testgenInvalid(t, input)
} }
func TestInvalidStringBadByteEscape(t *testing.T) { func TestInvalidStringBadByteEscape(t *testing.T) {
t.Parallel()
input := `naughty = "\xAg"` input := `naughty = "\xAg"`
testgenInvalid(t, input) testgenInvalid(t, input)
} }
func TestInvalidStringBadEscape(t *testing.T) { func TestInvalidStringBadEscape(t *testing.T) {
t.Parallel()
input := `invalid-escape = "This string has a bad \a escape character."` input := `invalid-escape = "This string has a bad \a escape character."`
testgenInvalid(t, input) testgenInvalid(t, input)
} }
func TestInvalidStringByteEscapes(t *testing.T) { func TestInvalidStringByteEscapes(t *testing.T) {
t.Parallel()
input := `answer = "\x33"` input := `answer = "\x33"`
testgenInvalid(t, input) testgenInvalid(t, input)
} }
func TestInvalidStringNoClose(t *testing.T) { func TestInvalidStringNoClose(t *testing.T) {
t.Parallel()
input := `no-ending-quote = "One time, at band camp` input := `no-ending-quote = "One time, at band camp`
testgenInvalid(t, input) testgenInvalid(t, input)
} }
func TestInvalidTableArrayImplicit(t *testing.T) { func TestInvalidTableArrayImplicit(t *testing.T) {
t.Parallel()
input := "# This test is a bit tricky. It should fail because the first use of\n" + input := "# This test is a bit tricky. It should fail because the first use of\n" +
"# `[[albums.songs]]` without first declaring `albums` implies that `albums`\n" + "# `[[albums.songs]]` without first declaring `albums` implies that `albums`\n" +
"# must be a table. The alternative would be quite weird. Namely, it wouldn't\n" + "# must be a table. The alternative would be quite weird. Namely, it wouldn't\n" +
@@ -150,46 +198,62 @@ func TestInvalidTableArrayImplicit(t *testing.T) {
} }
func TestInvalidTableArrayMalformedBracket(t *testing.T) { func TestInvalidTableArrayMalformedBracket(t *testing.T) {
t.Parallel()
input := `[[albums] input := `[[albums]
name = "Born to Run"` name = "Born to Run"`
testgenInvalid(t, input) testgenInvalid(t, input)
} }
func TestInvalidTableArrayMalformedEmpty(t *testing.T) { func TestInvalidTableArrayMalformedEmpty(t *testing.T) {
t.Parallel()
input := `[[]] input := `[[]]
name = "Born to Run"` name = "Born to Run"`
testgenInvalid(t, input) testgenInvalid(t, input)
} }
func TestInvalidTableEmpty(t *testing.T) { func TestInvalidTableEmpty(t *testing.T) {
t.Parallel()
input := `[]` input := `[]`
testgenInvalid(t, input) testgenInvalid(t, input)
} }
func TestInvalidTableNestedBracketsClose(t *testing.T) { func TestInvalidTableNestedBracketsClose(t *testing.T) {
t.Parallel()
input := `[a]b] input := `[a]b]
zyx = 42` zyx = 42`
testgenInvalid(t, input) testgenInvalid(t, input)
} }
func TestInvalidTableNestedBracketsOpen(t *testing.T) { func TestInvalidTableNestedBracketsOpen(t *testing.T) {
t.Parallel()
input := `[a[b] input := `[a[b]
zyx = 42` zyx = 42`
testgenInvalid(t, input) testgenInvalid(t, input)
} }
func TestInvalidTableWhitespace(t *testing.T) { func TestInvalidTableWhitespace(t *testing.T) {
t.Parallel()
input := `[invalid key]` input := `[invalid key]`
testgenInvalid(t, input) testgenInvalid(t, input)
} }
func TestInvalidTableWithPound(t *testing.T) { func TestInvalidTableWithPound(t *testing.T) {
t.Parallel()
input := `[key#group] input := `[key#group]
answer = 42` answer = 42`
testgenInvalid(t, input) testgenInvalid(t, input)
} }
func TestInvalidTextAfterArrayEntries(t *testing.T) { func TestInvalidTextAfterArrayEntries(t *testing.T) {
t.Parallel()
input := `array = [ input := `array = [
"Is there life after an array separator?", No "Is there life after an array separator?", No
"Entry" "Entry"
@@ -198,21 +262,29 @@ func TestInvalidTextAfterArrayEntries(t *testing.T) {
} }
func TestInvalidTextAfterInteger(t *testing.T) { func TestInvalidTextAfterInteger(t *testing.T) {
t.Parallel()
input := `answer = 42 the ultimate answer?` input := `answer = 42 the ultimate answer?`
testgenInvalid(t, input) testgenInvalid(t, input)
} }
func TestInvalidTextAfterString(t *testing.T) { func TestInvalidTextAfterString(t *testing.T) {
t.Parallel()
input := `string = "Is there life after strings?" No.` input := `string = "Is there life after strings?" No.`
testgenInvalid(t, input) testgenInvalid(t, input)
} }
func TestInvalidTextAfterTable(t *testing.T) { func TestInvalidTextAfterTable(t *testing.T) {
t.Parallel()
input := `[error] this shouldn't be here` input := `[error] this shouldn't be here`
testgenInvalid(t, input) testgenInvalid(t, input)
} }
func TestInvalidTextBeforeArraySeparator(t *testing.T) { func TestInvalidTextBeforeArraySeparator(t *testing.T) {
t.Parallel()
input := `array = [ input := `array = [
"Is there life before an array separator?" No, "Is there life before an array separator?" No,
"Entry" "Entry"
@@ -221,6 +293,8 @@ func TestInvalidTextBeforeArraySeparator(t *testing.T) {
} }
func TestInvalidTextInArray(t *testing.T) { func TestInvalidTextInArray(t *testing.T) {
t.Parallel()
input := `array = [ input := `array = [
"Entry 1", "Entry 1",
I don't belong, I don't belong,
@@ -230,6 +304,8 @@ func TestInvalidTextInArray(t *testing.T) {
} }
func TestValidArrayEmpty(t *testing.T) { func TestValidArrayEmpty(t *testing.T) {
t.Parallel()
input := `thevoid = [[[[[]]]]]` input := `thevoid = [[[[[]]]]]`
jsonRef := `{ jsonRef := `{
"thevoid": { "type": "array", "value": [ "thevoid": { "type": "array", "value": [
@@ -246,6 +322,8 @@ func TestValidArrayEmpty(t *testing.T) {
} }
func TestValidArrayNospaces(t *testing.T) { func TestValidArrayNospaces(t *testing.T) {
t.Parallel()
input := `ints = [1,2,3]` input := `ints = [1,2,3]`
jsonRef := `{ jsonRef := `{
"ints": { "ints": {
@@ -261,6 +339,8 @@ func TestValidArrayNospaces(t *testing.T) {
} }
func TestValidArraysHetergeneous(t *testing.T) { func TestValidArraysHetergeneous(t *testing.T) {
t.Parallel()
input := `mixed = [[1, 2], ["a", "b"], [1.1, 2.1]]` input := `mixed = [[1, 2], ["a", "b"], [1.1, 2.1]]`
jsonRef := `{ jsonRef := `{
"mixed": { "mixed": {
@@ -285,6 +365,8 @@ func TestValidArraysHetergeneous(t *testing.T) {
} }
func TestValidArraysNested(t *testing.T) { func TestValidArraysNested(t *testing.T) {
t.Parallel()
input := `nest = [["a"], ["b"]]` input := `nest = [["a"], ["b"]]`
jsonRef := `{ jsonRef := `{
"nest": { "nest": {
@@ -303,6 +385,8 @@ func TestValidArraysNested(t *testing.T) {
} }
func TestValidArrays(t *testing.T) { func TestValidArrays(t *testing.T) {
t.Parallel()
input := `ints = [1, 2, 3] input := `ints = [1, 2, 3]
floats = [1.1, 2.1, 3.1] floats = [1.1, 2.1, 3.1]
strings = ["a", "b", "c"] strings = ["a", "b", "c"]
@@ -349,6 +433,8 @@ dates = [
} }
func TestValidBool(t *testing.T) { func TestValidBool(t *testing.T) {
t.Parallel()
input := `t = true input := `t = true
f = false` f = false`
jsonRef := `{ jsonRef := `{
@@ -359,6 +445,8 @@ f = false`
} }
func TestValidCommentsEverywhere(t *testing.T) { func TestValidCommentsEverywhere(t *testing.T) {
t.Parallel()
input := `# Top comment. input := `# Top comment.
# Top comment. # Top comment.
# Top comment. # Top comment.
@@ -368,7 +456,7 @@ func TestValidCommentsEverywhere(t *testing.T) {
[group] # Comment [group] # Comment
answer = 42 # Comment answer = 42 # Comment
# no-extraneous-keys-please = 999 # no-extraneous-keys-please = 999
# Inbetween comment. # In between comment.
more = [ # Comment more = [ # Comment
# What about multiple # comments? # What about multiple # comments?
# Can you handle it? # Can you handle it?
@@ -399,6 +487,8 @@ more = [ # Comment
} }
func TestValidDatetime(t *testing.T) { func TestValidDatetime(t *testing.T) {
t.Parallel()
input := `bestdayever = 1987-07-05T17:45:00Z` input := `bestdayever = 1987-07-05T17:45:00Z`
jsonRef := `{ jsonRef := `{
"bestdayever": {"type": "datetime", "value": "1987-07-05T17:45:00Z"} "bestdayever": {"type": "datetime", "value": "1987-07-05T17:45:00Z"}
@@ -407,12 +497,16 @@ func TestValidDatetime(t *testing.T) {
} }
func TestValidEmpty(t *testing.T) { func TestValidEmpty(t *testing.T) {
t.Parallel()
input := `` input := ``
jsonRef := `{}` jsonRef := `{}`
testgenValid(t, input, jsonRef) testgenValid(t, input, jsonRef)
} }
func TestValidExample(t *testing.T) { func TestValidExample(t *testing.T) {
t.Parallel()
input := `best-day-ever = 1987-07-05T17:45:00Z input := `best-day-ever = 1987-07-05T17:45:00Z
[numtheory] [numtheory]
@@ -436,6 +530,8 @@ perfection = [6, 28, 496]`
} }
func TestValidFloat(t *testing.T) { func TestValidFloat(t *testing.T) {
t.Parallel()
input := `pi = 3.14 input := `pi = 3.14
negpi = -3.14` negpi = -3.14`
jsonRef := `{ jsonRef := `{
@@ -446,6 +542,8 @@ negpi = -3.14`
} }
func TestValidImplicitAndExplicitAfter(t *testing.T) { func TestValidImplicitAndExplicitAfter(t *testing.T) {
t.Parallel()
input := `[a.b.c] input := `[a.b.c]
answer = 42 answer = 42
@@ -465,6 +563,8 @@ better = 43`
} }
func TestValidImplicitAndExplicitBefore(t *testing.T) { func TestValidImplicitAndExplicitBefore(t *testing.T) {
t.Parallel()
input := `[a] input := `[a]
better = 43 better = 43
@@ -484,6 +584,8 @@ answer = 42`
} }
func TestValidImplicitGroups(t *testing.T) { func TestValidImplicitGroups(t *testing.T) {
t.Parallel()
input := `[a.b.c] input := `[a.b.c]
answer = 42` answer = 42`
jsonRef := `{ jsonRef := `{
@@ -499,6 +601,8 @@ answer = 42`
} }
func TestValidInteger(t *testing.T) { func TestValidInteger(t *testing.T) {
t.Parallel()
input := `answer = 42 input := `answer = 42
neganswer = -42` neganswer = -42`
jsonRef := `{ jsonRef := `{
@@ -509,6 +613,8 @@ neganswer = -42`
} }
func TestValidKeyEqualsNospace(t *testing.T) { func TestValidKeyEqualsNospace(t *testing.T) {
t.Parallel()
input := `answer=42` input := `answer=42`
jsonRef := `{ jsonRef := `{
"answer": {"type": "integer", "value": "42"} "answer": {"type": "integer", "value": "42"}
@@ -517,6 +623,8 @@ func TestValidKeyEqualsNospace(t *testing.T) {
} }
func TestValidKeySpace(t *testing.T) { func TestValidKeySpace(t *testing.T) {
t.Parallel()
input := `"a b" = 1` input := `"a b" = 1`
jsonRef := `{ jsonRef := `{
"a b": {"type": "integer", "value": "1"} "a b": {"type": "integer", "value": "1"}
@@ -525,6 +633,8 @@ func TestValidKeySpace(t *testing.T) {
} }
func TestValidKeySpecialChars(t *testing.T) { func TestValidKeySpecialChars(t *testing.T) {
t.Parallel()
input := "\"~!@$^&*()_+-`1234567890[]|/?><.,;:'\" = 1\n" input := "\"~!@$^&*()_+-`1234567890[]|/?><.,;:'\" = 1\n"
jsonRef := "{\n" + jsonRef := "{\n" +
" \"~!@$^&*()_+-`1234567890[]|/?><.,;:'\": {\n" + " \"~!@$^&*()_+-`1234567890[]|/?><.,;:'\": {\n" +
@@ -535,6 +645,8 @@ func TestValidKeySpecialChars(t *testing.T) {
} }
func TestValidLongFloat(t *testing.T) { func TestValidLongFloat(t *testing.T) {
t.Parallel()
input := `longpi = 3.141592653589793 input := `longpi = 3.141592653589793
neglongpi = -3.141592653589793` neglongpi = -3.141592653589793`
jsonRef := `{ jsonRef := `{
@@ -545,6 +657,8 @@ neglongpi = -3.141592653589793`
} }
func TestValidLongInteger(t *testing.T) { func TestValidLongInteger(t *testing.T) {
t.Parallel()
input := `answer = 9223372036854775807 input := `answer = 9223372036854775807
neganswer = -9223372036854775808` neganswer = -9223372036854775808`
jsonRef := `{ jsonRef := `{
@@ -555,6 +669,8 @@ neganswer = -9223372036854775808`
} }
func TestValidMultilineString(t *testing.T) { func TestValidMultilineString(t *testing.T) {
t.Parallel()
input := `multiline_empty_one = """""" input := `multiline_empty_one = """"""
multiline_empty_two = """ multiline_empty_two = """
""" """
@@ -612,6 +728,8 @@ equivalent_three = """\
} }
func TestValidRawMultilineString(t *testing.T) { func TestValidRawMultilineString(t *testing.T) {
t.Parallel()
input := `oneline = '''This string has a ' quote character.''' input := `oneline = '''This string has a ' quote character.'''
firstnl = ''' firstnl = '''
This string has a ' quote character.''' This string has a ' quote character.'''
@@ -639,6 +757,8 @@ in it.'''`
} }
func TestValidRawString(t *testing.T) { func TestValidRawString(t *testing.T) {
t.Parallel()
input := `backspace = 'This string has a \b backspace character.' input := `backspace = 'This string has a \b backspace character.'
tab = 'This string has a \t tab character.' tab = 'This string has a \t tab character.'
newline = 'This string has a \n new line character.' newline = 'This string has a \n new line character.'
@@ -680,6 +800,8 @@ backslash = 'This string has a \\ backslash character.'`
} }
func TestValidStringEmpty(t *testing.T) { func TestValidStringEmpty(t *testing.T) {
t.Parallel()
input := `answer = ""` input := `answer = ""`
jsonRef := `{ jsonRef := `{
"answer": { "answer": {
@@ -691,6 +813,8 @@ func TestValidStringEmpty(t *testing.T) {
} }
func TestValidStringEscapes(t *testing.T) { func TestValidStringEscapes(t *testing.T) {
t.Parallel()
input := `backspace = "This string has a \b backspace character." input := `backspace = "This string has a \b backspace character."
tab = "This string has a \t tab character." tab = "This string has a \t tab character."
newline = "This string has a \n new line character." newline = "This string has a \n new line character."
@@ -752,6 +876,8 @@ notunicode4 = "This string does not have a unicode \\\u0075 escape."`
} }
func TestValidStringSimple(t *testing.T) { func TestValidStringSimple(t *testing.T) {
t.Parallel()
input := `answer = "You are not drinking enough whisky."` input := `answer = "You are not drinking enough whisky."`
jsonRef := `{ jsonRef := `{
"answer": { "answer": {
@@ -763,6 +889,8 @@ func TestValidStringSimple(t *testing.T) {
} }
func TestValidStringWithPound(t *testing.T) { func TestValidStringWithPound(t *testing.T) {
t.Parallel()
input := `pound = "We see no # comments here." input := `pound = "We see no # comments here."
poundcomment = "But there are # some comments here." # Did I # mess you up?` poundcomment = "But there are # some comments here." # Did I # mess you up?`
jsonRef := `{ jsonRef := `{
@@ -776,6 +904,8 @@ poundcomment = "But there are # some comments here." # Did I # mess you up?`
} }
func TestValidTableArrayImplicit(t *testing.T) { func TestValidTableArrayImplicit(t *testing.T) {
t.Parallel()
input := `[[albums.songs]] input := `[[albums.songs]]
name = "Glory Days"` name = "Glory Days"`
jsonRef := `{ jsonRef := `{
@@ -789,6 +919,8 @@ name = "Glory Days"`
} }
func TestValidTableArrayMany(t *testing.T) { func TestValidTableArrayMany(t *testing.T) {
t.Parallel()
input := `[[people]] input := `[[people]]
first_name = "Bruce" first_name = "Bruce"
last_name = "Springsteen" last_name = "Springsteen"
@@ -820,6 +952,8 @@ last_name = "Seger"`
} }
func TestValidTableArrayNest(t *testing.T) { func TestValidTableArrayNest(t *testing.T) {
t.Parallel()
input := `[[albums]] input := `[[albums]]
name = "Born to Run" name = "Born to Run"
@@ -831,7 +965,7 @@ name = "Born to Run"
[[albums]] [[albums]]
name = "Born in the USA" name = "Born in the USA"
[[albums.songs]] [[albums.songs]]
name = "Glory Days" name = "Glory Days"
@@ -859,6 +993,8 @@ name = "Born in the USA"
} }
func TestValidTableArrayOne(t *testing.T) { func TestValidTableArrayOne(t *testing.T) {
t.Parallel()
input := `[[people]] input := `[[people]]
first_name = "Bruce" first_name = "Bruce"
last_name = "Springsteen"` last_name = "Springsteen"`
@@ -874,6 +1010,8 @@ last_name = "Springsteen"`
} }
func TestValidTableEmpty(t *testing.T) { func TestValidTableEmpty(t *testing.T) {
t.Parallel()
input := `[a]` input := `[a]`
jsonRef := `{ jsonRef := `{
"a": {} "a": {}
@@ -882,6 +1020,8 @@ func TestValidTableEmpty(t *testing.T) {
} }
func TestValidTableSubEmpty(t *testing.T) { func TestValidTableSubEmpty(t *testing.T) {
t.Parallel()
input := `[a] input := `[a]
[a.b]` [a.b]`
jsonRef := `{ jsonRef := `{
@@ -891,6 +1031,8 @@ func TestValidTableSubEmpty(t *testing.T) {
} }
func TestValidTableWhitespace(t *testing.T) { func TestValidTableWhitespace(t *testing.T) {
t.Parallel()
input := `["valid key"]` input := `["valid key"]`
jsonRef := `{ jsonRef := `{
"valid key": {} "valid key": {}
@@ -899,6 +1041,8 @@ func TestValidTableWhitespace(t *testing.T) {
} }
func TestValidTableWithPound(t *testing.T) { func TestValidTableWithPound(t *testing.T) {
t.Parallel()
input := `["key#group"] input := `["key#group"]
answer = 42` answer = 42`
jsonRef := `{ jsonRef := `{
@@ -910,6 +1054,8 @@ answer = 42`
} }
func TestValidUnicodeEscape(t *testing.T) { func TestValidUnicodeEscape(t *testing.T) {
t.Parallel()
input := `answer4 = "\u03B4" input := `answer4 = "\u03B4"
answer8 = "\U000003B4"` answer8 = "\U000003B4"`
jsonRef := `{ jsonRef := `{
@@ -920,6 +1066,8 @@ answer8 = "\U000003B4"`
} }
func TestValidUnicodeLiteral(t *testing.T) { func TestValidUnicodeLiteral(t *testing.T) {
t.Parallel()
input := `answer = "δ"` input := `answer = "δ"`
jsonRef := `{ jsonRef := `{
"answer": {"type": "string", "value": "δ"} "answer": {"type": "string", "value": "δ"}
+46 -10
View File
@@ -81,7 +81,7 @@ type decoder struct {
strict strict strict strict
} }
func (d *decoder) arrayIndex(append bool, v reflect.Value) int { func (d *decoder) arrayIndex(shouldAppend bool, v reflect.Value) int {
if d.arrayIndexes == nil { if d.arrayIndexes == nil {
d.arrayIndexes = make(map[reflect.Value]int, 1) d.arrayIndexes = make(map[reflect.Value]int, 1)
} }
@@ -90,7 +90,7 @@ func (d *decoder) arrayIndex(append bool, v reflect.Value) int {
if !ok { if !ok {
d.arrayIndexes[v] = 0 d.arrayIndexes[v] = 0
} else if append { } else if shouldAppend {
idx++ idx++
d.arrayIndexes[v] = idx d.arrayIndexes[v] = idx
} }
@@ -173,6 +173,7 @@ func (d *decoder) fromParser(p *parser, v interface{}) error {
found = true found = true
case ast.Table: case ast.Table:
d.strict.EnterTable(node) d.strict.EnterTable(node)
current, found, err = d.scopeWithKey(root, node.Key()) current, found, err = d.scopeWithKey(root, node.Key())
if err == nil && found { if err == nil && found {
// In case this table points to an interface, // In case this table points to an interface,
@@ -180,7 +181,10 @@ func (d *decoder) fromParser(p *parser, v interface{}) error {
// looks like a table. Otherwise the information // looks like a table. Otherwise the information
// of a table is lost, and marshal cannot do the // of a table is lost, and marshal cannot do the
// round trip. // round trip.
ensureMapIfInterface(current) err := ensureMapIfInterface(current)
if err != nil {
panic(fmt.Sprintf("ensureMapIfInterface: %s", err))
}
} }
case ast.ArrayTable: case ast.ArrayTable:
d.strict.EnterArrayTable(node) d.strict.EnterArrayTable(node)
@@ -305,6 +309,7 @@ func (d *decoder) unmarshalKeyValue(x target, node ast.Node) error {
// A struct in the path was not found. Skip this value. // A struct in the path was not found. Skip this value.
if !found { if !found {
d.strict.MissingField(node) d.strict.MissingField(node)
return nil return nil
} }
@@ -327,11 +332,21 @@ 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) err := v.Interface().(encoding.TextUnmarshaler).UnmarshalText(node.Data)
if err != nil {
return false, fmt.Errorf("tryTextUnmarshaler: %w", err)
}
return true, nil
} }
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) err := v.Addr().Interface().(encoding.TextUnmarshaler).UnmarshalText(node.Data)
if err != nil {
return false, fmt.Errorf("tryTextUnmarshaler: %w", err)
}
return true, nil
} }
return false, nil return false, nil
@@ -345,7 +360,7 @@ func (d *decoder) unmarshalValue(x target, node ast.Node) error {
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 fmt.Errorf("unmarshalValue: %w", err)
} }
v = x.get() v = x.get()
@@ -423,14 +438,25 @@ func unmarshalDateTime(x target, node ast.Node) error {
func setLocalDateTime(x target, v LocalDateTime) error { func setLocalDateTime(x target, v LocalDateTime) error {
if x.get().Type() == timeType { if x.get().Type() == timeType {
cast := v.In(time.Local) cast := v.In(time.Local)
return setDateTime(x, cast) return setDateTime(x, cast)
} }
return x.set(reflect.ValueOf(v)) err := x.set(reflect.ValueOf(v))
if err != nil {
return fmt.Errorf("setLocalDateTime: %w", err)
}
return nil
} }
func setDateTime(x target, v time.Time) error { func setDateTime(x target, v time.Time) error {
return x.set(reflect.ValueOf(v)) err := x.set(reflect.ValueOf(v))
if err != nil {
return fmt.Errorf("setDateTime: %w", err)
}
return nil
} }
var timeType = reflect.TypeOf(time.Time{}) var timeType = reflect.TypeOf(time.Time{})
@@ -438,10 +464,16 @@ var timeType = reflect.TypeOf(time.Time{})
func setDate(x target, v LocalDate) error { func setDate(x target, v LocalDate) error {
if x.get().Type() == timeType { if x.get().Type() == timeType {
cast := v.In(time.Local) cast := v.In(time.Local)
return setDateTime(x, cast) return setDateTime(x, cast)
} }
return x.set(reflect.ValueOf(v)) err := x.set(reflect.ValueOf(v))
if err != nil {
return fmt.Errorf("setDate: %w", err)
}
return nil
} }
func unmarshalString(x target, node ast.Node) error { func unmarshalString(x target, node ast.Node) error {
@@ -470,6 +502,7 @@ func unmarshalInteger(x target, node ast.Node) error {
func unmarshalFloat(x target, node ast.Node) error { func unmarshalFloat(x target, node ast.Node) error {
assertNode(ast.Float, node) assertNode(ast.Float, node)
v, err := parseFloat(node.Data) v, err := parseFloat(node.Data)
if err != nil { if err != nil {
return err return err
@@ -481,7 +514,10 @@ func unmarshalFloat(x target, node ast.Node) error {
func (d *decoder) unmarshalInlineTable(x target, node ast.Node) error { func (d *decoder) unmarshalInlineTable(x target, node ast.Node) error {
assertNode(ast.InlineTable, node) assertNode(ast.InlineTable, node)
ensureMapIfInterface(x) err := ensureMapIfInterface(x)
if err != nil {
return fmt.Errorf("unmarshalInlineTable: %w", err)
}
it := node.Children() it := node.Children()
for it.Next() { for it.Next() {
+15
View File
@@ -838,6 +838,7 @@ func (i *Integer484) UnmarshalText(data []byte) error {
return fmt.Errorf("UnmarshalText: %w", err) return fmt.Errorf("UnmarshalText: %w", err)
} }
i.Value = conv i.Value = conv
return nil return nil
} }
@@ -846,6 +847,8 @@ type Config484 struct {
} }
func TestIssue484(t *testing.T) { func TestIssue484(t *testing.T) {
t.Parallel()
raw := []byte(`integers = ["1","2","3","100"]`) raw := []byte(`integers = ["1","2","3","100"]`)
var cfg Config484 var cfg Config484
@@ -866,6 +869,8 @@ func (m Map458) A(s string) Slice458 {
} }
func TestIssue458(t *testing.T) { func TestIssue458(t *testing.T) {
t.Parallel()
s := []byte(`[[package]] s := []byte(`[[package]]
dependencies = ["regex"] dependencies = ["regex"]
name = "decode" name = "decode"
@@ -885,6 +890,8 @@ version = "0.1.0"`)
} }
func TestIssue252(t *testing.T) { func TestIssue252(t *testing.T) {
t.Parallel()
type config struct { type config struct {
Val1 string `toml:"val1"` Val1 string `toml:"val1"`
Val2 string `toml:"val2"` Val2 string `toml:"val2"`
@@ -905,6 +912,8 @@ val1 = "test1"
} }
func TestIssue494(t *testing.T) { func TestIssue494(t *testing.T) {
t.Parallel()
data := ` data := `
foo = 2021-04-08 foo = 2021-04-08
bar = 2021-04-08 bar = 2021-04-08
@@ -920,6 +929,8 @@ bar = 2021-04-08
} }
func TestIssue507(t *testing.T) { func TestIssue507(t *testing.T) {
t.Parallel()
data := []byte{'0', '=', '\n', '0', 'a', 'm', 'e'} data := []byte{'0', '=', '\n', '0', 'a', 'm', 'e'}
m := map[string]interface{}{} m := map[string]interface{}{}
err := toml.Unmarshal(data, &m) err := toml.Unmarshal(data, &m)
@@ -1094,6 +1105,8 @@ func TestLocalDateTime(t *testing.T) {
} }
func TestIssue287(t *testing.T) { func TestIssue287(t *testing.T) {
t.Parallel()
b := `y=[[{}]]` b := `y=[[{}]]`
v := map[string]interface{}{} v := map[string]interface{}{}
err := toml.Unmarshal([]byte(b), &v) err := toml.Unmarshal([]byte(b), &v)
@@ -1110,6 +1123,8 @@ func TestIssue287(t *testing.T) {
} }
func TestIssue508(t *testing.T) { func TestIssue508(t *testing.T) {
t.Parallel()
type head struct { type head struct {
Title string `toml:"title"` Title string `toml:"title"`
} }