From e60d7a709a0bd109f902acde5a881ef2716f0e7b Mon Sep 17 00:00:00 2001 From: Martin Killenberg <martin.killenberg@desy.de> Date: Fri, 11 Aug 2017 14:23:08 +0200 Subject: [PATCH] added test and implementation for getting properties by location from the mapper --- include/VariableMapper.h | 4 +- src/VariableMapper.cc | 130 +++++-------------------------- tests/src/testVariableMapper.cpp | 14 ++++ 3 files changed, 38 insertions(+), 110 deletions(-) diff --git a/include/VariableMapper.h b/include/VariableMapper.h index bb08e65..8cee9a7 100644 --- a/include/VariableMapper.h +++ b/include/VariableMapper.h @@ -71,13 +71,15 @@ namespace ChimeraTK{ void processLocation(xmlpp::Node const * locationNode); void processProperty(xmlpp::Node const * propertyNode, std::string locationName); void processImport(xmlpp::Node const * importNode, std::string importLocationName=std::string()); - // void processGlobalImport(xmlpp::Node const * importNode); std::map<std::string, PropertyAttributes> _locationDefaults; PropertyAttributes _globalDefaults; // PropertyDescriptions, sorted by input, i.e. the ChimeraTK PV name std::map<std::string, PropertyDescription> _inputSortedDescriptions; + + /// An internal helper function to abbreviate the syntax + bool nodeIsWhitespace(const xmlpp::Node* node); }; } // namespace ChimeraTK diff --git a/src/VariableMapper.cc b/src/VariableMapper.cc index 256633c..15de501 100644 --- a/src/VariableMapper.cc +++ b/src/VariableMapper.cc @@ -1,117 +1,28 @@ #include "VariableMapper.h" #include <libxml++/libxml++.h> -#include <iostream> #include <regex> #include "splitStringAtFirstSlash.h" namespace ChimeraTK{ -//LCOV_EXCL_START -void print_indentation(unsigned int indentation) -{ - for(unsigned int i = 0; i < indentation; ++i) - std::cout << " "; -} + + VariableMapper & VariableMapper::getInstance(){ + static VariableMapper instance; + return instance; + } - bool nodeIsWhitespace(const xmlpp::Node* node){ + bool VariableMapper::nodeIsWhitespace(const xmlpp::Node* node){ const xmlpp::TextNode* nodeAsText = dynamic_cast<const xmlpp::TextNode*>(node); if(nodeAsText){ return nodeAsText->is_white_space(); } return false; } - -void print_node(const xmlpp::Node* node, unsigned int indentation = 0) -{ - std::cout << std::endl; //Separate nodes by an empty line. - - const xmlpp::ContentNode* nodeContent = dynamic_cast<const xmlpp::ContentNode*>(node); - const xmlpp::TextNode* nodeText = dynamic_cast<const xmlpp::TextNode*>(node); - const xmlpp::CommentNode* nodeComment = dynamic_cast<const xmlpp::CommentNode*>(node); - - if(nodeText && nodeText->is_white_space()){ //Let's ignore the indenting - you don't always want to do this. - std::cout << "--ignoring whitespace" << std::endl; - return; - } - - Glib::ustring nodename = node->get_name(); - - if(!nodeText && !nodeComment && !nodename.empty()) //Let's not say "name: text". - { - print_indentation(indentation); - std::cout << "Node name = " << node->get_name() << std::endl; - std::cout << "Node name = " << nodename << std::endl; - } - else if(nodeText) //Let's say when it's text. - e.g. let's say what that white space is. - { - print_indentation(indentation); - std::cout << "Text Node" << std::endl; - } - - //Treat the various node types differently: - if(nodeText) - { - print_indentation(indentation); - std::cout << "text = \"" << nodeText->get_content() << "\"" << std::endl; - } - else if(nodeComment) - { - print_indentation(indentation); - std::cout << "comment = " << nodeComment->get_content() << std::endl; - } - else if(nodeContent) - { - print_indentation(indentation); - std::cout << "content = " << nodeContent->get_content() << std::endl; - } - else if(const xmlpp::Element* nodeElement = dynamic_cast<const xmlpp::Element*>(node)) - { - //A normal Element node: - - //line() works only for ElementNodes. - print_indentation(indentation); - std::cout << " line = " << node->get_line() << std::endl; - - //Print attributes: - const xmlpp::Element::AttributeList& attributes = nodeElement->get_attributes(); - for(xmlpp::Element::AttributeList::const_iterator iter = attributes.begin(); iter != attributes.end(); ++iter) - { - const xmlpp::Attribute* attribute = *iter; - print_indentation(indentation); - std::cout << " Attribute " << attribute->get_name() << " = " << attribute->get_value() << std::endl; - } - - const xmlpp::Attribute* attribute = nodeElement->get_attribute("title"); - if(attribute) - { - std::cout << "title found: =" << attribute->get_value() << std::endl; - - } - } - - if(!nodeContent) - { - //Recurse through child nodes: - xmlpp::Node::NodeList list = node->get_children(); - for(xmlpp::Node::NodeList::iterator iter = list.begin(); iter != list.end(); ++iter) - { - print_node(*iter, indentation + 2); //recursive - } - } -} -//LCOV_EXCL_STOP - - VariableMapper & VariableMapper::getInstance(){ - static VariableMapper instance; - return instance; - } void VariableMapper::processLocation(xmlpp::Node const * locationNode){ const xmlpp::Element* location = dynamic_cast<const xmlpp::Element*>(locationNode); std::string locationName = location->get_attribute("name")->get_value(); - std::cout << "Found location: " << locationName << std::endl; - for (auto const & node : location->get_children()){ if (nodeIsWhitespace(node)) continue; @@ -150,8 +61,7 @@ void print_node(const xmlpp::Node* node, unsigned int indentation = 0) }else{ absoluteSource=std::string("/")+locationName+"/"+source; } - std::cout << "going to create property: " << locationName << "/" << name - << " from " << absoluteSource << std::endl; + auto existingCandidate = _inputSortedDescriptions.find(absoluteSource); if (existingCandidate != _inputSortedDescriptions.end()){ auto existingPropertyDescription = existingCandidate->second; @@ -166,7 +76,6 @@ void print_node(const xmlpp::Node* node, unsigned int indentation = 0) for (auto const & node : importNode->get_children()){ const xmlpp::TextNode* nodeAsText = dynamic_cast<const xmlpp::TextNode*>(node); std::string importSource = nodeAsText->get_content(); - std::cout << "Importing in location '"<<importLocationName <<"': " << importSource << std::endl; // a slash will be added after the source, so we make the source empty for an import of everything if (importSource == "/"){ @@ -176,23 +85,18 @@ void print_node(const xmlpp::Node* node, unsigned int indentation = 0) // loop source tree, cut beginning, replace / with _ and add a property for (auto const & processVariable : _inputVariables){ if (_inputSortedDescriptions.find(processVariable) != _inputSortedDescriptions.end()){ - std::cout << processVariable << " alread in the map. Not importing" << std::endl; continue; } if ( processVariable.find( importSource+"/") == 0 ){ // processVariable starts with wanted source - std::cout << "importing " << processVariable << " from " << importSource << " into " - << importLocationName << std::endl; auto nameSource = processVariable.substr( importSource.size() + 1); // add the slash to be removed - std::cout << "nameSource " << nameSource << std::endl; std::string propertyName; std::string locationName; if (importLocationName.empty()){ // a global import, try to get the location name from the source auto locationAndPropertyName = splitStringAtFirstSlash(nameSource); locationName = locationAndPropertyName.first; - std::cout << "new location name is " << locationName << std::endl; propertyName = locationAndPropertyName.second; if (locationName.empty() ){ throw std::logic_error(std::string("Invalid XML content in global import of ") + importSource + ": Cannot create location name from '" + nameSource + "', one hirarchy level is missing."); @@ -203,7 +107,6 @@ void print_node(const xmlpp::Node* node, unsigned int indentation = 0) locationName = importLocationName; } - std::cout << "new property name is " << propertyName << std::endl; _inputSortedDescriptions[processVariable] = PropertyDescription(locationName, propertyName); } } @@ -225,11 +128,6 @@ void print_node(const xmlpp::Node* node, unsigned int indentation = 0) //Walk the tree: const xmlpp::Node* rootNode = parser.get_document()->get_root_node(); //deleted by DomParser. - - // std::cout << "****************************\nPredefined printout in "<< xmlFile<<":\n" << std::endl; - // print_node(rootNode); - - std::cout << "\n My interpretation for "<< xmlFile << "\n===================================" << std::endl; for (auto const & mainNode : rootNode->get_children()){ if (nodeIsWhitespace(mainNode)) continue; @@ -252,5 +150,19 @@ void print_node(const xmlpp::Node* node, unsigned int indentation = 0) return _inputSortedDescriptions; } + std::map< std::string, VariableMapper::PropertyDescription > VariableMapper::getPropertiesInLocation(std::string location) const{ + std::map< std::string, PropertyDescription > output; + + for (auto const & variable : _inputSortedDescriptions){ + if (variable.second.location == location){ + // no need to check return value. There cannot be duplicate entries because the values are + // coming from another map. + (void) output.insert( variable ); + } + } + return output; + } + + } // namespace ChimeraTK diff --git a/tests/src/testVariableMapper.cpp b/tests/src/testVariableMapper.cpp index 68d2fac..cedeecf 100644 --- a/tests/src/testVariableMapper.cpp +++ b/tests/src/testVariableMapper.cpp @@ -115,6 +115,20 @@ BOOST_AUTO_TEST_CASE( testImportAll ){ testXmlParsing("variableTreeXml/globalImportAndRename.xml", propertyMap); } +BOOST_AUTO_TEST_CASE( testGetPropertiesInLocation ){ + // same input as for testAll, so we know the overall output is OK due to the separate test. + VariableMapper & vm = VariableMapper::getInstance(); + vm.prepareOutput("variableTreeXml/importAll.xml", generateInputVariables()); + BOOST_CHECK( mapCompare( vm.getPropertiesInLocation("A"), { {"/A/a/di", {"A","a.di"}}, + {"/A/a/do", {"A","a.do"}}, + {"/A/b", {"A","b"}} + } ) ); + BOOST_CHECK( mapCompare( vm.getPropertiesInLocation("B"), { {"/B/a/dr", {"B","a.dr"}}, + {"/B/c/de", {"B","c.de"}}, + {"/B/c/gne", {"B","c.gne"}} + } ) ); +} + BOOST_AUTO_TEST_CASE( testImportIntoLocation ){ std::map< std::string, VariableMapper::PropertyDescription > propertyMap( { {"/A/a/di", {"MASTER","A.a.di"}}, -- GitLab