Skip to content
Open
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
12 changes: 12 additions & 0 deletions reader.go
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,19 @@ func setFieldValue(field reflect.Value, value string) error {
if err != nil {
return err
}
if field.OverflowInt(intValue) {
return fmt.Errorf("value %d out of range for type %s", intValue, field.Kind())
}
field.SetInt(intValue)
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
uintValue, err := strconv.ParseUint(value, 10, 64)
if err != nil {
return err
}
if field.OverflowUint(uintValue) {
return fmt.Errorf("value %d out of range for type %s", uintValue, field.Kind())
}
field.SetUint(uintValue)
case reflect.Float32, reflect.Float64:
floatValue, err := strconv.ParseFloat(value, 64)
if err != nil {
Expand Down
58 changes: 55 additions & 3 deletions reader_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,9 +101,9 @@ Bob,bob@example.com,25

func TestComplexTypes(t *testing.T) {
// CSV data with various types
csvData := `name,created_at,active,score,count,rate,tags
John,2023-01-02T15:04:05Z,true,98.6,42,3.14,test;debug
Jane,2023-06-15T09:30:00Z,false,75.2,100,2.718,prod;live`
csvData := `name,created_at,active,score,count,rate,tags,rank
John,2023-01-02T15:04:05Z,true,98.6,42,3.14,test;debug,1
Jane,2023-06-15T09:30:00Z,false,75.2,100,2.718,prod;live,42`

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you add a test about sending a negative number via a CSV into a uint field ?

I feel like it could be useful to validate how the library behaves in such use case.

Also, it would help to avoid regression

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the comment. I've added a test for invalid values.


reader := strings.NewReader(csvData)

Expand All @@ -125,6 +125,7 @@ Jane,2023-06-15T09:30:00Z,false,75.2,100,2.718,prod;live`
Count: 42,
Rate: 3.14,
Tags: "test;debug",
Rank: 1,
},
{
Name: "Jane",
Expand All @@ -134,6 +135,7 @@ Jane,2023-06-15T09:30:00Z,false,75.2,100,2.718,prod;live`
Count: 100,
Rate: 2.718,
Tags: "prod;live",
Rank: 42,
},
}

Expand Down Expand Up @@ -166,3 +168,53 @@ func TestCustomUnmarshaler(t *testing.T) {
t.Errorf("Parsed results do not match expected.\nExpected: %+v\nGot: %+v", expected, results)
}
}

func TestInvalidData(t *testing.T) {
t.Parallel()

panickedValue := func(f func()) (value any) {
defer func() {
value = recover()
}()

f()
return
}

test := func(t *testing.T, input string, expectedMessage string) {
t.Helper()

reader := strings.NewReader(input)

rb, err := rowboat.NewReader[ComplexRecord](reader)
if err != nil {
t.Fatalf("Failed to create RowBoat: %v", err)
}

actualValue := panickedValue(func() {
slices.Collect(rb.All())
})

if actualValue == nil {
t.Errorf("Expected a panic for input '%s', but it was parsed without error", input)
return
}

actualError, ok := actualValue.(error)
if !ok {
t.Errorf("Expected a panic for input '%s', but received a non-error value: %v (%[2]T)", input, actualValue)
return
}

actualMessage := actualError.Error()
if expectedMessage != actualMessage {
t.Errorf("Expected a panic for input %q with error message %q, but got %q", input, expectedMessage, actualMessage)
}
}

test(t, "score\nnot-float", `error setting field Score: strconv.ParseFloat: parsing "not-float": invalid syntax`)
test(t, "rank\n-1", `error setting field Rank: strconv.ParseUint: parsing "-1": invalid syntax`)
test(t, "rank\n1000", "error setting field Rank: value 1000 out of range for type uint8")
test(t, "int8\n1000", "error setting field Int8: value 1000 out of range for type int8")
test(t, "int8\n-1000", "error setting field Int8: value -1000 out of range for type int8")
}
2 changes: 2 additions & 0 deletions shared_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ type ComplexRecord struct {
Count int `csv:"count"`
Rate float32 `csv:"rate"`
Tags string `csv:"tags"`
Rank uint8 `csv:"rank"`
Int8 int8 `csv:"int8"`
}

type Point struct {
Expand Down
4 changes: 4 additions & 0 deletions writer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ func TestComplexWriter(t *testing.T) {
Count: 42,
Rate: 3.14,
Tags: "test;debug",
Rank: 1,
},
{
Name: "Jane",
Expand All @@ -81,6 +82,7 @@ func TestComplexWriter(t *testing.T) {
Count: 100,
Rate: 2.718,
Tags: "prod;live",
Rank: 42,
},
}

Expand Down Expand Up @@ -127,6 +129,7 @@ func TestWriteAll(t *testing.T) {
Count: 42,
Rate: 3.14,
Tags: "test;debug",
Rank: 1,
},
{
Name: "Jane",
Expand All @@ -136,6 +139,7 @@ func TestWriteAll(t *testing.T) {
Count: 100,
Rate: 2.718,
Tags: "prod;live",
Rank: 42,
},
}

Expand Down