diff --git a/CMakeLists.txt b/CMakeLists.txt index 4d77232..4f2d72c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -194,6 +194,7 @@ if(RAPIDCSV_BUILD_TESTS) add_unit_test(test102) add_unit_test(test103) add_unit_test(test104) + add_unit_test(test105) # perf tests add_perf_test(ptest001) diff --git a/src/rapidcsv.h b/src/rapidcsv.h index c3d57ca..601624f 100644 --- a/src/rapidcsv.h +++ b/src/rapidcsv.h @@ -2,7 +2,7 @@ * rapidcsv.h * * URL: https://github.com/d99kris/rapidcsv - * Version: 8.93 + * Version: 8.94 * * Copyright (C) 2017-2026 Kristofer Berggren * All rights reserved. @@ -1440,6 +1440,14 @@ namespace rapidcsv } const size_t dataColumnIdx = GetDataColumnIndex(pColumnIdx); + + // remove old name from map before adding new one + const size_t nameRowIdx = static_cast(mLabelParams.mColumnNameIdx); + if ((nameRowIdx < mData.size()) && (dataColumnIdx < mData.at(nameRowIdx).size())) + { + const std::string oldName = mData.at(nameRowIdx).at(dataColumnIdx); + mColumnNames.erase(oldName); + } mColumnNames[pColumnName] = dataColumnIdx; // increase table size if necessary: @@ -1497,6 +1505,14 @@ namespace rapidcsv void SetRowName(size_t pRowIdx, const std::string& pRowName) { const size_t dataRowIdx = GetDataRowIndex(pRowIdx); + + // remove old name from map before adding new one + if ((mLabelParams.mRowNameIdx >= 0) && (dataRowIdx < mData.size()) && + (static_cast(mLabelParams.mRowNameIdx) < mData.at(dataRowIdx).size())) + { + const std::string oldName = mData.at(dataRowIdx).at(static_cast(mLabelParams.mRowNameIdx)); + mRowNames.erase(oldName); + } mRowNames[pRowName] = dataRowIdx; if (mLabelParams.mRowNameIdx < 0) { diff --git a/tests/test105.cpp b/tests/test105.cpp new file mode 100644 index 0000000..642eabc --- /dev/null +++ b/tests/test105.cpp @@ -0,0 +1,61 @@ +// test105.cpp - SetColumnName / SetRowName stale label cleanup + +#include +#include "unittest.h" + +int main() +{ + int rv = 0; + + std::string csv = + "name,value\n" + "row1,100\n" + "row2,200\n" + ; + + std::string path = unittest::TempPath(); + unittest::WriteFile(path, csv); + + try + { + // Test 1: SetColumnName removes old name from map + { + rapidcsv::Document doc(path, rapidcsv::LabelParams(0, 0)); + + unittest::ExpectEqual(int, doc.GetColumnIdx("value"), 0); + doc.SetColumnName(0, "price"); + unittest::ExpectEqual(int, doc.GetColumnIdx("price"), 0); + unittest::ExpectEqual(int, doc.GetColumnIdx("value"), -1); + } + + // Test 2: SetRowName removes old name from map + { + rapidcsv::Document doc(path, rapidcsv::LabelParams(0, 0)); + + unittest::ExpectEqual(int, doc.GetRowIdx("row1"), 0); + doc.SetRowName(0, "item1"); + unittest::ExpectEqual(int, doc.GetRowIdx("item1"), 0); + unittest::ExpectEqual(int, doc.GetRowIdx("row1"), -1); + } + + // Test 3: Data access by new name works correctly + { + rapidcsv::Document doc(path, rapidcsv::LabelParams(0, 0)); + + doc.SetColumnName(0, "price"); + unittest::ExpectEqual(std::string, doc.GetCell("price", "row1"), "100"); + + doc.SetRowName(0, "item1"); + unittest::ExpectEqual(std::string, doc.GetCell("price", "item1"), "100"); + } + } + catch (const std::exception& ex) + { + std::cout << ex.what() << std::endl; + rv = 1; + } + + unittest::DeleteFile(path); + + return rv; +}