diff --git a/CMakeLists.txt b/CMakeLists.txt index 4f2d72c..31e21ed 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -195,6 +195,7 @@ if(RAPIDCSV_BUILD_TESTS) add_unit_test(test103) add_unit_test(test104) add_unit_test(test105) + add_unit_test(test106) # perf tests add_perf_test(ptest001) diff --git a/src/rapidcsv.h b/src/rapidcsv.h index 601624f..bc83e0e 100644 --- a/src/rapidcsv.h +++ b/src/rapidcsv.h @@ -2,7 +2,7 @@ * rapidcsv.h * * URL: https://github.com/d99kris/rapidcsv - * Version: 8.94 + * Version: 8.95 * * Copyright (C) 2017-2026 Kristofer Berggren * All rights reserved. @@ -1828,6 +1828,7 @@ namespace rapidcsv { if (mSeparatorParams.mAutoQuote && ((itc->find(mSeparatorParams.mSeparator) != std::string::npos) || + (itc->find(mSeparatorParams.mQuoteChar) != std::string::npos) || (itc->find(' ') != std::string::npos) || (itc->find('\n') != std::string::npos))) { diff --git a/tests/test106.cpp b/tests/test106.cpp new file mode 100644 index 0000000..1416528 --- /dev/null +++ b/tests/test106.cpp @@ -0,0 +1,81 @@ +// test106.cpp - write round-trip with cells containing quote characters + +#include +#include "unittest.h" + +int main() +{ + int rv = 0; + + try + { + // Test 1: Cell containing quote character but no separator/space/newline + { + std::string path = unittest::TempPath(); + std::string csv = + "a,b,c\n" + "1,he said \"hello\",3\n" + "4,5,6\n" + ; + unittest::WriteFile(path, csv); + + rapidcsv::Document doc1(path, rapidcsv::LabelParams(-1, -1)); + unittest::ExpectEqual(std::string, doc1.GetCell(1, 1), + "he said \"hello\""); + + // Save and reload - data must survive round-trip + doc1.Save(path); + rapidcsv::Document doc2(path, rapidcsv::LabelParams(-1, -1)); + + unittest::ExpectEqual(size_t, doc2.GetRowCount(), size_t(3)); + unittest::ExpectEqual(size_t, doc2.GetColumnCount(), size_t(3)); + unittest::ExpectEqual(std::string, doc2.GetCell(1, 1), + "he said \"hello\""); + + unittest::DeleteFile(path); + } + + // Test 2: Cell containing only a quote character + { + std::string path = unittest::TempPath(); + + std::istringstream ss("a,b\nx,\"y\"\n"); + rapidcsv::Document doc1(ss, rapidcsv::LabelParams(-1, -1)); + doc1.SetCell(1, 0, "\""); + doc1.Save(path); + + rapidcsv::Document doc2(path, rapidcsv::LabelParams(-1, -1)); + unittest::ExpectEqual(std::string, doc2.GetCell(1, 0), "\""); + + unittest::DeleteFile(path); + } + + // Test 3: Empty quoted cells round-trip + { + std::string path = unittest::TempPath(); + std::string csv = "\"\",\"\",\"\"\n"; + unittest::WriteFile(path, csv); + + rapidcsv::Document doc1(path, rapidcsv::LabelParams(-1, -1)); + unittest::ExpectEqual(std::string, doc1.GetCell(0, 0), ""); + unittest::ExpectEqual(std::string, doc1.GetCell(1, 0), ""); + unittest::ExpectEqual(std::string, doc1.GetCell(2, 0), ""); + + doc1.Save(path); + rapidcsv::Document doc2(path, rapidcsv::LabelParams(-1, -1)); + unittest::ExpectEqual(size_t, doc2.GetColumnCount(), size_t(3)); + unittest::ExpectEqual(std::string, doc2.GetCell(0, 0), ""); + unittest::ExpectEqual(std::string, doc2.GetCell(1, 0), ""); + unittest::ExpectEqual(std::string, doc2.GetCell(2, 0), ""); + + unittest::DeleteFile(path); + } + } + catch (const std::exception& ex) + { + std::cout << ex.what() << std::endl; + rv = 1; + } + + return rv; +}