wip
This commit is contained in:
@@ -430,29 +430,6 @@ title = "Placeholder"
|
|||||||
[map]
|
[map]
|
||||||
`)
|
`)
|
||||||
|
|
||||||
type emptyMarshalTestStruct2 struct {
|
|
||||||
Title string `toml:"title"`
|
|
||||||
Bool bool `toml:"bool,omitempty"`
|
|
||||||
Int int `toml:"int, omitempty"`
|
|
||||||
String string `toml:"string,omitempty "`
|
|
||||||
StringList []string `toml:"stringlist,omitempty"`
|
|
||||||
Ptr *basicMarshalTestStruct `toml:"ptr,omitempty"`
|
|
||||||
Map map[string]string `toml:"map,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
var emptyTestData2 = emptyMarshalTestStruct2{
|
|
||||||
Title: "Placeholder",
|
|
||||||
Bool: false,
|
|
||||||
Int: 0,
|
|
||||||
String: "",
|
|
||||||
StringList: []string{},
|
|
||||||
Ptr: nil,
|
|
||||||
Map: map[string]string{},
|
|
||||||
}
|
|
||||||
|
|
||||||
var emptyTestToml2 = []byte(`title = "Placeholder"
|
|
||||||
`)
|
|
||||||
|
|
||||||
func TestEmptytomlUnmarshal(t *testing.T) {
|
func TestEmptytomlUnmarshal(t *testing.T) {
|
||||||
type emptyMarshalTestStruct struct {
|
type emptyMarshalTestStruct struct {
|
||||||
Title string `toml:"title"`
|
Title string `toml:"title"`
|
||||||
@@ -481,15 +458,32 @@ func TestEmptytomlUnmarshal(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestEmptyUnmarshalOmit(t *testing.T) {
|
func TestEmptyUnmarshalOmit(t *testing.T) {
|
||||||
|
t.Skipf("Have not figured yet if omitempty is a good idea")
|
||||||
|
|
||||||
|
type emptyMarshalTestStruct2 struct {
|
||||||
|
Title string `toml:"title"`
|
||||||
|
Bool bool `toml:"bool,omitempty"`
|
||||||
|
Int int `toml:"int, omitempty"`
|
||||||
|
String string `toml:"string,omitempty "`
|
||||||
|
StringList []string `toml:"stringlist,omitempty"`
|
||||||
|
Ptr *basicMarshalTestStruct `toml:"ptr,omitempty"`
|
||||||
|
Map map[string]string `toml:"map,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
var emptyTestData2 = emptyMarshalTestStruct2{
|
||||||
|
Title: "Placeholder",
|
||||||
|
Bool: false,
|
||||||
|
Int: 0,
|
||||||
|
String: "",
|
||||||
|
StringList: []string{},
|
||||||
|
Ptr: nil,
|
||||||
|
Map: map[string]string{},
|
||||||
|
}
|
||||||
|
|
||||||
result := emptyMarshalTestStruct2{}
|
result := emptyMarshalTestStruct2{}
|
||||||
err := toml.Unmarshal(emptyTestToml, &result)
|
err := toml.Unmarshal(emptyTestToml, &result)
|
||||||
expected := emptyTestData2
|
require.NoError(t, err)
|
||||||
if err != nil {
|
assert.Equal(t, emptyTestData2, result)
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
if !reflect.DeepEqual(result, expected) {
|
|
||||||
t.Errorf("Bad empty omit unmarshal: expected %v, got %v", expected, result)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type pointerMarshalTestStruct struct {
|
type pointerMarshalTestStruct struct {
|
||||||
@@ -532,15 +526,11 @@ Str = "Hello"
|
|||||||
`)
|
`)
|
||||||
|
|
||||||
func TestPointerUnmarshal(t *testing.T) {
|
func TestPointerUnmarshal(t *testing.T) {
|
||||||
|
t.Log("TOML data:", string(pointerTestToml))
|
||||||
result := pointerMarshalTestStruct{}
|
result := pointerMarshalTestStruct{}
|
||||||
err := toml.Unmarshal(pointerTestToml, &result)
|
err := toml.Unmarshal(pointerTestToml, &result)
|
||||||
expected := pointerTestData
|
require.NoError(t, err)
|
||||||
if err != nil {
|
assert.Equal(t, pointerTestData, result)
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
if !reflect.DeepEqual(result, expected) {
|
|
||||||
t.Errorf("Bad pointer unmarshal: expected %v, got %v", expected, result)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestUnmarshalTypeMismatch(t *testing.T) {
|
func TestUnmarshalTypeMismatch(t *testing.T) {
|
||||||
|
|||||||
@@ -37,6 +37,14 @@ func (v valueTarget) get() reflect.Value {
|
|||||||
|
|
||||||
func (v valueTarget) set(value reflect.Value) error {
|
func (v valueTarget) set(value reflect.Value) error {
|
||||||
rv := reflect.Value(v)
|
rv := reflect.Value(v)
|
||||||
|
|
||||||
|
// value is guaranteed to be a pointer
|
||||||
|
|
||||||
|
if rv.Kind() != reflect.Ptr {
|
||||||
|
// TODO: check value is nil?
|
||||||
|
value = value.Elem()
|
||||||
|
}
|
||||||
|
|
||||||
err := isAssignable(rv.Type(), value)
|
err := isAssignable(rv.Type(), value)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -59,6 +67,13 @@ func (v mapTarget) get() reflect.Value {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (v mapTarget) set(value reflect.Value) error {
|
func (v mapTarget) set(value reflect.Value) error {
|
||||||
|
// value is guaranteed to be a pointer
|
||||||
|
|
||||||
|
if v.m.Type().Elem().Kind() != reflect.Ptr {
|
||||||
|
// TODO: check value is nil?
|
||||||
|
value = value.Elem()
|
||||||
|
}
|
||||||
|
|
||||||
err := isAssignable(v.m.Type().Elem(), value)
|
err := isAssignable(v.m.Type().Elem(), value)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -486,6 +501,7 @@ func (b *Builder) SetInt(n int64) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (b *Builder) Set(v reflect.Value) error {
|
func (b *Builder) Set(v reflect.Value) error {
|
||||||
|
assertPtr(v)
|
||||||
t := b.top()
|
t := b.top()
|
||||||
return t.set(v)
|
return t.set(v)
|
||||||
}
|
}
|
||||||
@@ -494,8 +510,16 @@ func (b *Builder) Set(v reflect.Value) error {
|
|||||||
func (b *Builder) EnsureSlice() error {
|
func (b *Builder) EnsureSlice() error {
|
||||||
t := b.top()
|
t := b.top()
|
||||||
v := t.get()
|
v := t.get()
|
||||||
|
|
||||||
|
if v.Kind() == reflect.Ptr {
|
||||||
|
if v.IsNil() {
|
||||||
|
v.Set(reflect.New(v.Type().Elem()))
|
||||||
|
}
|
||||||
|
v = v.Elem()
|
||||||
|
}
|
||||||
|
|
||||||
if v.Kind() != reflect.Slice {
|
if v.Kind() != reflect.Slice {
|
||||||
return IncorrectKindError{Actual: v.Kind(), Expected: reflect.Slice}
|
return IncorrectKindError{Actual: v.Kind(), Expected: []reflect.Kind{reflect.Slice}}
|
||||||
}
|
}
|
||||||
|
|
||||||
if v.IsNil() {
|
if v.IsNil() {
|
||||||
@@ -505,6 +529,27 @@ func (b *Builder) EnsureSlice() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// EnsureStructOrMap makes sure that the cursor points to an initialized
|
||||||
|
// struct or map.
|
||||||
|
func (b *Builder) EnsureStructOrMap() error {
|
||||||
|
t := b.top()
|
||||||
|
v := t.get()
|
||||||
|
|
||||||
|
switch v.Kind() {
|
||||||
|
case reflect.Struct:
|
||||||
|
case reflect.Map:
|
||||||
|
if v.IsNil() {
|
||||||
|
return t.set(reflect.MakeMap(v.Type()))
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return IncorrectKindError{
|
||||||
|
Actual: v.Kind(),
|
||||||
|
Expected: []reflect.Kind{reflect.Struct, reflect.Map},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func checkKindInt(rt reflect.Type) error {
|
func checkKindInt(rt reflect.Type) error {
|
||||||
switch rt.Kind() {
|
switch rt.Kind() {
|
||||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||||
@@ -513,7 +558,7 @@ func checkKindInt(rt reflect.Type) error {
|
|||||||
|
|
||||||
return IncorrectKindError{
|
return IncorrectKindError{
|
||||||
Actual: rt.Kind(),
|
Actual: rt.Kind(),
|
||||||
Expected: reflect.Int,
|
Expected: []reflect.Kind{reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -525,7 +570,7 @@ func checkKindFloat(rt reflect.Type) error {
|
|||||||
|
|
||||||
return IncorrectKindError{
|
return IncorrectKindError{
|
||||||
Actual: rt.Kind(),
|
Actual: rt.Kind(),
|
||||||
Expected: reflect.Float64,
|
Expected: []reflect.Kind{reflect.Float64},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -533,7 +578,7 @@ func checkKind(rt reflect.Type, expected reflect.Kind) error {
|
|||||||
if rt.Kind() != expected {
|
if rt.Kind() != expected {
|
||||||
return IncorrectKindError{
|
return IncorrectKindError{
|
||||||
Actual: rt.Kind(),
|
Actual: rt.Kind(),
|
||||||
Expected: expected,
|
Expected: []reflect.Kind{expected},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
@@ -541,11 +586,14 @@ func checkKind(rt reflect.Type, expected reflect.Kind) error {
|
|||||||
|
|
||||||
type IncorrectKindError struct {
|
type IncorrectKindError struct {
|
||||||
Actual reflect.Kind
|
Actual reflect.Kind
|
||||||
Expected reflect.Kind
|
Expected []reflect.Kind
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e IncorrectKindError) Error() string {
|
func (e IncorrectKindError) Error() string {
|
||||||
return fmt.Sprintf("incorrect kind: expected '%s', got '%s'", e.Expected, e.Actual)
|
if len(e.Expected) < 2 {
|
||||||
|
return fmt.Sprintf("incorrect kind: expected '%s', got '%s'", e.Expected[0], e.Actual)
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("incorrect kind: expected any of '%s', got '%s'", e.Expected, e.Actual)
|
||||||
}
|
}
|
||||||
|
|
||||||
type FieldNotFoundError struct {
|
type FieldNotFoundError struct {
|
||||||
|
|||||||
@@ -140,7 +140,7 @@ func TestSliceNewElemNested(t *testing.T) {
|
|||||||
func TestIncorrectKindError(t *testing.T) {
|
func TestIncorrectKindError(t *testing.T) {
|
||||||
err := reflectbuild.IncorrectKindError{
|
err := reflectbuild.IncorrectKindError{
|
||||||
Actual: reflect.String,
|
Actual: reflect.String,
|
||||||
Expected: reflect.Struct,
|
Expected: []reflect.Kind{reflect.Struct},
|
||||||
}
|
}
|
||||||
assert.NotEmpty(t, err.Error())
|
assert.NotEmpty(t, err.Error())
|
||||||
}
|
}
|
||||||
|
|||||||
+12
-5
@@ -45,6 +45,10 @@ type unmarshaler struct {
|
|||||||
// keyval if a field is missing.
|
// keyval if a field is missing.
|
||||||
parsingTable bool
|
parsingTable bool
|
||||||
|
|
||||||
|
// Counters that indicate that we are skipping TOML expressions. It happens
|
||||||
|
// when the document contains values that are not in the target struct.
|
||||||
|
// TODO: signal the parser that it can just scan to avoid processing the
|
||||||
|
// unused data.
|
||||||
skipKeyValCount uint
|
skipKeyValCount uint
|
||||||
skipTable bool
|
skipTable bool
|
||||||
}
|
}
|
||||||
@@ -152,7 +156,8 @@ func (u *unmarshaler) StringValue(v []byte) {
|
|||||||
}
|
}
|
||||||
u.builder.Load()
|
u.builder.Load()
|
||||||
} else {
|
} else {
|
||||||
u.err = u.builder.SetString(string(v))
|
s := string(v)
|
||||||
|
u.err = u.builder.Set(reflect.ValueOf(&s))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -216,7 +221,7 @@ func (u *unmarshaler) LocalDateValue(date LocalDate) {
|
|||||||
}
|
}
|
||||||
u.builder.Load()
|
u.builder.Load()
|
||||||
} else {
|
} else {
|
||||||
u.err = u.builder.Set(reflect.ValueOf(date))
|
u.err = u.builder.Set(reflect.ValueOf(&date))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -232,7 +237,7 @@ func (u *unmarshaler) LocalDateTimeValue(dt LocalDateTime) {
|
|||||||
}
|
}
|
||||||
u.builder.Load()
|
u.builder.Load()
|
||||||
} else {
|
} else {
|
||||||
u.err = u.builder.Set(reflect.ValueOf(dt))
|
u.err = u.builder.Set(reflect.ValueOf(&dt))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -248,7 +253,7 @@ func (u *unmarshaler) DateTimeValue(dt time.Time) {
|
|||||||
}
|
}
|
||||||
u.builder.Load()
|
u.builder.Load()
|
||||||
} else {
|
} else {
|
||||||
u.err = u.builder.Set(reflect.ValueOf(dt))
|
u.err = u.builder.Set(reflect.ValueOf(&dt))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -264,7 +269,7 @@ func (u *unmarshaler) LocalTimeValue(localTime LocalTime) {
|
|||||||
}
|
}
|
||||||
u.builder.Load()
|
u.builder.Load()
|
||||||
} else {
|
} else {
|
||||||
u.err = u.builder.Set(reflect.ValueOf(localTime))
|
u.err = u.builder.Set(reflect.ValueOf(&localTime))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -313,4 +318,6 @@ func (u *unmarshaler) StandardTableEnd() {
|
|||||||
if u.skipping() || u.err != nil {
|
if u.skipping() || u.err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
u.builder.EnsureStructOrMap()
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user