8000 Implements WithOmitEmptyFields by apstndb · Pull Request #23 · Code-Hex/dd · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Implements WithOmitEmptyFields #23

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions dumper.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
type dumpFunc func(reflect.Value, Writer)

type options struct {
omitEmptyFields bool
exportedOnly bool
indentSize int
uintFormat UintFormat
Expand All @@ -25,6 +26,7 @@ type options struct {

func newDefaultOptions() *options {
return &options{
omitEmptyFields: false,
exportedOnly: false,
indentSize: 2,
uintFormat: DecimalUint,
Expand All @@ -42,6 +44,7 @@ type dumper struct {
cachedZeroValues map[reflect.Type]string
clonePool *sync.Pool
// options
omitEmptyFields bool
exportedOnly bool
uintFormat UintFormat
convertibleTypes map[reflect.Type]dumpFunc
Expand Down Expand Up @@ -73,6 +76,7 @@ func newDataDumper(obj interface{}, optFuncs ...OptionFunc) *dumper {
ret.visitPointers = make(map[uintptr]bool)
ret.cachedZeroValues = zeroPrimitives
ret.clonePool = clonePool
ret.omitEmptyFields = opts.omitEmptyFields
ret.exportedOnly = opts.exportedOnly
ret.uintFormat = opts.uintFormat
ret.convertibleTypes = opts.convertibleTypes
Expand All @@ -87,6 +91,7 @@ func (d *dumper) clone(obj interface{}) *dumper {
child.visitPointers = d.visitPointers
child.cachedZeroValues = d.cachedZeroValues
child.clonePool = d.clonePool
child.omitEmptyFields = d.omitEmptyFields
child.exportedOnly = d.exportedOnly
child.uintFormat = d.uintFormat
child.convertibleTypes = d.convertibleTypes
Expand Down Expand Up @@ -293,6 +298,9 @@ func (d *dumper) writeStruct() {
if !isExported(field) && fieldVal.CanAddr() {
fieldVal = getUnexportedField(fieldVal)
}
if d.omitEmptyFields && fieldVal.IsZero() {
continue
}
d.indentedPrintf("%s: %s,\n", field.Name, dumpclone(d, fieldVal))
}
})
Expand Down
6 changes: 6 additions & 0 deletions export.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,3 +62,9 @@ func WithListBreakLineSize(typ interface{}, size int) OptionFunc {
o.listGroupingSize[tmp] = size
}
}

func WithOmitEmptyFields() OptionFunc {
return func(o *options) {
o.omitEmptyFields = true
}
}
109 changes: 83 additions & 26 deletions export_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import (
"mime/multipart"
"net/http"
"net/textproto"
"reflect"
"strconv"
"strings"
"testing"
Expand Down Expand Up @@ -275,11 +274,6 @@ func TestDumpBasic(t *testing.T) {
v: (func(int, int) bool)(nil),
want: "(func(int, int) bool)(nil)",
},
{
name: "reflect.Value{}",
v: reflect.Value{},
want: "reflect.Value{\n typ: (*reflect.rtype)(nil),\n ptr: unsafe.Pointer(uintptr(0)),\n flag: 0,\n}",
},
{
name: "context.CancelFunc",
v: context.CancelFunc(func() {}),
Expand Down Expand Up @@ -434,6 +428,89 @@ func TestPointer(t *testing.T) {
})
}

func TestWithOmitEmptyFields(t *testing.T) {
type manyFields struct {
intField int
intPtr *int
stringField string
stringPtr *string
boolField bool
boolPtr *bool
uint8Field uint8
uint8Ptr *uint8
uint16Field uint16
uint16Ptr *uint16
uint32Field uint32
uint32Ptr *uint32
uint64Field uint64
uint64Ptr *uint64
float32Field float32
float32Ptr *float32
float64Field float64
float64Ptr *float64
complex64Field complex64
complex64Ptr *complex64
complex128Field complex128
complex128Ptr *complex128
arrayField [2]int
arrayPtr *[2]int
sliceField []int
slicePtr *[]int
mapField map[string]int
mapPtr *map[string]int
chanField chan int
chanPtr *chan int
funcField func()
funcPtr *func()
interfaceField any
structField struct{ intField int }
structPtr *struct{ intField int }
}
cases := []struct {
name string
v interface{}
wantOmit string
wantEmit string
}{
{
name: "nil pointer of int",
v: manyFields{},
wantOmit: "dd_test.manyFields{\n}",
wantEmit: "dd_test.manyFields{\n intField: 0,\n intPtr: (*int)(nil),\n stringField: \"\",\n stringPtr: (*string)(nil),\n boolField: false,\n boolPtr: (*bool)(nil),\n uint8Field: 0,\n uint8Ptr: (*uint8)(nil),\n uint16Field: 0,\n uint16Ptr: (*uint16)(nil),\n uint32Field: 0,\n uint32Ptr: (*uint32)(nil),\n uint64Field: 0,\n uint64Ptr: (*uint64)(nil),\n float32Field: 0.000000,\n float32Ptr: (*float32)(nil),\n float64Field: 0.000000,\n float64Ptr: (*float64)(nil),\n complex64Field: (0+0i),\n complex64Ptr: (*complex64)(nil),\n complex128Field: (0+0i),\n complex128Ptr: (*complex128)(nil),\n arrayField: [2]int{\n 0,\n 0,\n },\n arrayPtr: (*[2]int)(nil),\n sliceField: ([]int)(nil),\n slicePtr: (*[]int)(nil),\n mapField: (map[string]int)(nil),\n mapPtr: (*map[string]int)(nil),\n chanField: (chan int)(nil),\n chanPtr: (*chan int)(nil),\n funcField: (func())(nil),\n funcPtr: (*func())(nil),\n interfaceField: nil,\n structField: struct { intField int }{\n intField: 0,\n },\n structPtr: (*struct { intField int })(nil),\n}",
},
}
t.Run("omit", func(t *testing.T) {
for _, tc := range cases {
tc := tc
t.Run(tc.name, func(t *testing.T) {
got := dd.Dump(tc.v, dd.WithOmitEmptyFields())
if !strings.Contains(got, tc.wantOmit) {
t.Fatalf("wantOmit %q, but got %q", tc.wantOmit, got)
}
if _, err := parser.ParseExpr(got); err != nil {
t.Fatal(err)
}
})
}
})

t.Run("emit", func(t *testing.T) {
for _, tc := range cases {
tc := tc
t.Run(tc.name, func(t *testing.T) {
got := dd.Dump(tc.v)
if !strings.Contains(got, tc.wantEmit) {
t.Fatalf("want %q, but got %q", tc.wantEmit, got)
}
if _, err := parser.ParseExpr(got); err != nil {
t.Fatal(err)
}
})
}
})

}

func TestWithIndent(t *testing.T) {
want := "[]int{\n 1,\n 2,\n}"
got := dd.Dump([]int{1, 2}, dd.WithIndent(4))
Expand Down Expand Up @@ -664,23 +741,3 @@ func TestWithListBreakLineSize(t *testing.T) {
})
}
}

func TestUnexportedField(t *testing.T) {
type stringKey struct{}
ctx := context.WithValue(
context.Background(),
stringKey{},
"value",
)
got := dd.Dump(ctx, dd.WithDumpFunc(func(s string, w dd.Writer) {
w.Write(s)
}))
got = addressReplaceRegexp.ReplaceAllString(got, "0x0")
want := "&context.valueCtx{\n Context: (*context.emptyCtx)(unsafe.Pointer(0x0)),\n key: dd_test.stringKey{},\n val: value,\n}"
if want != got {
t.Fatalf("want %q, but got %q", want, got)
}
if _, err := parser.ParseExpr(got); err != nil {
t.Fatal(err)
}
}
0