-
Notifications
You must be signed in to change notification settings - Fork 2
Fix trim fields #18
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
base: main
Are you sure you want to change the base?
Fix trim fields #18
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -69,28 +69,38 @@ void test_csv_parser_whitespace_trimming() { | |
| assert(arena_create(&arena, 4096) == ARENA_OK); | ||
| CSVConfig *config = csv_config_create(&arena); | ||
|
|
||
| // Test trailing whitespace trimming (parser only trims trailing, not leading) | ||
| // Test with trimFields = false | ||
| config->trimFields = false; | ||
| CSVParseResult result1 = csv_parse_line_inplace(" field1 , field2 , field3 ", &arena, config, 1); | ||
| assert(result1.success == true); | ||
| assert(result1.fields.count == 3); | ||
| assert(strcmp(result1.fields.fields[0], " field1") == 0); // Leading spaces preserved | ||
| assert(strcmp(result1.fields.fields[1], " field2") == 0); // Leading spaces preserved | ||
| assert(strcmp(result1.fields.fields[2], " field3") == 0); // Leading spaces preserved | ||
| assert(strcmp(result1.fields.fields[0], " field1 ") == 0); // Leading spaces preserved | ||
| assert(strcmp(result1.fields.fields[1], " field2 ") == 0); // Leading spaces preserved | ||
| assert(strcmp(result1.fields.fields[2], " field3 ") == 0); // Leading spaces preserved | ||
|
|
||
| // Test with quoted fields (should not trim inside quotes) | ||
| CSVParseResult result2 = csv_parse_line_inplace("\" field1 \", field2 ", &arena, config, 2); | ||
| // Test with trimFields = true | ||
| config->trimFields = true; | ||
| CSVParseResult result2 = csv_parse_line_inplace(" field1 , field2 , field3 ", &arena, config, 1); | ||
| assert(result2.success == true); | ||
| assert(result2.fields.count == 2); | ||
| assert(strcmp(result2.fields.fields[0], " field1 ") == 0); | ||
| assert(strcmp(result2.fields.fields[1], " field2") == 0); | ||
|
|
||
| // Test pure trailing whitespace trimming | ||
| CSVParseResult result3 = csv_parse_line_inplace("field1 ,field2\t\t,field3 ", &arena, config, 3); | ||
| assert(result2.fields.count == 3); | ||
| assert(strcmp(result2.fields.fields[0], "field1") == 0); // Leading spaces preserved | ||
| assert(strcmp(result2.fields.fields[1], "field2") == 0); // Leading spaces preserved | ||
| assert(strcmp(result2.fields.fields[2], "field3") == 0); // Leading spaces preserved | ||
|
|
||
|
Comment on lines
+72
to
+89
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win Missing coverage for clean/empty fields under These new cases only cover fields with existing leading/trailing whitespace. Adding a case with an already-clean field (e.g. 🤖 Prompt for AI Agents |
||
| // Test with quoted fields (should not trim inside quotes) | ||
| CSVParseResult result3 = csv_parse_line_inplace("\" field1 \", field2 ", &arena, config, 2); | ||
| assert(result3.success == true); | ||
| assert(result3.fields.count == 3); | ||
| assert(strcmp(result3.fields.fields[0], "field1") == 0); // Trailing spaces trimmed | ||
| assert(strcmp(result3.fields.fields[1], "field2") == 0); // Trailing tabs trimmed | ||
| assert(strcmp(result3.fields.fields[2], "field3") == 0); // Trailing space trimmed | ||
| assert(result3.fields.count == 2); | ||
| assert(strcmp(result3.fields.fields[0], " field1 ") == 0); | ||
| assert(strcmp(result3.fields.fields[1], "field2") == 0); | ||
|
|
||
| // Test pure trailing whitespace trimming with trimFields = true | ||
| CSVParseResult result4 = csv_parse_line_inplace("field1 ,field2\t\t,field3 ", &arena, config, 3); | ||
| assert(result4.success == true); | ||
| assert(result4.fields.count == 3); | ||
| assert(strcmp(result4.fields.fields[0], "field1") == 0); // Trailing spaces trimmed | ||
| assert(strcmp(result4.fields.fields[1], "field2") == 0); // Trailing tabs trimmed | ||
| assert(strcmp(result4.fields.fields[2], "field3") == 0); // Trailing space trimmed | ||
|
|
||
| arena_destroy(&arena); | ||
| printf("✓ CSV parser whitespace trimming test passed\n"); | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🎯 Functional Correctness | 🔴 Critical | ⚡ Quick win
Off-by-one: wrong
max_lencauses spurious failures for clean/empty fields.csv_utils_trim_whitespace(field, len)passes the string length as the buffer capacity, but the actual buffer allocated forfieldislen + 1bytes (Line 45:arena_alloc(arena, len + 1, &ptr)). Percsv_utils_trim_whitespace's contract (fromcsv_utils.c): it returnsCSV_UTILS_ERROR_BUFFER_OVERFLOWwhentrimmed_len >= max_len, andCSV_UTILS_ERROR_INVALID_INPUTimmediately whenmax_len == 0.Since trimming can never increase length,
trimmed_len == lenwhenever a field has no leading/trailing whitespace — which then satisfiestrimmed_len >= max_len(both equallen) and wrongly returnsBUFFER_OVERFLOW. Worse, for empty fields (e.g. the call at Line 130 withlen == 0, reachable via consecutive delimiters like"a,,c"),max_len == 0triggersCSV_UTILS_ERROR_INVALID_INPUTunconditionally.In both cases
add_fieldreturnsfalse, andcsv_parse_line_inplaceaborts the whole line with"Memory allocation failed"— so withtrimFields = true, any already-clean field or any empty field breaks parsing entirely. The tests added in this PR only exercise fields that actually have whitespace to trim, so this doesn't surface there.🐛 Proposed fix: pass buffer capacity, not string length
if (config->trimFields) { - CSVUtilsResult utilsResult = csv_utils_trim_whitespace(field, len); + CSVUtilsResult utilsResult = csv_utils_trim_whitespace(field, len + 1); if (utilsResult != CSV_UTILS_OK) { return false; } }📝 Committable suggestion
🤖 Prompt for AI Agents