Make SetHeaderNormalizer safe to call while decoding

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.
This commit is contained in:
dualfroz committed 2026-10-02 16:20:31 +02:00
1 parent 391e8f0876
commit f87ec7522c
3 files changed
+60 -8

No files matched your search

+32
View File
@@ -2,6 +2,8 @@ package gocsv
import (
"errors"
"strings"
"sync"
"testing"
)
@@ -25,6 +27,36 @@ func TestUnmarshalToCallback_ReaderError(t *testing.T) {
}
}
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) {