Skip to content

Instantly share code, notes, and snippets.

@KalleDK
Created September 13, 2019 11:44
Show Gist options
  • Save KalleDK/6616d6634a787fa31cfff02c47110f2c to your computer and use it in GitHub Desktop.
Save KalleDK/6616d6634a787fa31cfff02c47110f2c to your computer and use it in GitHub Desktop.
package csvutil_test
import (
"bytes"
"encoding/csv"
"testing"
"io"
"time"
"github.com/jszwec/csvutil"
csvutildk "github.com/KalleDK/csvutil"
)
type A struct {
A int `csv:"a" name:"a"`
B float64 `csv:"b" name:"b"`
C string `csv:"c" name:"c"`
D int64 `csv:"d" name:"d"`
E int8 `csv:"e" name:"e"`
F float32 `csv:"f" name:"f"`
G float32 `csv:"g" name:"g"`
H float32 `csv:"h" name:"h"`
I string `csv:"i" name:"i"`
J int `csv:"j" name:"j"`
K time.Time `csv:"k" name:"k"`
L time.Time `csv:"l" name:"l"`
}
func UnmarshalDate(s string, v interface{}) (err error) {
*(v.(*time.Time)), err = time.Parse("2006.01.02", s)
if err != nil {
return err
}
return nil
}
func ConvertDate(s string) string {
date, err := time.Parse("2006.01.02", s)
if err != nil {
return ""
}
return date.Format(time.RFC3339)
}
func BenchmarkUnmarshal(b *testing.B) {
fixture := []struct {
desc string
records int
}{
{
desc: "1 record",
records: 1,
},
{
desc: "10 records",
records: 10,
},
{
desc: "100 records",
records: 100,
},
{
desc: "1000 records",
records: 1000,
},
{
desc: "10000 records",
records: 10000,
},
{
desc: "100000 records",
records: 100000,
},
}
tests := []struct {
desc string
fn func([]byte, *testing.B)
}{
{
desc: "csvutildk.Unmarshal",
fn: func(data []byte, b *testing.B) {
var a []A
dec, err := csvutildk.NewDecoder(csv.NewReader(bytes.NewReader(data)))
if err != nil {
b.Error(err)
}
dec.FnMap = func(name string, v interface{}) csvutildk.DecodeFunc {
if name == "k" {
return UnmarshalDate
}
if _, ok := v.(time.Time); ok {
return UnmarshalDate
}
return nil
}
for {
value := A{}
if err := dec.Decode(&value); err == io.EOF {
break
} else if err != nil {
b.Error(err)
}
a = append(a, value)
}
},
},
{
desc: "csvutil.Unmarshal",
fn: func(data []byte, b *testing.B) {
var a []A
dec, err := csvutil.NewDecoder(csv.NewReader(bytes.NewReader(data)))
if err != nil {
b.Error(err)
}
dec.Map = func(field, column string, v interface{}) string {
if column == "k" {
return ConvertDate(field)
}
if _, ok := v.(time.Time); ok {
return ConvertDate(field)
}
return field
}
for {
value := A{}
if err := dec.Decode(&value); err == io.EOF {
break
} else if err != nil {
b.Error(err)
}
a = append(a, value)
}
},
},
}
for _, t := range tests {
b.Run(t.desc, func(b *testing.B) {
for _, f := range fixture {
b.Run(f.desc, func(b *testing.B) {
data := genData(f.records)
for i := 0; i < b.N; i++ {
t.fn(data, b)
}
})
}
})
}
}
func genData(records int) []byte {
header := []string{"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l"}
record := []string{"1", "2.5", "foo", "6", "7", "8", "9", "10", "bar", "10", "2019.08.31", "2019.08.31"}
var buf bytes.Buffer
w := csv.NewWriter(&buf)
w.Write(header)
for i := 0; i < records; i++ {
w.Write(record)
}
w.Flush()
if err := w.Error(); err != nil {
panic(err)
}
return buf.Bytes()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment