From 4835627845bd1d3eae85df98aff1c0c88926e154 Mon Sep 17 00:00:00 2001 From: Thomas Pelletier Date: Mon, 28 Aug 2023 11:17:48 -0400 Subject: [PATCH] Decode: improve errors on integers and strings (#891) --- unmarshaler.go | 12 ++++++--- unmarshaler_test.go | 62 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+), 4 deletions(-) diff --git a/unmarshaler.go b/unmarshaler.go index 5cede08..868c74c 100644 --- a/unmarshaler.go +++ b/unmarshaler.go @@ -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 { @@ -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()) { @@ -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 diff --git a/unmarshaler_test.go b/unmarshaler_test.go index c78ecb2..4019268 100644 --- a/unmarshaler_test.go +++ b/unmarshaler_test.go @@ -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)