Skip to content

Commit

Permalink
Decode: improve errors on integers and strings (#891)
Browse files Browse the repository at this point in the history
  • Loading branch information
pelletier committed Aug 28, 2023
1 parent cef80b9 commit 4835627
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 4 deletions.
12 changes: 8 additions & 4 deletions unmarshaler.go
Original file line number Diff line number Diff line change
Expand Up @@ -149,12 +149,16 @@ type errorContext struct {
}

func (d *decoder) typeMismatchError(toml string, target reflect.Type) error {
return fmt.Errorf("toml: %s", d.typeMismatchString(toml, target))
}

func (d *decoder) typeMismatchString(toml string, target reflect.Type) string {
if d.errorContext != nil && d.errorContext.Struct != nil {
ctx := d.errorContext
f := ctx.Struct.FieldByIndex(ctx.Field)
return fmt.Errorf("toml: cannot decode TOML %s into struct field %s.%s of type %s", toml, ctx.Struct, f.Name, f.Type)
return fmt.Sprintf("cannot decode TOML %s into struct field %s.%s of type %s", toml, ctx.Struct, f.Name, f.Type)
}
return fmt.Errorf("toml: cannot decode TOML %s into a Go value of type %s", toml, target)
return fmt.Sprintf("cannot decode TOML %s into a Go value of type %s", toml, target)
}

func (d *decoder) expr() *unstable.Node {
Expand Down Expand Up @@ -963,7 +967,7 @@ func (d *decoder) unmarshalInteger(value *unstable.Node, v reflect.Value) error
case reflect.Interface:
r = reflect.ValueOf(i)
default:
return d.typeMismatchError("integer", v.Type())
return unstable.NewParserError(d.p.Raw(value.Raw), d.typeMismatchString("integer", v.Type()))
}

if !r.Type().AssignableTo(v.Type()) {
Expand All @@ -982,7 +986,7 @@ func (d *decoder) unmarshalString(value *unstable.Node, v reflect.Value) error {
case reflect.Interface:
v.Set(reflect.ValueOf(string(value.Data)))
default:
return unstable.NewParserError(d.p.Raw(value.Raw), "cannot store TOML string into a Go %s", v.Kind())
return unstable.NewParserError(d.p.Raw(value.Raw), d.typeMismatchString("string", v.Type()))
}

return nil
Expand Down
62 changes: 62 additions & 0 deletions unmarshaler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2048,6 +2048,68 @@ func TestUnmarshalErrors(t *testing.T) {
require.Equal(t, "toml: cannot decode TOML integer into struct field toml_test.mystruct.Bar of type string", err.Error())
}

func TestUnmarshalStringInvalidStructField(t *testing.T) {
type Server struct {
Path string
Port int
}

type Cfg struct {
Server Server
}

var cfg Cfg

data := `[server]
path = "/my/path"
port = "bad"
`

file := strings.NewReader(data)
err := toml.NewDecoder(file).Decode(&cfg)
require.Error(t, err)

x := err.(*toml.DecodeError)
require.Equal(t, "toml: cannot decode TOML string into struct field toml_test.Server.Port of type int", x.Error())
expected := `1| [server]
2| path = "/my/path"
3| port = "bad"
| ~~~~~ cannot decode TOML string into struct field toml_test.Server.Port of type int`

require.Equal(t, expected, x.String())
}

func TestUnmarshalIntegerInvalidStructField(t *testing.T) {
type Server struct {
Path string
Port int
}

type Cfg struct {
Server Server
}

var cfg Cfg

data := `[server]
path = 100
port = 50
`

file := strings.NewReader(data)
err := toml.NewDecoder(file).Decode(&cfg)
require.Error(t, err)

x := err.(*toml.DecodeError)
require.Equal(t, "toml: cannot decode TOML integer into struct field toml_test.Server.Path of type string", x.Error())
expected := `1| [server]
2| path = 100
| ~~~ cannot decode TOML integer into struct field toml_test.Server.Path of type string
3| port = 50`

require.Equal(t, expected, x.String())
}

func TestUnmarshalInvalidTarget(t *testing.T) {
x := "foo"
err := toml.Unmarshal([]byte{}, x)
Expand Down

0 comments on commit 4835627

Please sign in to comment.