@@ -117,6 +117,53 @@ TEST_CASE("Worker thread exceptions propagate to main thread", "[error_handling]
117117 }
118118}
119119
120+ /* Ensure reading empty CSVs does not cause errors.
121+ *
122+ * Reported in:
123+ * - https://github.com/vincentlaucsb/csv-parser/issues/116
124+ * - https://github.com/vincentlaucsb/csv-parser/issues/121
125+ * - empty mmap EOF guard in issue #267
126+ */
127+ TEST_CASE (" Empty CSV does not crash parser entry points" , " [error_handling][empty_csv]" ) {
128+ SECTION (" Stream path handles empty inputs and header-only inputs" ) {
129+ auto csv_string = GENERATE (as<std::string>{},
130+ " A,B,C,D\r\n " , // Header row only
131+ " " // No content
132+ );
133+
134+ std::stringstream source (csv_string);
135+ CSVReader reader (source);
136+ REQUIRE (reader.empty ());
137+
138+ for (auto & row : reader) {
139+ (void )row;
140+ }
141+
142+ REQUIRE (reader.n_rows () == 0 );
143+ }
144+
145+ #ifndef __EMSCRIPTEN__
146+ SECTION (" Filename path reports a zero-byte file as an open failure" ) {
147+ bool caught = false ;
148+ std::string error_message;
149+
150+ try {
151+ CSVReader reader (" ./tests/data/fake_data/empty.csv" );
152+ for (auto & row : reader) {
153+ (void )row;
154+ }
155+ }
156+ catch (const std::exception& e) {
157+ caught = true ;
158+ error_message = e.what ();
159+ }
160+
161+ REQUIRE (caught);
162+ REQUIRE (error_message == " Cannot open file ./tests/data/fake_data/empty.csv" );
163+ }
164+ #endif
165+ }
166+
120167#ifndef __EMSCRIPTEN__
121168TEST_CASE (" Fields at chunk boundaries are not corrupted" , " [chunking][data_integrity]" ) {
122169 SECTION (" Large file with known values around chunk boundary" ) {
0 commit comments