SetHeaderNormalizer reassigned the normalizer and copied a fresh sync.Map over the struct info cache while other goroutines were using it. Keep both in one value swapped atomically instead. Fixes #237.
67 lines
1.5 KiB
Go
67 lines
1.5 KiB
Go
package gocsv
|
|
|
|
import (
|
|
"errors"
|
|
"strings"
|
|
"sync"
|
|
"testing"
|
|
)
|
|
|
|
func TestUnmarshalToCallback_ReaderError(t *testing.T) {
|
|
type Dummy struct{}
|
|
var reader = &errorReader{}
|
|
|
|
err := UnmarshalToCallback(reader, func(Dummy) {})
|
|
if !errors.Is(err, readerErr) {
|
|
t.Error("UnmarshalToCallback should return first reader error")
|
|
}
|
|
|
|
err = UnmarshalDecoderToCallback(newSimpleDecoderFromReader(reader), func(Dummy) {})
|
|
if !errors.Is(err, readerErr) {
|
|
t.Error("UnmarshalDecoderToCallback should return first reader error")
|
|
}
|
|
|
|
err = UnmarshalToCallbackWithError(reader, func(Dummy) error { return nil })
|
|
if !errors.Is(err, readerErr) {
|
|
t.Error("UnmarshalToCallbackWithError should return first reader error")
|
|
}
|
|
}
|
|
|
|
func TestSetHeaderNormalizerWhileUnmarshaling(t *testing.T) {
|
|
defer SetHeaderNormalizer(DefaultNameNormalizer())
|
|
|
|
type row struct {
|
|
ID string `csv:"id"`
|
|
Name string `csv:"name"`
|
|
}
|
|
|
|
var wg sync.WaitGroup
|
|
for i := 0; i < 50; i++ {
|
|
wg.Add(2)
|
|
go func() {
|
|
defer wg.Done()
|
|
SetHeaderNormalizer(strings.ToLower)
|
|
}()
|
|
go func() {
|
|
defer wg.Done()
|
|
var rows []row
|
|
if err := UnmarshalString("id,name\n1,foo\n", &rows); err != nil {
|
|
t.Error(err)
|
|
return
|
|
}
|
|
if len(rows) != 1 || rows[0].ID != "1" || rows[0].Name != "foo" {
|
|
t.Errorf("unexpected rows: %+v", rows)
|
|
}
|
|
}()
|
|
}
|
|
wg.Wait()
|
|
}
|
|
|
|
type errorReader struct{}
|
|
|
|
func (e *errorReader) Read([]byte) (n int, err error) {
|
|
return 0, readerErr
|
|
}
|
|
|
|
var readerErr = errors.New("reader error")
|