Skip to content

Commit 5c4209e

Browse files
tychoishSam Kleinman
authored andcommitted
GODRIVER-395: add zeroer implementation
Change-Id: I300499d79b01fa2e612a4c707d32757e01303534
1 parent d0c1f47 commit 5c4209e

File tree

2 files changed

+49
-1
lines changed

2 files changed

+49
-1
lines changed

bson/encode.go

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,13 @@ type DocumentEncoder interface {
9696
EncodeDocument(interface{}) (*Document, error)
9797
}
9898

99+
// Zeroer allows custom struct types to implement a report of zero
100+
// state. All struct types that don't implement Zeroer or where IsZero
101+
// returns false are considered to be not zero.
102+
type Zeroer interface {
103+
IsZero() bool
104+
}
105+
99106
type encoder struct {
100107
w io.Writer
101108
}
@@ -473,7 +480,10 @@ func (e *encoder) isZero(v reflect.Value) bool {
473480
case reflect.Interface, reflect.Ptr:
474481
return v.IsNil()
475482
case reflect.Struct:
476-
return reflect.Zero(v.Type()).Interface() == v.Interface()
483+
if z, ok := v.Interface().(Zeroer); ok {
484+
return z.IsZero()
485+
}
486+
return false
477487
}
478488

479489
return false

bson/encode_test.go

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,13 @@ package bson
99
import (
1010
"bytes"
1111
"io"
12+
"reflect"
1213
"testing"
1314
"time"
1415

1516
"github.com/google/go-cmp/cmp"
1617
"github.com/mongodb/mongo-go-driver/bson/objectid"
18+
"github.com/stretchr/testify/assert"
1719
)
1820

1921
func TestEncoder(t *testing.T) {
@@ -911,6 +913,42 @@ func reflectionEncoderTest(t *testing.T) {
911913
}
912914
}
913915

916+
type zeroTest struct {
917+
reportZero bool
918+
}
919+
920+
func (z zeroTest) IsZero() bool { return z.reportZero }
921+
922+
type nonZeroer struct {
923+
value bool
924+
}
925+
926+
func TestZeoerInterfaceUsedByDecoder(t *testing.T) {
927+
enc := &encoder{}
928+
929+
// cases that are zero, because they are known types or pointers
930+
var st *nonZeroer
931+
assert.True(t, enc.isZero(reflect.ValueOf(st)))
932+
assert.True(t, enc.isZero(reflect.ValueOf(0)))
933+
assert.True(t, enc.isZero(reflect.ValueOf(false)))
934+
935+
// cases that shouldn't be zero
936+
st = &nonZeroer{value: false}
937+
assert.False(t, enc.isZero(reflect.ValueOf(struct{ val bool }{val: true})))
938+
assert.False(t, enc.isZero(reflect.ValueOf(struct{ val bool }{val: false})))
939+
assert.False(t, enc.isZero(reflect.ValueOf(st)))
940+
st.value = true
941+
assert.False(t, enc.isZero(reflect.ValueOf(st)))
942+
943+
// a test to see if the interface impacts the outcome
944+
z := zeroTest{}
945+
assert.False(t, enc.isZero(reflect.ValueOf(z)))
946+
947+
z.reportZero = true
948+
assert.True(t, enc.isZero(reflect.ValueOf(z)))
949+
950+
}
951+
914952
func docToBytes(d *Document) []byte {
915953
b, err := d.MarshalBSON()
916954
if err != nil {

0 commit comments

Comments
 (0)