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