diff --git a/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/CopyDataObjectFilter.cpp b/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/CopyDataObjectFilter.cpp index cf1f5fd366..12c1c74045 100644 --- a/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/CopyDataObjectFilter.cpp +++ b/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/CopyDataObjectFilter.cpp @@ -1,5 +1,6 @@ #include "CopyDataObjectFilter.hpp" +#include "simplnx/DataStructure/AttributeMatrix.hpp" #include "simplnx/DataStructure/BaseGroup.hpp" #include "simplnx/Filter/Actions/CopyDataObjectAction.hpp" #include "simplnx/Parameters/BoolParameter.hpp" @@ -80,7 +81,7 @@ IFilter::PreflightResult CopyDataObjectFilter::preflightImpl(const DataStructure return {MakeErrorResult(-27360, "Copied Object(s) have the same parent as original data but the suffix is empty."), {}}; } - OutputActions actions; + Result resultOutputActions; for(const auto& dataArrayPath : dataArrayPaths) { @@ -88,6 +89,27 @@ IFilter::PreflightResult CopyDataObjectFilter::preflightImpl(const DataStructure if(useNewParent) { parentPath = args.value(k_NewPath_Key); + // Scope AM check since we fully expect it to be a nullptr + { + const auto* possibleAM = data.getDataAs(parentPath); + if(possibleAM != nullptr) + { + for(const auto& path : dataArrayPaths) + { + const auto* possibleIArray = data.getDataAs(path); + if(possibleIArray != nullptr) + { + if(possibleAM->getShape() != possibleIArray->getTupleShape()) + { + resultOutputActions.warnings().push_back( + Warning{-27361, fmt::format("The tuple dimensions of {} [{}] do not match the AttributeMatrix {} tuple dimensions [{}]. This could result in a runtime error if the sizing remains " + "the same at time of this filters execution. Proceed with caution.", + possibleIArray->getName(), possibleIArray->getNumberOfTuples(), possibleAM->getName(), possibleAM->getNumTuples())}); + } + } + } + } + } } std::string newTargetName = dataArrayPath.getTargetName() + suffix; DataPath newDataPath = parentPath.createChildPath(newTargetName); @@ -100,16 +122,16 @@ IFilter::PreflightResult CopyDataObjectFilter::preflightImpl(const DataStructure { for(const auto& sourcePath : pathsToBeCopied.value()) { - std::string createdPathName = nx::core::StringUtilities::replace(sourcePath.toString(), dataArrayPath.getTargetName(), newTargetName); + std::string createdPathName = StringUtilities::replace(sourcePath.toString(), dataArrayPath.getTargetName(), newTargetName); allCreatedPaths.push_back(DataPath::FromString(createdPathName).value()); } } } auto action = std::make_unique(dataArrayPath, newDataPath, allCreatedPaths); - actions.appendAction(std::move(action)); + resultOutputActions.value().appendAction(std::move(action)); } - return {std::move(actions)}; + return {std::move(resultOutputActions)}; } //------------------------------------------------------------------------------ diff --git a/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/MoveData.cpp b/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/MoveData.cpp index 7fcb2d213b..bef5c64ad8 100644 --- a/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/MoveData.cpp +++ b/src/Plugins/SimplnxCore/src/SimplnxCore/Filters/MoveData.cpp @@ -1,5 +1,6 @@ #include "MoveData.hpp" +#include "simplnx/DataStructure/AttributeMatrix.hpp" #include "simplnx/DataStructure/BaseGroup.hpp" #include "simplnx/Filter/Actions/MoveDataAction.hpp" #include "simplnx/Parameters/DataGroupSelectionParameter.hpp" @@ -10,13 +11,6 @@ namespace nx::core { -namespace -{ -constexpr int64 k_TupleCountInvalidError = -250; -constexpr int64 k_MissingFeaturePhasesError = -251; - -} // namespace - //------------------------------------------------------------------------------ std::string MoveData::name() const { @@ -74,6 +68,27 @@ IFilter::PreflightResult MoveData::preflightImpl(const DataStructure& data, cons Result resultOutputActions; std::vector preflightUpdatedValues; + // Scope AM check since we fully expect it to be a nullptr + { + const auto* possibleAM = data.getDataAs(newParentPath); + if(possibleAM != nullptr) + { + for(const auto& path : dataPaths) + { + const auto* possibleIArray = data.getDataAs(path); + if(possibleIArray != nullptr) + { + if(possibleAM->getShape() != possibleIArray->getTupleShape()) + { + resultOutputActions.warnings().push_back(Warning{-69250, fmt::format("The tuple dimensions of {} [{}] do not match the AttributeMatrix {} tuple dimensions [{}]. This could result in a " + "runtime error if the sizing remains the same at time of this filters execution. Proceed with caution.", + possibleIArray->getName(), possibleIArray->getNumberOfTuples(), possibleAM->getName(), possibleAM->getNumTuples())}); + } + } + } + } + } + for(const auto& dataPath : dataPaths) { auto moveDataAction = std::make_unique(dataPath, newParentPath); diff --git a/src/Plugins/SimplnxCore/test/CopyDataObjectTest.cpp b/src/Plugins/SimplnxCore/test/CopyDataObjectTest.cpp index ab92ec1bcb..b9e9b11352 100644 --- a/src/Plugins/SimplnxCore/test/CopyDataObjectTest.cpp +++ b/src/Plugins/SimplnxCore/test/CopyDataObjectTest.cpp @@ -8,6 +8,11 @@ using namespace nx::core; +namespace +{ +const int32 k_TupleDimMismatchWarningCode = -27361; +} + TEST_CASE("SimplnxCore::CopyDataObjectFilter(Valid Execution)", "[SimplnxCore][CopyDataObjectFilter]") { static const DataPath k_DataPath1({Constants::k_SmallIN100, "Phase Data"}); @@ -95,6 +100,22 @@ TEST_CASE("SimplnxCore::CopyDataObjectFilter(Invalid Parameters)", "[SimplnxCore args.insert(CopyDataObjectFilter::k_NewPath_Key, std::make_any(copyPath)); args.insert(CopyDataObjectFilter::k_NewPathSuffix_Key, std::make_any("_COPY")); + // Preflight the filter and check result + auto preflightResult = filter.preflight(dataStructure, args); + + REQUIRE_FALSE(preflightResult.outputActions.warnings().empty()); + + bool found = false; + for(const auto& warning : preflightResult.outputActions.warnings()) + { + if(warning.code == ::k_TupleDimMismatchWarningCode) + { + found = true; + } + } + + REQUIRE(found); + auto result = filter.execute(dataStructure, args); SIMPLNX_RESULT_REQUIRE_INVALID(result.result); } diff --git a/src/Plugins/SimplnxCore/test/MoveDataTest.cpp b/src/Plugins/SimplnxCore/test/MoveDataTest.cpp index e57188d8e6..b61adc36f9 100644 --- a/src/Plugins/SimplnxCore/test/MoveDataTest.cpp +++ b/src/Plugins/SimplnxCore/test/MoveDataTest.cpp @@ -1,5 +1,7 @@ #include "SimplnxCore/Filters/MoveData.hpp" +#include "simplnx/DataStructure/AttributeMatrix.hpp" +#include "simplnx/DataStructure/DataArray.hpp" #include "simplnx/DataStructure/DataGroup.hpp" #include "simplnx/UnitTest/UnitTestCommon.hpp" @@ -16,6 +18,11 @@ constexpr StringLiteral k_Group2Name = "Group2"; constexpr StringLiteral k_Group3Name = "Group3"; constexpr StringLiteral k_Group4Name = "Group4"; +const int32 k_TupleDimMismatchWarningCode = -69250; + +constexpr StringLiteral k_AM1Name = "Matrix1"; +constexpr StringLiteral k_DataArray1Name = "Array1"; + DataStructure createDataStructure() { DataStructure data; @@ -24,6 +31,11 @@ DataStructure createDataStructure() auto group3 = DataGroup::Create(data, k_Group3Name, group2->getId()); auto group4 = DataGroup::Create(data, k_Group4Name, group2->getId()); + auto am1 = AttributeMatrix::Create(data, k_AM1Name, std::vector{2}); + + auto dataStore = std::make_unique>(std::vector{20}, std::vector{3}, 0); + auto dataArray1 = DataArray::Create(data, k_DataArray1Name, std::move(dataStore)); + data.setAdditionalParent(group4->getId(), group3->getId()); return data; } @@ -80,19 +92,61 @@ TEST_CASE("SimplnxCore::MoveData Unsuccessful", "[Complex::Core][MoveData]") { args.insertOrAssign(MoveData::k_Data_Key, std::make_any>({k_Group3Path})); args.insertOrAssign(MoveData::k_NewParent_Key, std::make_any(k_Group2Path)); + + // Preflight the filter and check result + auto preflightResult = filter.preflight(dataStructure, args); + SIMPLNX_RESULT_REQUIRE_INVALID(preflightResult.outputActions); } SECTION("Cannot reparent object to itself") { args.insertOrAssign(MoveData::k_Data_Key, std::make_any>({k_Group3Path})); args.insertOrAssign(MoveData::k_NewParent_Key, std::make_any(k_Group3Path)); + + // Preflight the filter and check result + auto preflightResult = filter.preflight(dataStructure, args); + SIMPLNX_RESULT_REQUIRE_INVALID(preflightResult.outputActions); } SECTION("Cannot reparent object to a child object") { args.insertOrAssign(MoveData::k_Data_Key, std::make_any>({k_Group2Path})); args.insertOrAssign(MoveData::k_NewParent_Key, std::make_any(k_Group3Path)); + + // Preflight the filter and check result + auto preflightResult = filter.preflight(dataStructure, args); + SIMPLNX_RESULT_REQUIRE_INVALID(preflightResult.outputActions); } +} + +TEST_CASE("SimplnxCore::MoveData Tuple Size Mismatches Warning and Failure", "[Complex::Core][MoveData]") +{ + MoveData filter; + Arguments args; + DataStructure dataStructure = createDataStructure(); + + const DataPath k_DataArrayPath({k_DataArray1Name}); + const DataPath k_AMPath({k_AM1Name}); + + args.insertOrAssign(MoveData::k_Data_Key, std::make_any>({k_DataArrayPath})); + args.insertOrAssign(MoveData::k_NewParent_Key, std::make_any(k_AMPath)); // Preflight the filter and check result auto preflightResult = filter.preflight(dataStructure, args); - SIMPLNX_RESULT_REQUIRE_INVALID(preflightResult.outputActions); + + REQUIRE_FALSE(preflightResult.outputActions.warnings().empty()); + + bool found = false; + for(const auto& warning : preflightResult.outputActions.warnings()) + { + if(warning.code == ::k_TupleDimMismatchWarningCode) + { + found = true; + } + } + + REQUIRE(found); + + SIMPLNX_RESULT_REQUIRE_VALID(preflightResult.outputActions); + + auto result = filter.execute(dataStructure, args); + SIMPLNX_RESULT_REQUIRE_INVALID(result.result); } diff --git a/src/simplnx/Filter/Actions/MoveDataAction.cpp b/src/simplnx/Filter/Actions/MoveDataAction.cpp index 9a8e75fdc9..4eb0492cdd 100644 --- a/src/simplnx/Filter/Actions/MoveDataAction.cpp +++ b/src/simplnx/Filter/Actions/MoveDataAction.cpp @@ -1,7 +1,6 @@ #include "MoveDataAction.hpp" #include "simplnx/DataStructure/BaseGroup.hpp" -#include "simplnx/Utilities/DataArrayUtilities.hpp" #include