diff --git a/Modules/Core/include/mitkPropertyKeyPath.h b/Modules/Core/include/mitkPropertyKeyPath.h index 525503f634..134bb8e9ff 100644 --- a/Modules/Core/include/mitkPropertyKeyPath.h +++ b/Modules/Core/include/mitkPropertyKeyPath.h @@ -1,214 +1,216 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef mitkPropertyKeyPath_h #define mitkPropertyKeyPath_h #include #include #include #include namespace mitk { /** @brief Class that can be used to specify nested or wild carded property keys. E.g. * for the use in context of the property persistence service or the property relation service.\n * Following assumptions are made /preconditions are defined: * - A property key is partitioned by "." into nodes (c.f. visualization of property keys in the PropertyView). * - A node can either be an element or a selection. * - An element has a name (alphanumric, - and space; "A-Za-z0-9- ") or is wildcarded ("*") * - A selection is either an index (e.g. "[1]") or a wildcard ("[*]"). * * Selections are used to indicate that the preceding element has multiple occurences and which occurence is meant. * Example property keys would be: * - prop : A simple property key * - prop.subprop1 : A property key consting of two nodes * - prop.* : Any property key that starts with a node "prop" * - prop.sub.[2] : A property key that starts with a node "prop" and a has a second node that is selection and has * the index 2. * - prop.sub.[*] : Any property key that starts with a node "prop" and a has a second node that is selection (with * any index). * * To build a path one may use the Add* method to build up the PropertyKeyPath element by element.\n * "first.*.third.[3]" would be equivalent to * propKeyPath.AddElement("first"); * propKeyPath.AddAnyElement(); * propKeyPath.AddSelection("third",3);\n * or the inline version * propKeyPath.AddElement("first").AddAnyElement().AddSelection("third",3); */ class MITKCORE_EXPORT PropertyKeyPath final { public: using ItemSelectionIndex = std::size_t; using ElementNameType = std::string; struct MITKCORE_EXPORT NodeInfo { enum class NodeType { Invalid = 0, //*< Node does not exist or is invalid. Element, //*< Selects an specific element given the node name. ElementSelection, //*< Selects an specific item in a sequence of items and has a item selector ("[n]"). AnySelection, //*< Selects all items of a specific element ("[*]"). AnyElement //*< Selects any element/item. Node name is wildcarded ("*"); item selection as well implictily. }; NodeType type; ElementNameType name; ItemSelectionIndex selection; NodeInfo(); NodeInfo(const ElementNameType &name, NodeType type = NodeType::Element, ItemSelectionIndex index = 0); bool Matches(const NodeInfo &right) const; bool operator==(const NodeInfo &right) const; }; using NodeInfoVectorType = std::vector; using PathIndexType = NodeInfoVectorType::size_type; /** Returns if the PropertyKeyPath is empty.*/ bool IsEmpty() const; /** Returns if the path is explicit (has no wildcards).*/ bool IsExplicit() const; /** Returns if the path has any nodes with item selection wild cards ([*]).*/ bool HasItemSelectionWildcardsOnly() const; /** Number of path nodes the PropertyKeyPath contains.*/ PathIndexType GetSize() const; /** Adds a new node to the end of the path. \param [in] newNode Reference to the node that should be added. \return Returns the index of the newly added node.*/ PathIndexType AddNode(const NodeInfo &newNode); /** Function returns the node info of a path node specified by the index * within the PropertyKeyPath. * \pre Passed index must not be out of bounds. * \param [in] index Index of the node whose info should be retrieved. * \return Info of the specified path node. If the index is out of bound an InvalidPathNode exception will be * thrown.*/ const NodeInfo &GetNode(const PathIndexType &index) const; /** Function returns the node info of a path node specified by the index * within the PropertyKeyPath. * \pre Passed index must not be out of bounds. * \param [in] index Index of the node whose info should be retrieved. * \return Info of the specified path node. If the index is out of bound an InvalidPathNode exception will be * thrown.*/ NodeInfo &GetNode(const PathIndexType &index); /** Function returns the node info of the first path node within the PropertyKeyPath. * \pre PropertyKeyPath must not be empty. * \return Info of the first path node. If the path is empty, an InvalidPathNode exception will be thrown.*/ NodeInfo &GetFirstNode(); /** Function returns the node info of the first path node within the PropertyKeyPath. * \pre PropertyKeyPath must not be empty. * \return Info of the first path node. If the path is empty, an InvalidPathNode exception will be thrown.*/ const NodeInfo &GetFirstNode() const; /** Function returns the node info of the last path node within the PropertyKeyPath. * \pre PropertyKeyPath must not be empty. * \return Info of the first path node. If the path is empty, an InvalidPathNode exception will be thrown.*/ NodeInfo &GetLastNode(); /** Function returns the node info of the last path node within the PropertyKeyPath. * \pre PropertyKeyPath must not be empty. * \return Info of the first path node. If the path is empty, an InvalidPathNode exception will be thrown.*/ const NodeInfo &GetLastNode() const; const NodeInfoVectorType &GetNodes() const; /**Compares two PropertyKeyPaths for real equality. So it is a string comparison of their string conversion.*/ bool operator==(const PropertyKeyPath &path) const; /**Operation equals like comparing the ToStr() results with operator <.*/ bool operator<(const PropertyKeyPath &right) const; /**Operation equals like comparing the ToStr() results with operator <=.*/ bool operator<=(const PropertyKeyPath &right) const; /**Operation equals like comparing the ToStr() results with operator >=.*/ bool operator>=(const PropertyKeyPath &right) const; /**Operation equals like comparing the ToStr() results with operator >.*/ bool operator>(const PropertyKeyPath &right) const; /**Checks if two PropertyKeyPaths specify the same node. Hence all wildcards will be processed.\n * E.G.: "item1.child1.grandChild2" == "item1.*.grandChild2" is true. * \remark If you want to check if two paths are "truly" equal and not only equal in terms of * pointing to the same node, use the member function operator ==().*/ bool Equals(const PropertyKeyPath &path) const; PropertyKeyPath &operator=(const PropertyKeyPath &path); /** Appends an "any element" to the path instance.*/ PropertyKeyPath &AddAnyElement(); /** Appends an element with the passed name to the path instance.*/ PropertyKeyPath &AddElement(const ElementNameType &name); /** Appends an element with the passed name and any selection to the path instance.*/ PropertyKeyPath &AddAnySelection(const ElementNameType &name); /** Appends an element with the passed name and selection index to the path instance.*/ PropertyKeyPath &AddSelection(const ElementNameType &name, ItemSelectionIndex index); PropertyKeyPath(); PropertyKeyPath(const PropertyKeyPath &path); + /** overload constructor that supports simple key pathes consisting only of elements.*/ + PropertyKeyPath(const std::initializer_list< ElementNameType >& list); ~PropertyKeyPath(); void Reset(); protected: NodeInfoVectorType m_NodeInfos; static bool PropertyKeyPathsMatch(const PropertyKeyPath &left, const PropertyKeyPath &right); }; class MITKCORE_EXPORT InvalidPathNodeException : public mitk::Exception { public: mitkExceptionClassMacro(InvalidPathNodeException, mitk::Exception); }; MITKCORE_EXPORT std::ostream &operator<<(std::ostream &os, const PropertyKeyPath &path); /**Helper function that converts a path PropertyKeyPath into a regex string that can be used to search for property keys (using std::regex) that are matched by the PropertyKeyPath. This function is used in context of the property persistence service.*/ MITKCORE_EXPORT std::string PropertyKeyPathToPropertyRegEx(const PropertyKeyPath &tagPath); /**Helper function that converts a path PropertyKeyPath into a regex string that can be used to search for property persistence keys (using std::regex) that are matched by the PropertyKeyPath. This function is used in context of the property persistence service.*/ MITKCORE_EXPORT std::string PropertyKeyPathToPersistenceKeyRegEx(const PropertyKeyPath &tagPath); /**Helper function that converts a path PropertyKeyPath into a regex that can be used as key template in a PropertyPersistanceInfo. This function is used in context of the property persistence service.*/ MITKCORE_EXPORT std::string PropertyKeyPathToPersistenceKeyTemplate(const PropertyKeyPath &tagPath); /**Helper function that converts a path PropertyKeyPath into a regex that can be used as name template in a PropertyPersistanceInfo. This function is used in context of the property persistence service.*/ MITKCORE_EXPORT std::string PropertyKeyPathToPersistenceNameTemplate(const PropertyKeyPath &tagPath); /** Converts the passed property name into a tag path. If the property name cannot be converted into a valid path, the returned path is empty.*/ MITKCORE_EXPORT PropertyKeyPath PropertyNameToPropertyKeyPath(const std::string &propertyName); /** returns the correct property name for a given PropertyKeyPath instance. */ MITKCORE_EXPORT std::string PropertyKeyPathToPropertyName(const PropertyKeyPath &tagPath); } // namespace mitk #endif diff --git a/Modules/Core/src/DataManagement/mitkPropertyKeyPath.cpp b/Modules/Core/src/DataManagement/mitkPropertyKeyPath.cpp index 83a2993207..27fa3f08a1 100644 --- a/Modules/Core/src/DataManagement/mitkPropertyKeyPath.cpp +++ b/Modules/Core/src/DataManagement/mitkPropertyKeyPath.cpp @@ -1,596 +1,605 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include #include #include #include #include namespace mitk { PropertyKeyPath::NodeInfo::NodeInfo() : type(NodeType::Invalid), selection(0){}; PropertyKeyPath::NodeInfo::NodeInfo(const ElementNameType &name, NodeType type, ItemSelectionIndex index) : type(type), name(name), selection(index){}; bool PropertyKeyPath::NodeInfo::operator==(const NodeInfo &right) const { if (this->name != right.name) return false; if (this->type != right.type) return false; if (this->selection != right.selection) return false; return true; }; bool PropertyKeyPath::NodeInfo::Matches(const NodeInfo &right) const { if (type == NodeType::Invalid || right.type == NodeType::Invalid) { return false; } else if (type == NodeType::AnyElement || right.type == NodeType::AnyElement) { return true; } else if (name == right.name) { if (type == NodeType::Element && right.type == NodeType::Element) { return true; } else if (selection == right.selection || type == NodeType::AnySelection || right.type == NodeType::AnySelection) { return true; } } return false; }; bool PropertyKeyPath::IsEmpty() const { return m_NodeInfos.empty(); }; bool PropertyKeyPath::IsExplicit() const { for (const auto &pos : m_NodeInfos) { if ((pos.type == NodeInfo::NodeType::AnySelection) || (pos.type == NodeInfo::NodeType::AnyElement)) { return false; } } return true; }; bool PropertyKeyPath::HasItemSelectionWildcardsOnly() const { bool result = false; for (const auto &pos : m_NodeInfos) { if (pos.type == NodeInfo::NodeType::AnyElement) { return false; } result = result || pos.type == NodeInfo::NodeType::AnySelection; } return result; }; PropertyKeyPath::PathIndexType PropertyKeyPath::GetSize() const { return m_NodeInfos.size(); } PropertyKeyPath::PathIndexType PropertyKeyPath::AddNode(const NodeInfo &newNode) { m_NodeInfos.push_back(newNode); return m_NodeInfos.size() - 1; }; const PropertyKeyPath::NodeInfo &PropertyKeyPath::GetNode(const PathIndexType &index) const { if (index >= GetSize()) { mitkThrowException(InvalidPathNodeException) << "Error. Cannot return info of path node. Node index is out of bounds. Index: " << index << "; Path: " << PropertyKeyPathToPropertyName(*this); } return m_NodeInfos[index]; }; PropertyKeyPath::NodeInfo &PropertyKeyPath::GetNode(const PathIndexType &index) { if (index >= this->GetSize()) { mitkThrowException(InvalidPathNodeException) << "Error. Cannot return info of path node. Node index is out of bounds. Index: " << index << "; Path: " << PropertyKeyPathToPropertyName(*this); } return m_NodeInfos[index]; }; const PropertyKeyPath::NodeInfo &PropertyKeyPath::GetFirstNode() const { if (m_NodeInfos.empty()) { mitkThrowException(InvalidPathNodeException) << "Error. Cannot return first path node. Path is empty."; } return this->GetNode(0); }; PropertyKeyPath::NodeInfo &PropertyKeyPath::GetFirstNode() { if (m_NodeInfos.empty()) { mitkThrowException(InvalidPathNodeException) << "Error. Cannot return first path node. Path is empty."; } return this->GetNode(0); }; const PropertyKeyPath::NodeInfo &PropertyKeyPath::GetLastNode() const { if (m_NodeInfos.empty()) { mitkThrowException(InvalidPathNodeException) << "Error. Cannot return last path node. Path is empty."; } return this->GetNode(GetSize() - 1); }; PropertyKeyPath::NodeInfo &PropertyKeyPath::GetLastNode() { if (m_NodeInfos.empty()) { mitkThrowException(InvalidPathNodeException) << "Error. Cannot return last path node. Path is empty."; } return this->GetNode(GetSize() - 1); }; const PropertyKeyPath::NodeInfoVectorType &PropertyKeyPath::GetNodes() const { return m_NodeInfos; }; bool PropertyKeyPath::operator==(const PropertyKeyPath &path) const { return m_NodeInfos == path.m_NodeInfos; }; bool PropertyKeyPath::operator<(const PropertyKeyPath &right) const { auto rightIter = right.m_NodeInfos.cbegin(); const auto rightEnd = right.m_NodeInfos.cend(); for (const auto &leftPos : m_NodeInfos) { if (rightIter == rightEnd) { return false; } if (leftPos.name < rightIter->name) { return true; } if (rightIter->name < leftPos.name) { return false; } if (leftPos.type < rightIter->type) { return true; } if (rightIter->type < leftPos.type) { return false; } if (leftPos.selection < rightIter->selection) { return true; } if (rightIter->selection < leftPos.selection) { return false; } ++rightIter; } return rightIter != rightEnd; } bool PropertyKeyPath::operator>(const PropertyKeyPath &right) const { auto rightIter = right.m_NodeInfos.cbegin(); const auto rightEnd = right.m_NodeInfos.cend(); for (const auto &leftPos : m_NodeInfos) { if (rightIter == rightEnd) return false; if (leftPos.name > rightIter->name) return true; if (rightIter->name > leftPos.name) return false; if (leftPos.type > rightIter->type) return true; if (rightIter->type > leftPos.type) return false; if (leftPos.selection > rightIter->selection) return true; if (rightIter->selection > leftPos.selection) return false; ++rightIter; } return rightIter != rightEnd; } bool PropertyKeyPath::operator>=(const PropertyKeyPath &right) const { return !(*this < right); } bool PropertyKeyPath::operator<=(const PropertyKeyPath &right) const { return !(*this > right); } bool PropertyKeyPath::Equals(const PropertyKeyPath &path) const { return PropertyKeyPathsMatch(*this, path); }; PropertyKeyPath &PropertyKeyPath::operator=(const PropertyKeyPath &path) { if (this != &path) { m_NodeInfos = path.m_NodeInfos; } return *this; }; PropertyKeyPath &PropertyKeyPath::AddAnyElement() { m_NodeInfos.emplace_back("", NodeInfo::NodeType::AnyElement); return *this; }; PropertyKeyPath &PropertyKeyPath::AddElement(const ElementNameType &name) { m_NodeInfos.emplace_back(name, NodeInfo::NodeType::Element); return *this; }; PropertyKeyPath &PropertyKeyPath::AddAnySelection(const ElementNameType &name) { m_NodeInfos.emplace_back(name, NodeInfo::NodeType::AnySelection); return *this; }; PropertyKeyPath &PropertyKeyPath::AddSelection(const ElementNameType &name, ItemSelectionIndex index) { m_NodeInfos.emplace_back(name, NodeInfo::NodeType::ElementSelection, index); return *this; }; PropertyKeyPath::PropertyKeyPath() { this->Reset(); }; PropertyKeyPath::PropertyKeyPath(const PropertyKeyPath &path) { *this = path; }; + PropertyKeyPath::PropertyKeyPath(const std::initializer_list< ElementNameType >& list) + { + this->Reset(); + for (const auto& name : list) + { + this->AddElement(name); + } + } + PropertyKeyPath::~PropertyKeyPath(){}; void PropertyKeyPath::Reset() { m_NodeInfos.clear(); }; bool PropertyKeyPath::PropertyKeyPathsMatch(const PropertyKeyPath &left, const PropertyKeyPath &right) { auto leftPos = left.GetNodes().cbegin(); auto rightPos = right.GetNodes().cbegin(); auto leftEnd = left.GetNodes().cend(); auto rightEnd = right.GetNodes().cend(); while (leftPos != leftEnd && rightPos != rightEnd) { if (!leftPos->Matches(*rightPos)) { break; } ++leftPos; ++rightPos; } if (leftPos == leftEnd && rightPos == rightEnd) { return true; } else { return false; } }; std::ostream &operator<<(std::ostream &os, const PropertyKeyPath &value) { os << PropertyKeyPathToPropertyName(value); return os; }; std::string PropertyKeyPathToPropertyRegEx(const PropertyKeyPath &tagPath) { std::ostringstream nameStream; PropertyKeyPath::PathIndexType i = 0; for (const auto &node : tagPath.GetNodes()) { if (i) { nameStream << "\\."; } ++i; if (node.type == PropertyKeyPath::NodeInfo::NodeType::AnyElement) { nameStream << "([a-zA-Z0-9- ]+)"; } else if (node.type != PropertyKeyPath::NodeInfo::NodeType::Invalid) { nameStream << node.name; if (node.type == PropertyKeyPath::NodeInfo::NodeType::ElementSelection) { nameStream << "\\.\\[" << node.selection << "\\]"; } else if (node.type == PropertyKeyPath::NodeInfo::NodeType::AnySelection) { nameStream << "\\.\\[(\\d*)\\]"; } } else { nameStream << "INVALIDNODE"; } } return nameStream.str(); }; std::string PropertyKeyPathToPersistenceKeyRegEx(const PropertyKeyPath &tagPath) { std::ostringstream nameStream; PropertyKeyPath::PathIndexType i = 0; for (const auto &node : tagPath.GetNodes()) { if (i) { nameStream << "_"; } ++i; if (node.type == PropertyKeyPath::NodeInfo::NodeType::AnyElement) { nameStream << "([a-zA-Z0-9- ]+)"; } else if (node.type != PropertyKeyPath::NodeInfo::NodeType::Invalid) { nameStream << node.name; if (node.type == PropertyKeyPath::NodeInfo::NodeType::ElementSelection) { nameStream << "_\\[" << node.selection << "\\]"; } else if (node.type == PropertyKeyPath::NodeInfo::NodeType::AnySelection) { nameStream << "_\\[(\\d*)\\]"; } } else { nameStream << "INVALIDNODE"; } } return nameStream.str(); }; std::string PropertyKeyPathToPersistenceKeyTemplate(const PropertyKeyPath &tagPath) { std::ostringstream nameStream; int captureGroup = 1; PropertyKeyPath::PathIndexType i = 0; for (const auto &node : tagPath.GetNodes()) { if (i) { nameStream << "_"; } ++i; if (node.type == PropertyKeyPath::NodeInfo::NodeType::AnyElement) { nameStream << "$" << captureGroup++; } else if (node.type != PropertyKeyPath::NodeInfo::NodeType::Invalid) { nameStream << node.name; if (node.type == PropertyKeyPath::NodeInfo::NodeType::ElementSelection) { nameStream << "_[" << node.selection << "]"; } else if (node.type == PropertyKeyPath::NodeInfo::NodeType::AnySelection) { nameStream << "_[$" << captureGroup++ << "]"; } } else { nameStream << "INVALID_NODE"; } } return nameStream.str(); }; std::string PropertyKeyPathToPersistenceNameTemplate(const PropertyKeyPath &tagPath) { std::ostringstream nameStream; int captureGroup = 1; PropertyKeyPath::PathIndexType i = 0; for (const auto &node : tagPath.GetNodes()) { if (i) { nameStream << "."; } ++i; if (node.type == PropertyKeyPath::NodeInfo::NodeType::AnyElement) { nameStream << "$" << captureGroup++; } else if (node.type != PropertyKeyPath::NodeInfo::NodeType::Invalid) { nameStream << node.name; if (node.type == PropertyKeyPath::NodeInfo::NodeType::ElementSelection) { nameStream << ".[" << node.selection << "]"; } else if (node.type == PropertyKeyPath::NodeInfo::NodeType::AnySelection) { nameStream << ".[$" << captureGroup++ << "]"; } } else { nameStream << "INVALID_NODE"; } } return nameStream.str(); }; PropertyKeyPath PropertyNameToPropertyKeyPath(const std::string &propertyName) { PropertyKeyPath result; std::regex reg_element("([a-zA-Z0-9- ]+)"); std::regex reg_anySelection("\\[\\*\\]"); std::regex reg_Selection("\\[(\\d+)\\]"); std::istringstream f(propertyName); std::string subStr; PropertyKeyPath::ElementNameType name = ""; while (getline(f, subStr, '.')) { if (subStr == "*") { if (!name.empty()) { result.AddElement(name); name.clear(); } result.AddAnyElement(); } else { std::smatch sm; if (std::regex_match(subStr, sm, reg_anySelection)) { if (!name.empty()) { result.AddAnySelection(name); name.clear(); } else { // invalid path return PropertyKeyPath(); } } else if (std::regex_match(subStr, sm, reg_Selection)) { if (!name.empty()) { result.AddSelection(name, std::stoi(sm[1])); name.clear(); } else { // invalid path return PropertyKeyPath(); } } else if (std::regex_match(subStr, sm, reg_element)) { if (!name.empty()) { // store the last element and start the next result.AddElement(name); } name = sm[1]; } else { return PropertyKeyPath(); } } } if (!name.empty()) { // add last element result.AddElement(name); } return result; }; std::string PropertyKeyPathToPropertyName(const mitk::PropertyKeyPath &tagPath) { std::ostringstream nameStream; PropertyKeyPath::PathIndexType i = 0; for (const auto &node : tagPath.GetNodes()) { if (i) { nameStream << "."; } ++i; if (node.type == PropertyKeyPath::NodeInfo::NodeType::AnyElement) { nameStream << "*"; } else if (node.type != PropertyKeyPath::NodeInfo::NodeType::Invalid) { nameStream << node.name; if (node.type == PropertyKeyPath::NodeInfo::NodeType::ElementSelection) { nameStream << ".[" << node.selection << "]"; } else if (node.type == PropertyKeyPath::NodeInfo::NodeType::AnySelection) { nameStream << ".[*]"; } } else { nameStream << "INVALID_NODE"; } } return nameStream.str(); }; } // namespace mitk diff --git a/Modules/Core/test/mitkPropertyKeyPathTest.cpp b/Modules/Core/test/mitkPropertyKeyPathTest.cpp index 338df2a20f..2ef686768e 100644 --- a/Modules/Core/test/mitkPropertyKeyPathTest.cpp +++ b/Modules/Core/test/mitkPropertyKeyPathTest.cpp @@ -1,314 +1,321 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "mitkPropertyKeyPath.h" #include "mitkTestFixture.h" #include "mitkTestingMacros.h" #include class mitkPropertyKeyPathTestSuite : public mitk::TestFixture { CPPUNIT_TEST_SUITE(mitkPropertyKeyPathTestSuite); MITK_TEST(AccessFunctions); MITK_TEST(PropertyKeyPathToPropertyRegEx); MITK_TEST(PropertyKeyPathToPersistenceKeyRegEx); MITK_TEST(PropertyKeyPathToPersistenceKeyTemplate); MITK_TEST(PropertyKeyPathToPersistenceNameTemplate); MITK_TEST(PropertyNameToPropertyKeyPath); MITK_TEST(PropertyKeyPathToPropertyName); MITK_TEST(ExecutePropertyRegEx); MITK_TEST(Comparison); + MITK_TEST(InitializerList); CPPUNIT_TEST_SUITE_END(); private: mitk::PropertyKeyPath simplePath; mitk::PropertyKeyPath simplePath2; mitk::PropertyKeyPath deepPath; mitk::PropertyKeyPath deepPath_withAnyElement; mitk::PropertyKeyPath deepPath_withAnySelection; mitk::PropertyKeyPath deepPath_withSelection; mitk::PropertyKeyPath verydeepPath; mitk::PropertyKeyPath emptyPath; public: void setUp() override { simplePath.AddElement("simple"); simplePath2.AddElement("AA-11"); deepPath.AddElement("a").AddElement("b2").AddElement("c3"); deepPath_withAnyElement.AddElement("a"); deepPath_withAnyElement.AddAnyElement(); deepPath_withAnyElement.AddElement("c3"); deepPath_withAnySelection.AddElement("a"); deepPath_withAnySelection.AddAnySelection("b"); deepPath_withAnySelection.AddElement("c"); deepPath_withSelection.AddElement("a"); deepPath_withSelection.AddSelection("b", 6); deepPath_withSelection.AddElement("c"); verydeepPath.AddAnySelection("a"); verydeepPath.AddAnyElement(); verydeepPath.AddElement("c"); verydeepPath.AddSelection("d", 4); verydeepPath.AddElement("e"); } void tearDown() override {} void AccessFunctions() { const auto constEmptyPath = emptyPath; const auto constVerydeepPath = verydeepPath; CPPUNIT_ASSERT_THROW(emptyPath.GetFirstNode(), mitk::InvalidPathNodeException); CPPUNIT_ASSERT_THROW(emptyPath.GetLastNode(), mitk::InvalidPathNodeException); CPPUNIT_ASSERT_THROW(emptyPath.GetNode(0), mitk::InvalidPathNodeException); CPPUNIT_ASSERT_THROW(constEmptyPath.GetFirstNode(), mitk::InvalidPathNodeException); CPPUNIT_ASSERT_THROW(constEmptyPath.GetLastNode(), mitk::InvalidPathNodeException); CPPUNIT_ASSERT_THROW(constEmptyPath.GetNode(0), mitk::InvalidPathNodeException); CPPUNIT_ASSERT_EQUAL_MESSAGE( "Testing GetFirstNode with 'a.[*].*.c.d.[4].e'", std::string("a"), verydeepPath.GetFirstNode().name); CPPUNIT_ASSERT_EQUAL_MESSAGE( "Testing const GetFirstNode with 'a.[*].*.c.d.[4].e'", std::string("a"), constVerydeepPath.GetFirstNode().name); CPPUNIT_ASSERT_EQUAL_MESSAGE( "Testing GetLastNode with 'a.[*].*.c.d.[4].e'", std::string("e"), verydeepPath.GetLastNode().name); CPPUNIT_ASSERT_EQUAL_MESSAGE( "Testing GetLastNode with 'a.[*].*.c.d.[4].e'", std::string("e"), constVerydeepPath.GetLastNode().name); CPPUNIT_ASSERT_EQUAL_MESSAGE( "Testing GetNode(3) with 'a.[*].*.c.d.[4].e'", std::string("d"), verydeepPath.GetNode(3).name); CPPUNIT_ASSERT_EQUAL_MESSAGE( "Testing GetNode(3) with 'a.[*].*.c.d.[4].e'", std::string("d"), constVerydeepPath.GetNode(3).name); CPPUNIT_ASSERT(5 == constVerydeepPath.GetSize()); CPPUNIT_ASSERT(0 == emptyPath.GetSize()); } void PropertyKeyPathToPropertyRegEx() { std::string result = mitk::PropertyKeyPathToPropertyRegEx(simplePath); CPPUNIT_ASSERT_EQUAL_MESSAGE( "Testing PropertyKeyPathToPropertyRegEx() with 'simple'", std::string("simple"), result); result = mitk::PropertyKeyPathToPropertyRegEx(deepPath); CPPUNIT_ASSERT_EQUAL_MESSAGE( "Testing PropertyKeyPathToPropertyRegEx() with 'a.b2.c3'", std::string("a\\.b2\\.c3"), result); result = mitk::PropertyKeyPathToPropertyRegEx(deepPath_withAnyElement); CPPUNIT_ASSERT_EQUAL_MESSAGE( "Testing PropertyKeyPathToPropertyRegEx() with 'a.*.c3'", std::string("a\\.([a-zA-Z0-9- ]+)\\.c3"), result); result = mitk::PropertyKeyPathToPropertyRegEx(deepPath_withAnySelection); CPPUNIT_ASSERT_EQUAL_MESSAGE( "Testing PropertyKeyPathToPropertyRegEx() with 'a.b.[*].c'", std::string("a\\.b\\.\\[(\\d*)\\]\\.c"), result); result = mitk::PropertyKeyPathToPropertyRegEx(deepPath_withSelection); CPPUNIT_ASSERT_EQUAL_MESSAGE( "Testing PropertyKeyPathToPropertyRegEx() with 'a.b.[6].c'", std::string("a\\.b\\.\\[6\\]\\.c"), result); result = mitk::PropertyKeyPathToPropertyRegEx(verydeepPath); CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing PropertyKeyPathToPropertyRegEx() with 'a.[*].*.c.d.[4].e'", std::string("a\\.\\[(\\d*)\\]\\.([a-zA-Z0-9- ]+)\\.c\\.d\\.\\[4\\]\\.e"), result); } void PropertyKeyPathToPersistenceKeyRegEx() { std::string result = mitk::PropertyKeyPathToPersistenceKeyRegEx(simplePath); CPPUNIT_ASSERT_EQUAL_MESSAGE( "Testing PropertyKeyPathToPersistenceKeyRegEx() with 'simple'", std::string("simple"), result); result = mitk::PropertyKeyPathToPersistenceKeyRegEx(deepPath); CPPUNIT_ASSERT_EQUAL_MESSAGE( "Testing PropertyKeyPathToPersistenceKeyRegEx() with 'a.b2.c3'", std::string("a_b2_c3"), result); result = mitk::PropertyKeyPathToPersistenceKeyRegEx(deepPath_withAnyElement); CPPUNIT_ASSERT_EQUAL_MESSAGE( "Testing PropertyKeyPathToPersistenceKeyRegEx() with 'a.*.c3'", std::string("a_([a-zA-Z0-9- ]+)_c3"), result); result = mitk::PropertyKeyPathToPersistenceKeyRegEx(deepPath_withAnySelection); CPPUNIT_ASSERT_EQUAL_MESSAGE( "Testing PropertyKeyPathToPersistenceKeyRegEx() with 'a.b.[*].c'", std::string("a_b_\\[(\\d*)\\]_c"), result); result = mitk::PropertyKeyPathToPersistenceKeyRegEx(deepPath_withSelection); CPPUNIT_ASSERT_EQUAL_MESSAGE( "Testing PropertyKeyPathToPersistenceKeyRegEx() with 'a.b.[6].c'", std::string("a_b_\\[6\\]_c"), result); result = mitk::PropertyKeyPathToPersistenceKeyRegEx(verydeepPath); CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing PropertyKeyPathToPersistenceKeyRegEx() with 'a.[*].*.c.d.[4].e'", std::string("a_\\[(\\d*)\\]_([a-zA-Z0-9- ]+)_c_d_\\[4\\]_e"), result); } void PropertyKeyPathToPersistenceKeyTemplate() { std::string result = mitk::PropertyKeyPathToPersistenceKeyTemplate(simplePath); CPPUNIT_ASSERT_EQUAL_MESSAGE( "Testing PropertyKeyPathToPersistenceKeyTemplate() with 'simple'", std::string("simple"), result); result = mitk::PropertyKeyPathToPersistenceKeyTemplate(deepPath); CPPUNIT_ASSERT_EQUAL_MESSAGE( "Testing PropertyKeyPathToPersistenceKeyTemplate() with 'a.b2.c3'", std::string("a_b2_c3"), result); result = mitk::PropertyKeyPathToPersistenceKeyTemplate(deepPath_withAnyElement); CPPUNIT_ASSERT_EQUAL_MESSAGE( "Testing PropertyKeyPathToPersistenceKeyTemplate() with 'a.*.c3'", std::string("a_$1_c3"), result); result = mitk::PropertyKeyPathToPersistenceKeyTemplate(deepPath_withAnySelection); CPPUNIT_ASSERT_EQUAL_MESSAGE( "Testing PropertyKeyPathToPersistenceKeyTemplate() with 'a.b.[*].c'", std::string("a_b_[$1]_c"), result); result = mitk::PropertyKeyPathToPersistenceKeyTemplate(deepPath_withSelection); CPPUNIT_ASSERT_EQUAL_MESSAGE( "Testing PropertyKeyPathToPersistenceKeyTemplate() with 'a.b.[6].c'", std::string("a_b_[6]_c"), result); result = mitk::PropertyKeyPathToPersistenceKeyTemplate(verydeepPath); CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing PropertyKeyPathToPersistenceKeyTemplate() with 'a.[*].*.c.d.[4].e'", std::string("a_[$1]_$2_c_d_[4]_e"), result); } void PropertyKeyPathToPersistenceNameTemplate() { std::string result = mitk::PropertyKeyPathToPersistenceNameTemplate(simplePath); CPPUNIT_ASSERT_EQUAL_MESSAGE( "Testing PropertyKeyPathToPersistenceNameTemplate() with 'simple'", std::string("simple"), result); result = mitk::PropertyKeyPathToPersistenceNameTemplate(deepPath); CPPUNIT_ASSERT_EQUAL_MESSAGE( "Testing PropertyKeyPathToPersistenceNameTemplate() with 'a.b2.c3'", std::string("a.b2.c3"), result); result = mitk::PropertyKeyPathToPersistenceNameTemplate(deepPath_withAnyElement); CPPUNIT_ASSERT_EQUAL_MESSAGE( "Testing PropertyKeyPathToPersistenceNameTemplate() with 'a.*.c3'", std::string("a.$1.c3"), result); result = mitk::PropertyKeyPathToPersistenceNameTemplate(deepPath_withAnySelection); CPPUNIT_ASSERT_EQUAL_MESSAGE( "Testing PropertyKeyPathToPersistenceNameTemplate() with 'a.b.[*].c'", std::string("a.b.[$1].c"), result); result = mitk::PropertyKeyPathToPersistenceNameTemplate(deepPath_withSelection); CPPUNIT_ASSERT_EQUAL_MESSAGE( "Testing PropertyKeyPathToPersistenceNameTemplate() with 'a.b.[6].c'", std::string("a.b.[6].c"), result); result = mitk::PropertyKeyPathToPersistenceNameTemplate(verydeepPath); CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing PropertyKeyPathToPersistenceNameTemplate() with 'a.[*].*.c.d.[4].e'", std::string("a.[$1].$2.c.d.[4].e"), result); } void PropertyNameToPropertyKeyPath() { mitk::PropertyKeyPath result = mitk::PropertyNameToPropertyKeyPath("simple"); CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing PropertyNameToPropertyKeyPath() with 'simple'", simplePath, result); result = mitk::PropertyNameToPropertyKeyPath("a.b2.c3"); CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing PropertyNameToPropertyKeyPath() with 'a.b2.c3'", deepPath, result); result = mitk::PropertyNameToPropertyKeyPath("a.*.c3"); CPPUNIT_ASSERT_EQUAL_MESSAGE( "Testing PropertyNameToPropertyKeyPath() with 'a.*.c3'", deepPath_withAnyElement, result); result = mitk::PropertyNameToPropertyKeyPath("a.b.[*].c"); CPPUNIT_ASSERT_EQUAL_MESSAGE( "Testing PropertyNameToPropertyKeyPath() with 'a.b.[*].c'", deepPath_withAnySelection, result); result = mitk::PropertyNameToPropertyKeyPath("a.b.[6].c"); CPPUNIT_ASSERT_EQUAL_MESSAGE( "Testing PropertyNameToPropertyKeyPath() with 'a.b.[6].c'", deepPath_withSelection, result); result = mitk::PropertyNameToPropertyKeyPath("a.[*].*.c.d.[4].e"); CPPUNIT_ASSERT_EQUAL_MESSAGE( "Testing PropertyNameToPropertyKeyPath() with 'a.[*].*.c.d.[4].e'", verydeepPath, result); result = mitk::PropertyNameToPropertyKeyPath("AA-11"); CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing PropertyNameToPropertyKeyPath() with 'AA-11'", simplePath2, result); result = mitk::PropertyNameToPropertyKeyPath("$$$IlligalNameChar.sub"); CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing PropertyNameToPropertyKeyPath() with wrong path", emptyPath, result); result = mitk::PropertyNameToPropertyKeyPath("emptyNode..sub"); CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing PropertyNameToPropertyKeyPath() with wrong path", emptyPath, result); result = mitk::PropertyNameToPropertyKeyPath("wrongIndex.[d]"); CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing PropertyNameToPropertyKeyPath() with wrong path", emptyPath, result); } void PropertyKeyPathToPropertyName() { std::string result = mitk::PropertyKeyPathToPropertyName(simplePath); CPPUNIT_ASSERT_EQUAL_MESSAGE( "Testing PropertyKeyPathToPropertyName() with 'simple'", result, std::string("simple")); result = mitk::PropertyKeyPathToPropertyName(deepPath); CPPUNIT_ASSERT_EQUAL_MESSAGE( "Testing PropertyKeyPathToPropertyName() with 'a.b2.c3'", result, std::string("a.b2.c3")); result = mitk::PropertyKeyPathToPropertyName(deepPath_withAnyElement); CPPUNIT_ASSERT_EQUAL_MESSAGE( "Testing PropertyKeyPathToPropertyName() with 'a.*.c3'", result, std::string("a.*.c3")); result = mitk::PropertyKeyPathToPropertyName(deepPath_withAnySelection); CPPUNIT_ASSERT_EQUAL_MESSAGE( "Testing PropertyKeyPathToPropertyName() with 'a.b.[*].c'", result, std::string("a.b.[*].c")); result = mitk::PropertyKeyPathToPropertyName(deepPath_withSelection); CPPUNIT_ASSERT_EQUAL_MESSAGE( "Testing PropertyKeyPathToPropertyName() with 'a.b.[6].c'", result, std::string("a.b.[6].c")); result = mitk::PropertyKeyPathToPropertyName(verydeepPath); CPPUNIT_ASSERT_EQUAL_MESSAGE( "Testing PropertyKeyPathToPropertyName() with 'a.[*].*.c.d.[4].e'", result, std::string("a.[*].*.c.d.[4].e")); } void Comparison() { mitk::PropertyKeyPath deepPath_noSelection = mitk::PropertyKeyPath().AddElement("a").AddElement("b").AddElement("c"); CPPUNIT_ASSERT(deepPath_noSelection < deepPath); CPPUNIT_ASSERT(deepPath_noSelection < deepPath_withSelection); CPPUNIT_ASSERT(deepPath_withSelection < deepPath); CPPUNIT_ASSERT(deepPath_withSelection < deepPath_withAnySelection); CPPUNIT_ASSERT(deepPath_withAnyElement < deepPath_noSelection); CPPUNIT_ASSERT(!(deepPath_noSelection < deepPath_noSelection)); CPPUNIT_ASSERT(!(deepPath_noSelection > deepPath_noSelection)); CPPUNIT_ASSERT(deepPath_noSelection <= deepPath_noSelection); CPPUNIT_ASSERT(deepPath_noSelection >= deepPath_noSelection); } void ExecutePropertyRegEx() { std::regex regEx(mitk::PropertyKeyPathToPropertyRegEx(simplePath)); std::string result = mitk::PropertyKeyPathToPropertyName(simplePath); CPPUNIT_ASSERT(std::regex_match(result, regEx)); regEx = std::regex(mitk::PropertyKeyPathToPropertyRegEx(deepPath)); result = mitk::PropertyKeyPathToPropertyName(deepPath); CPPUNIT_ASSERT(std::regex_match(result, regEx)); regEx = std::regex(mitk::PropertyKeyPathToPropertyRegEx(deepPath_withAnyElement)); result = mitk::PropertyKeyPathToPropertyName(deepPath_withAnyElement); auto position = result.find("*"); if (std::string::npos != position) { result.replace(position, 1, "ConcreteNode1"); CPPUNIT_ASSERT(std::regex_match(result, regEx)); } regEx = std::regex(mitk::PropertyKeyPathToPropertyRegEx(deepPath_withAnySelection)); result = mitk::PropertyKeyPathToPropertyName(deepPath_withAnySelection); position = result.find("[*]"); if (std::string::npos != position) { result.replace(position, 3, "[10]"); CPPUNIT_ASSERT(std::regex_match(result, regEx)); } regEx = std::regex(mitk::PropertyKeyPathToPropertyRegEx(deepPath_withSelection)); result = mitk::PropertyKeyPathToPropertyName(deepPath_withSelection); CPPUNIT_ASSERT(std::regex_match(result, regEx)); regEx = std::regex(mitk::PropertyKeyPathToPropertyRegEx(verydeepPath)); result = mitk::PropertyKeyPathToPropertyName(verydeepPath); position = result.find("[*]"); if (std::string::npos != position) { result.replace(position, 3, "[1]"); position = result.find("*"); if (std::string::npos != position) { result.replace(position, 1, "ConcreteNode2"); CPPUNIT_ASSERT(std::regex_match(result, regEx)); } } } + + void InitializerList() + { + mitk::PropertyKeyPath newPath = {"a","b2","c3"}; + CPPUNIT_ASSERT(newPath == deepPath); + } }; MITK_TEST_SUITE_REGISTRATION(mitkPropertyKeyPath)