Skip to content

Commit

Permalink
Don't return error on uncomparable types: just silently ignore like b…
Browse files Browse the repository at this point in the history
…efore

This is more compatible with the previous behaviour, as well as what
stdlib does.

Ref: #360
  • Loading branch information
arp242 committed Jul 28, 2022
1 parent 929b0a7 commit 360c9e3
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 48 deletions.
5 changes: 2 additions & 3 deletions encode.go
Original file line number Diff line number Diff line change
Expand Up @@ -654,10 +654,9 @@ func (enc *Encoder) isEmpty(rv reflect.Value) bool {
case reflect.Array, reflect.Slice, reflect.Map, reflect.String:
return rv.Len() == 0
case reflect.Struct:
if !rv.Type().Comparable() {
encPanic(fmt.Errorf("type %q cannot be used with omitempty as it's uncomparable", rv.Type()))
if rv.Type().Comparable() {
return reflect.Zero(rv.Type()).Interface() == rv.Interface()
}
return reflect.Zero(rv.Type()).Interface() == rv.Interface()
case reflect.Bool:
return !rv.Bool()
}
Expand Down
73 changes: 28 additions & 45 deletions encode_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -182,23 +182,33 @@ func TestEncodeOmitEmptyStruct(t *testing.T) {
}

func TestEncodeWithOmitEmpty(t *testing.T) {
type uncomparable struct {
Field []string `toml:"Field,omitempty"`
}
type simple struct {
Bool bool `toml:"bool,omitempty"`
String string `toml:"string,omitempty"`
Array [0]byte `toml:"array,omitempty"`
Slice []int `toml:"slice,omitempty"`
Map map[string]string `toml:"map,omitempty"`
Time time.Time `toml:"time,omitempty"`
Bool bool `toml:"bool,omitempty"`
String string `toml:"string,omitempty"`
Array [0]byte `toml:"array,omitempty"`
Slice []int `toml:"slice,omitempty"`
Map map[string]string `toml:"map,omitempty"`
Time time.Time `toml:"time,omitempty"`
Uncomparable1 uncomparable `toml:"uncomparable1,omitempty"`
Uncomparable2 uncomparable `toml:"uncomparable2,omitempty"`
}

var v simple
encodeExpected(t, "fields with omitempty are omitted when empty", v, "", nil)
encodeExpected(t, "fields with omitempty are omitted when empty", v, `
[uncomparable1]
[uncomparable2]
`, nil)
v = simple{
Bool: true,
String: " ",
Slice: []int{2, 3, 4},
Map: map[string]string{"foo": "bar"},
Time: time.Date(1985, 6, 18, 15, 16, 17, 0, time.UTC),
Bool: true,
String: " ",
Slice: []int{2, 3, 4},
Map: map[string]string{"foo": "bar"},
Time: time.Date(1985, 6, 18, 15, 16, 17, 0, time.UTC),
Uncomparable2: uncomparable{[]string{"XXX"}},
}
expected := `bool = true
string = " "
Expand All @@ -207,43 +217,16 @@ time = 1985-06-18T15:16:17Z
[map]
foo = "bar"
[uncomparable1]
[uncomparable2]
Field = ["XXX"]
`
encodeExpected(t, "fields with omitempty are not omitted when non-empty",
v, expected, nil)
}

func TestEncodeWithOmitEmptyError(t *testing.T) {
type nest struct {
Field []string `toml:"Field,omitempty"`
}

tests := []struct {
in interface{}
wantErr string
}{
{ // Make sure it doesn't panic on uncomparable types; #360
struct {
Values nest `toml:"values,omitempty"`
Empty nest `toml:"empty,omitempty"`
}{Values: nest{[]string{"XXX"}}},
"cannot be used with omitempty as it's uncomparable",
},
}

for _, tt := range tests {
t.Run("", func(t *testing.T) {
buf := new(bytes.Buffer)
err := NewEncoder(buf).Encode(tt.in)
if !errorContains(err, tt.wantErr) {
t.Fatalf("wrong error: %v", err)
}
if buf.String() != "" {
t.Errorf("output not empty:\n%s", buf)
}
})
}
}

func TestEncodeWithOmitZero(t *testing.T) {
type simple struct {
Number int `toml:"number,omitzero"`
Expand Down Expand Up @@ -1164,8 +1147,8 @@ ArrayOfMixedSlices = [[1, 2], ["a", "b"]]

func encodeExpected(t *testing.T, label string, val interface{}, want string, wantErr error) {
t.Helper()

t.Run(label, func(t *testing.T) {
t.Helper()
var buf bytes.Buffer
err := NewEncoder(&buf).Encode(val)
if err != wantErr {
Expand Down

0 comments on commit 360c9e3

Please sign in to comment.