Skip to content
Snippets Groups Projects
Commit e60d7a70 authored by Martin Killenberg's avatar Martin Killenberg
Browse files

added test and implementation for getting properties by location from the mapper

parent 1e9118fe
No related branches found
No related tags found
No related merge requests found
......@@ -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
......
#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
......@@ -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"}},
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment