golangci-lint (#530)
This commit is contained in:
+1
-1
@@ -79,6 +79,6 @@ enable = [
|
|||||||
"varcheck",
|
"varcheck",
|
||||||
"wastedassign",
|
"wastedassign",
|
||||||
"whitespace",
|
"whitespace",
|
||||||
"wrapcheck",
|
# "wrapcheck",
|
||||||
"wsl"
|
"wsl"
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -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)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
@@ -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
@@ -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)
|
||||||
|
|||||||
@@ -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
@@ -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
@@ -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() {
|
||||||
|
|||||||
@@ -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"`
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user