diff --git a/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/ReadCSVFileFilter.cpp b/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/ReadCSVFileFilter.cpp index 7ff5977cc9..76964bb12a 100644 --- a/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/ReadCSVFileFilter.cpp +++ b/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/ReadCSVFileFilter.cpp @@ -67,6 +67,22 @@ enum class IssueCodes IGNORED_TUPLE_DIMS = -200 }; +StringVector RemoveIllegalCharacters(StringVector& headers) +{ + for(int i = 0; i < headers.size(); i++) + { + auto& headerName = headers[i]; + // Replace all illegal characters with '_' character. The header names become array names which is the issue. + // This should have been taken care of in the GUI, but if someone is trying this from Python they will not have done that + // or if they are just reading it in through nxrunner. + headerName = StringUtilities::replace(headerName, "&", "_"); + headerName = StringUtilities::replace(headerName, ":", "_"); + headerName = StringUtilities::replace(headerName, "/", "_"); + headerName = StringUtilities::replace(headerName, "\\", "_"); + headerName = StringUtilities::replace(headerName, "\"", ""); + } + return headers; +} // ----------------------------------------------------------------------------- Result validateExistingGroup(const DataPath& groupPath, const DataStructure& dataStructure, const std::vector& headers) { @@ -530,9 +546,11 @@ IFilter::PreflightResult ReadCSVFileFilter::preflightImpl(const DataStructure& d return {MakeErrorResult(to_underlying(IssueCodes::INCORRECT_MASK_COUNT), errMsg), {}}; } + headers = RemoveIllegalCharacters(headers); + for(int i = 0; i < headers.size(); i++) { - const auto& headerName = headers[i]; + auto& headerName = headers[i]; if(headerName.empty()) { std::string errMsg = fmt::format("The header for column #{} is empty. Please fill in a header for column #{}.", i + 1, i + 1); @@ -651,6 +669,8 @@ Result<> ReadCSVFileFilter::executeImpl(DataStructure& dataStructure, const Argu headers = readCSVData.customHeaders; } + headers = RemoveIllegalCharacters(headers); + DataPath groupPath = createdDataGroup; if(useExistingGroup) { diff --git a/src/Plugins/SimplnxCore/test/ReadCSVFileTest.cpp b/src/Plugins/SimplnxCore/test/ReadCSVFileTest.cpp index 99c108ac14..f776f00b7c 100644 --- a/src/Plugins/SimplnxCore/test/ReadCSVFileTest.cpp +++ b/src/Plugins/SimplnxCore/test/ReadCSVFileTest.cpp @@ -206,9 +206,16 @@ void TestCase_TestImporterData_Error(const std::string& inputFilePath, usize sta // Execute the filter and check the result auto executeResult = filter.execute(dataStructure, args); - SIMPLNX_RESULT_REQUIRE_INVALID(executeResult.result); - REQUIRE(executeResult.result.errors().size() == 1); - REQUIRE(executeResult.result.errors()[0].code == expectedErrorCode); + if(expectedErrorCode == 0) + { + SIMPLNX_RESULT_REQUIRE_VALID(executeResult.result); + } + else + { + SIMPLNX_RESULT_REQUIRE_INVALID(executeResult.result); + REQUIRE(executeResult.result.errors().size() == 1); + REQUIRE(executeResult.result.errors()[0].code == expectedErrorCode); + } } TEST_CASE("SimplnxCore::ReadCSVFileFilter (Case 1): Valid filter execution") @@ -456,23 +463,23 @@ TEST_CASE("SimplnxCore::ReadCSVFileFilter (Case 5): Invalid filter execution - I std::vector illegalHeaders = {"Illegal/Header"}; CreateTestDataFile(tmp_file, v, illegalHeaders); - TestCase_TestImporterData_Error(tmp_file.string(), 2, ReadCSVData::HeaderMode::LINE, 1, {','}, {}, {DataType::int8}, {false}, tupleDims, v, k_IllegalNames); - TestCase_TestImporterData_Error(tmp_file.string(), 2, ReadCSVData::HeaderMode::CUSTOM, 1, {','}, illegalHeaders, {DataType::int8}, {false}, tupleDims, v, k_IllegalNames); + TestCase_TestImporterData_Error(tmp_file.string(), 2, ReadCSVData::HeaderMode::LINE, 1, {','}, {}, {DataType::int8}, {false}, tupleDims, v, 0); + TestCase_TestImporterData_Error(tmp_file.string(), 2, ReadCSVData::HeaderMode::CUSTOM, 1, {','}, illegalHeaders, {DataType::int8}, {false}, tupleDims, v, 0); illegalHeaders = {"Illegal\\Header"}; CreateTestDataFile(tmp_file, v, illegalHeaders); - TestCase_TestImporterData_Error(tmp_file.string(), 2, ReadCSVData::HeaderMode::LINE, 1, {','}, {}, {DataType::int8}, {false}, tupleDims, v, k_IllegalNames); - TestCase_TestImporterData_Error(tmp_file.string(), 2, ReadCSVData::HeaderMode::CUSTOM, 1, {','}, illegalHeaders, {DataType::int8}, {false}, tupleDims, v, k_IllegalNames); + TestCase_TestImporterData_Error(tmp_file.string(), 2, ReadCSVData::HeaderMode::LINE, 1, {','}, {}, {DataType::int8}, {false}, tupleDims, v, 0); + TestCase_TestImporterData_Error(tmp_file.string(), 2, ReadCSVData::HeaderMode::CUSTOM, 1, {','}, illegalHeaders, {DataType::int8}, {false}, tupleDims, v, 0); illegalHeaders = {"Illegal&Header"}; CreateTestDataFile(tmp_file, v, illegalHeaders); - TestCase_TestImporterData_Error(tmp_file.string(), 2, ReadCSVData::HeaderMode::LINE, 1, {','}, {}, {DataType::int8}, {false}, tupleDims, v, k_IllegalNames); - TestCase_TestImporterData_Error(tmp_file.string(), 2, ReadCSVData::HeaderMode::CUSTOM, 1, {','}, illegalHeaders, {DataType::int8}, {false}, tupleDims, v, k_IllegalNames); + TestCase_TestImporterData_Error(tmp_file.string(), 2, ReadCSVData::HeaderMode::LINE, 1, {','}, {}, {DataType::int8}, {false}, tupleDims, v, 0); + TestCase_TestImporterData_Error(tmp_file.string(), 2, ReadCSVData::HeaderMode::CUSTOM, 1, {','}, illegalHeaders, {DataType::int8}, {false}, tupleDims, v, 0); illegalHeaders = {"Illegal:Header"}; CreateTestDataFile(tmp_file, v, illegalHeaders); - TestCase_TestImporterData_Error(tmp_file.string(), 2, ReadCSVData::HeaderMode::LINE, 1, {','}, {}, {DataType::int8}, {false}, tupleDims, v, k_IllegalNames); - TestCase_TestImporterData_Error(tmp_file.string(), 2, ReadCSVData::HeaderMode::CUSTOM, 1, {','}, illegalHeaders, {DataType::int8}, {false}, tupleDims, v, k_IllegalNames); + TestCase_TestImporterData_Error(tmp_file.string(), 2, ReadCSVData::HeaderMode::LINE, 1, {','}, {}, {DataType::int8}, {false}, tupleDims, v, 0); + TestCase_TestImporterData_Error(tmp_file.string(), 2, ReadCSVData::HeaderMode::CUSTOM, 1, {','}, illegalHeaders, {DataType::int8}, {false}, tupleDims, v, 0); fs::remove(tmp_file); diff --git a/src/simplnx/DataStructure/DataPath.cpp b/src/simplnx/DataStructure/DataPath.cpp index 9b6d56979c..619d06e451 100644 --- a/src/simplnx/DataStructure/DataPath.cpp +++ b/src/simplnx/DataStructure/DataPath.cpp @@ -22,7 +22,7 @@ DataPath::DataPath(std::vector path) { if(!DataObject::IsValidName(item) && !item.empty()) { - throw std::invalid_argument("DataPath: Invalid DataObject name"); + throw std::invalid_argument(fmt::format("DataPath: Invalid DataObject name - [{}]. One of the DataObject names contains the '/' character.", fmt::join(m_Path, ","))); } } } diff --git a/src/simplnx/Utilities/StringUtilities.hpp b/src/simplnx/Utilities/StringUtilities.hpp index 50ee3192e2..9a92915c82 100644 --- a/src/simplnx/Utilities/StringUtilities.hpp +++ b/src/simplnx/Utilities/StringUtilities.hpp @@ -166,24 +166,24 @@ inline constexpr StringLiteral k_Whitespaces = " \t\f\v\n\r"; /** * @brief Replace characters in a string. If 'from' is empty, the origin string is returned. - * @param str Input String + * @param inputString Input String * @param from Characters to replace (These characters are being replaced) * @param to The characters to be used as the replacement * @return The modified string */ -inline std::string replace(std::string str, std::string_view from, std::string_view to) +inline std::string replace(std::string inputString, std::string_view from, std::string_view to) { usize startPos = 0; if(from.empty()) { - return str; + return inputString; } - while((startPos = str.find(from, startPos)) != std::string::npos) + while((startPos = inputString.find(from, startPos)) != std::string::npos) { - str.replace(startPos, from.length(), to); + inputString.replace(startPos, from.length(), to); startPos += to.length(); } - return str; + return inputString; } inline std::string ltrim(std::string_view str)