COOLFluiD  Release kernel
COOLFluiD is a Collaborative Simulation Environment (CSE) focused on complex MultiPhysics simulations.
utest-xml-map.cpp
Go to the documentation of this file.
1 // Copyright (C) 2010-2013 von Karman Institute for Fluid Dynamics, Belgium
2 //
3 // This software is distributed under the terms of the
4 // GNU Lesser General Public License version 3 (LGPLv3).
5 // See doc/lgpl.txt and doc/gpl.txt for the license text.
6 
7 #define BOOST_TEST_DYN_LINK
8 #define BOOST_TEST_MODULE "Test module for XML maps manipulation"
9 
10 #include <boost/assign/list_of.hpp>
11 
12 #include <boost/test/unit_test.hpp>
13 
14 #include "rapidxml/rapidxml.hpp"
15 
16 #include "common/CF.hpp"
19 
20 #include "common/XML/Protocol.hpp"
21 
22 #include "common/XML/Map.hpp"
23 #include <common/TypeInfo.hpp>
24 #include <common/Option.hpp>
25 #include <common/Core.hpp>
26 #include <common/Environment.hpp>
27 #include <common/OptionList.hpp>
28 
29 using namespace cf3;
30 using namespace cf3::common;
31 using namespace cf3::common::XML;
32 using namespace boost::assign; // for list_of
33 
35 
36 struct XmlFixture
37 {
39  {
40  Core::instance().environment().options().set("exception_backtrace", false);
41  Core::instance().environment().options().set("exception_outputs", false);
42  }
43 };
44 
45 BOOST_FIXTURE_TEST_SUITE( XmlMap_TestSuite, XmlFixture )
46 
47 
49 BOOST_AUTO_TEST_CASE ( set_value )
50 {
52  Map map(node);
53  XmlNode value_node;
54  XmlNode mod_value_node;
55  XmlNode type_node;
56 
57  rapidxml::xml_attribute<>* key_attr = nullptr;
58 
59  //
60  // 1. the key is empty
61  BOOST_CHECK_THROW ( map.set_value( "", common::class_name<bool>(), "true" ), BadValue );
62 
63  //
64  // 2. the value does not exist, setting it should create it and the
65  // correct node should be returned
66  //
67 
68  value_node = map.set_value( "TheUltimateAnswer", common::class_name<int>(), "12" );
69  BOOST_CHECK ( value_node.is_valid() );
70 
71  // 2a. it should be a "value" node
72  BOOST_CHECK_EQUAL ( std::strcmp(value_node.content->name(), Protocol::Tags::node_value()), 0 );
73 
74  // 2b. it should have the right key value
75  key_attr = value_node.content->first_attribute( Protocol::Tags::attr_key() );
76  BOOST_CHECK ( is_not_null(key_attr) );
77  BOOST_CHECK_EQUAL ( std::strcmp(key_attr->value(), "TheUltimateAnswer"), 0 );
78 
79  // 2c. it should have the right value with the right type
80  type_node = XmlNode( value_node.content->first_node( common::class_name<int>().c_str() ) );
81  BOOST_CHECK ( type_node.is_valid() );
82  BOOST_CHECK_EQUAL ( std::strcmp(type_node.content->value(), "12"), 0 );
83 
84  //
85  // 3. test the type checking
86  //
87 
88  // 3a. try to change the value but with a wrong type
89  BOOST_CHECK_THROW ( map.set_value("TheUltimateAnswer", common::class_name<std::string>(), std::string()), XmlError );
90 
91  // 3b. the value in the xml tree has no type
93  BOOST_CHECK_THROW ( map.set_value("hello", common::class_name<std::string>(),std::string()), XmlError );
94 
95  // 3c. the value in the xml tree is an array
97  BOOST_CHECK_THROW ( map.set_value("world", common::class_name<std::string>(), std::string()), XmlError );
98 
99  //
100  // 4. change the value
101  //
102 
103  mod_value_node = map.set_value( "TheUltimateAnswer", common::class_name<int>(), "42" );
104  BOOST_CHECK ( mod_value_node.is_valid() );
105 
106  // 4a. it should be the same node as the one before (same object/pointer)
107  BOOST_CHECK_EQUAL ( mod_value_node.content, value_node.content );
108 
109  // 4b. it should the right value with the right type
110  type_node = XmlNode( mod_value_node.content->first_node( common::class_name<int>().c_str() ) );
111  BOOST_CHECK ( type_node.is_valid() );
112  BOOST_CHECK_EQUAL ( std::strcmp(type_node.content->value(), "42"), 0 );
113 
114  // clear the memory pool
115  delete node.content->document();
116 }
117 
119 
120 BOOST_AUTO_TEST_CASE ( set_array )
121 {
122  XmlNode node(new rapidxml::xml_document<>());
123  Map map(node);
124  XmlNode value_node;
125  XmlNode mod_value_node;
126 
127  std::vector<int> vect_first = list_of<int>(12)(5)(546)(2135)(12164)(3464)(1);
128  std::vector<int> vect_second = list_of<int>(7987)(346)(101);
129  cf3::Uint size_first = vect_first.size();
130  cf3::Uint size_second = vect_second.size();
131 
132  // the values as they should be written in the array
133  std::string str_first("12 ; 5 ; 546 ; 2135 ; 12164 ; 3464 ; 1"); // delimiter is " ; "
134  std::string str_second("7987_|_346_|_101"); // delimiter is "_|_"
135 
136  rapidxml::xml_attribute<>* tmp_attr = nullptr;
137 
138 
139  //
140  // 1. test the argument validity checking
141  //
142 
143  // 1b. the key is empty
144  BOOST_CHECK_THROW ( map.set_array( "", common::class_name<int>(), common::option_vector_to_str(vect_first, " ; "), " ; "), BadValue );
145 
146  // 1c. the delimiter is empty
147  BOOST_CHECK_THROW ( map.set_array( "Array", common::class_name<int>(), common::option_vector_to_str(vect_first, ""), ""), BadValue );
148 
149  //
150  // 2. the value does not exist, setting it should create it and the
151  // correct node should be returned
152  //
153 
154  value_node = map.set_array( "TheArray", common::class_name<int>(), option_vector_to_str(vect_first, " ; "), " ; " );
155  BOOST_CHECK ( value_node.is_valid() );
156 
157  // 2a. it should be a "array" node
158  BOOST_CHECK_EQUAL ( std::strcmp(value_node.content->name(), Protocol::Tags::node_array()), 0 );
159 
160  // 2b. it should have the right key value
161  tmp_attr = value_node.content->first_attribute( Protocol::Tags::attr_key() );
162  BOOST_CHECK ( is_not_null(tmp_attr) );
163  BOOST_CHECK_EQUAL ( std::string(tmp_attr->value()), std::string("TheArray") );
164 
165  // 2c. it should have the right type
166  tmp_attr = value_node.content->first_attribute( Protocol::Tags::attr_array_type() );
167  BOOST_CHECK ( is_not_null(tmp_attr) );
168  BOOST_CHECK_EQUAL ( std::string(tmp_attr->value()), std::string(common::class_name<int>() ));
169 
170  // 2d. it should have the right size
171  tmp_attr = value_node.content->first_attribute( Protocol::Tags::attr_array_size() );
172  BOOST_CHECK ( is_not_null(tmp_attr) );
173  BOOST_CHECK_EQUAL ( std::string(tmp_attr->value()), std::string( to_str(size_first) ));
174 
175  // 2e. it should have the right delimiter
176  tmp_attr = value_node.content->first_attribute( Protocol::Tags::attr_array_delimiter() );
177  BOOST_CHECK ( is_not_null(tmp_attr) );
178  BOOST_CHECK_EQUAL ( std::string(tmp_attr->value()), std::string(" ; ") );
179 
180  // 2f. it should have the right value
181  BOOST_CHECK ( is_not_null(value_node.content->value()) );
182  BOOST_CHECK_EQUAL ( std::string(value_node.content->value()), str_first );
183 
184  //
185  // 3. test the type checking
186  //
187 
188  // 3a. try to change the array but with a wrong type
189  std::vector<std::string> vect_wrong;
190  BOOST_CHECK_THROW ( map.set_array( "TheArray", common::class_name<std::string>(), common::option_vector_to_str(vect_wrong, " ; "), " ; " ), XmlError );
191 
192  // 3b. the array in the xml tree has no type
194  BOOST_CHECK_THROW ( map.set_array( "hello", common::class_name<std::string>(), common::option_vector_to_str(vect_wrong, " ; "), " ; " ), XmlError );
195 
196  // 3c. the arry in the xml tree is a single value
198  BOOST_CHECK_THROW ( map.set_array( "world", common::class_name<std::string>(), common::option_vector_to_str(vect_wrong, " ; "), " ; " ), XmlError );
199 
200  //
201  // 4. change the value
202  //
203 
204  mod_value_node = map.set_array( "TheArray", common::class_name<int>(), common::option_vector_to_str(vect_second, "_|_"), "_|_" );
205  BOOST_CHECK ( mod_value_node.is_valid() );
206 
207  // 4a. it should be the same node as the one before (same object/pointer)
208  BOOST_CHECK_EQUAL ( mod_value_node.content, value_node.content );
209 
210  // 4b. the size should have been updated
211  tmp_attr = mod_value_node.content->first_attribute( Protocol::Tags::attr_array_size() );
212  BOOST_CHECK ( is_not_null(tmp_attr) );
213  BOOST_CHECK_EQUAL ( std::string(tmp_attr->value()), std::string( to_str(size_second) ));
214 
215  // 4c. the delimiter should have been updated
216  tmp_attr = mod_value_node.content->first_attribute( Protocol::Tags::attr_array_delimiter() );
217  BOOST_CHECK ( is_not_null(tmp_attr) );
218  BOOST_CHECK_EQUAL ( std::string(tmp_attr->value()), std::string("_|_") );
219 
220  // 4d. the value should have been updated
221  BOOST_CHECK ( is_not_null(mod_value_node.content->value()) );
222  BOOST_CHECK_EQUAL ( std::string(mod_value_node.content->value()), str_second );
223 
224  // clear the memory pool
225  delete node.content->document();
226 }
227 
229 
230 BOOST_AUTO_TEST_CASE ( find_value )
231 {
232  XmlNode node(new rapidxml::xml_document<>());
233  Map map(node);
234  XmlNode first_node( node.add_node(Protocol::Tags::node_map()) );
235  XmlNode second_node( node.add_node(Protocol::Tags::node_value()) );
236  XmlNode found_node;
237  rapidxml::xml_attribute<>* key_attr = nullptr;
238 
239  first_node.set_attribute( Protocol::Tags::attr_key(), "FirstNode" );
240  second_node.set_attribute( Protocol::Tags::attr_key(), "SecondNode" );
241 
242  //
243  // 1. seeking a node with empty key should return FirstNode (the first node found)
244  //
245 
246  found_node = map.find_value();
247 
248  BOOST_CHECK ( found_node.is_valid() );
249  BOOST_CHECK_EQUAL ( found_node.content, first_node.content );
250 
251  //
252  // 2. seeking a node with non-empty key should return the correct node
253  //
254 
255  found_node = map.find_value( "SecondNode" );
256 
257  BOOST_CHECK ( found_node.is_valid() );
258  BOOST_CHECK_EQUAL ( found_node.content, second_node.content );
259 
260  //
261  // 3. if the node is not found, an invalid node should be returned
262  //
263 
264  found_node = map.find_value( "MapThatDoesNotExist" );
265 
266  BOOST_CHECK ( !found_node.is_valid() );
267 
268  // clear the memory pool
269  delete node.content->document();
270 }
271 
273 
274 BOOST_AUTO_TEST_CASE ( is_single_value )
275 {
276  XmlNode node;
277  XmlNode added_node;
278 
279  // 1. the node is not valid, should return false
280  BOOST_CHECK ( !Map::is_single_value(node) );
281 
282  node.content = new rapidxml::xml_document<>();
283 
284  // 2. the node is an array value, should return false
285  added_node = node.add_node( Protocol::Tags::node_array() );
286  BOOST_CHECK ( !Map::is_single_value(added_node) );
287 
288  // 3. the node is a single value, should return true
289  added_node = node.add_node( Protocol::Tags::node_value() );
290  BOOST_CHECK ( Map::is_single_value(added_node) );
291 
292  // clear the memory pool
293  delete node.content->document();
294 }
295 
297 
298 BOOST_AUTO_TEST_CASE ( is_array_value )
299 {
300  XmlNode node;
301  XmlNode added_node;
302 
303  // 1. the node is not valid, should return false
304  BOOST_CHECK ( !Map::is_array_value(node) );
305 
306  node.content = new rapidxml::xml_document<>();
307 
308  // 2. the node is a single value, should return false
309  added_node = node.add_node( Protocol::Tags::node_value() );
310  BOOST_CHECK ( !Map::is_array_value(added_node) );
311 
312  // 3. the node is an array value, should return true
313  added_node = node.add_node( Protocol::Tags::node_array() );
314  BOOST_CHECK ( Map::is_array_value(added_node) );
315 
316  // clear the memory pool
317  delete node.content->document();
318 }
319 
321 
322 BOOST_AUTO_TEST_CASE ( get_value_type )
323 {
324  XmlNode node(new rapidxml::xml_document<>());
325  Map map(node);
326  std::vector<int> vect;
327 
328  XmlNode value( map.set_value("MyString", class_name<std::string>(), std::string("TheString")) );
329  XmlNode array( map.set_array("MyVector", class_name<int>(), "", " ; ") );
330 
331  XmlNode wrong_value( node.add_node(Protocol::Tags::node_value()) );
332  XmlNode wrong_array( node.add_node(Protocol::Tags::node_array()) );
333  XmlNode wrong_node( node.add_node(Protocol::Tags::node_map()) );
334 
335  wrong_value.set_attribute( Protocol::Tags::attr_key(), "AValue" );
336  wrong_array.set_attribute( Protocol::Tags::attr_key(), "AnArray" );
337  wrong_node.set_attribute( Protocol::Tags::attr_key(), "AMap");
338 
339  // the node is correct and the right type should be returned
340  BOOST_CHECK_EQUAL ( std::strcmp( Map::get_value_type(value), common::class_name<std::string>().c_str() ), 0);
341  BOOST_CHECK_EQUAL ( std::strcmp( Map::get_value_type(array), common::class_name<int>().c_str() ), 0);
342 
343  // the type is wrong, an exception should be thrown
344  BOOST_CHECK_THROW ( Map::get_value_type(wrong_value), XmlError);
345  BOOST_CHECK_THROW ( Map::get_value_type(wrong_array), XmlError);
346  BOOST_CHECK_THROW ( Map::get_value_type(wrong_node), XmlError);
347 
348  // clear the memory pool
349  delete node.content->document();
350 }
351 
353 
354 BOOST_AUTO_TEST_CASE ( get_value )
355 {
356  XmlNode node(new rapidxml::xml_document<>());
357  Map map(node);
358  XmlNode added_node;
359  std::vector<int> int_vals = list_of<int>(1213)(5464)(5554)(5654)(273)(554)(354);
360  std::string str("Hello, World!");
361 
362  map.set_value( "AString", class_name<std::string>(), str );
363  map.set_value( "Zero", class_name<int>(), "0" );
364  map.set_array( "SomeInts", class_name<int>(), option_vector_to_str(int_vals, " ; "), " ; " );
365 
366  // 1. try to get with a wrong type
367  BOOST_CHECK_THROW ( map.get_value<int>( "AString"), XmlError );
368 
369  // 2. try to get an array (type is not important here)
370  BOOST_CHECK_THROW ( map.get_value<int>( "SomeInts"), XmlError );
371 
372  // 3. get the value with the correct type
373  BOOST_CHECK_EQUAL ( map.get_value<std::string>( "AString"), str );
374 
375  // clear the memory pool
376  delete node.content->document();
377 }
378 
380 
381 BOOST_AUTO_TEST_CASE ( get_array )
382 {
383  XmlNode node(new rapidxml::xml_document<>());
384  Map map(node);
385  XmlNode added_node;
386  std::vector<int> int_vals = list_of<int>(1213)(5464)(5554)(5654)(273)(554)(354);
387  std::vector<int> int_read;
388  std::vector<int>::iterator it_vals = int_vals.begin();
389  std::vector<int>::iterator it_read;
390  std::string str("Hello, World!");
391 
392  map.set_value( "AString", class_name<std::string>(), str );
393  map.set_value( "Zero", class_name<int>(), "0" );
394  map.set_array( "SomeInts", class_name<int>(), option_vector_to_str(int_vals, " ; "), " ; " );
395 
396  // 1. try to get with a wrong type
397  BOOST_CHECK_THROW ( map.get_array<Real>( "SomeInts"), XmlError );
398 
399  // 2. try to get a signal value (type is not important here)
400  BOOST_CHECK_THROW ( map.get_array<int>( "Zero"), XmlError );
401 
402  // 3. get the value with the correct type
403  BOOST_CHECK_NO_THROW ( int_read = map.get_array<int>( "SomeInts") );
404 
405  BOOST_CHECK_EQUAL ( int_read.size(), int_vals.size() );
406 
407  // check that items match
408  for( it_read = int_read.begin() ; it_read != int_read.end() ; ++it_read, ++it_vals )
409  BOOST_CHECK_EQUAL ( *it_read, *it_vals);
410 
411  // clear the memory pool
412  delete node.content->document();
413 }
414 
416 
417 BOOST_AUTO_TEST_CASE ( split_string )
418 {
419  XmlNode node(new rapidxml::xml_document<>());
420  Map map(node);
421  XmlNode added_node;
422  std::vector<std::string> str_vals = list_of<std::string>("hello")("hello with some white spaces");
423  std::vector<std::string> str_read;
424  std::vector<std::string>::iterator it_vals = str_vals.begin();
425  std::vector<std::string>::iterator it_read;
426 
427  map.set_array( "SomeStrings", class_name<std::string>(), option_vector_to_str(str_vals, " ; "), " ; " );
428 
429  // get the value
430  BOOST_CHECK_NO_THROW ( str_read = map.get_array<std::string>( "SomeStrings") );
431 
432  // check that sizes match
433  BOOST_CHECK_EQUAL ( str_read.size(), str_vals.size() );
434 
435  // check that items match
436  for( it_read = str_read.begin() ; it_read != str_read.end() ; ++it_read, ++it_vals )
437  BOOST_CHECK_EQUAL ( *it_read, *it_vals);
438 
439  // clear the memory pool
440  delete node.content->document();
441 }
442 
444 
445 BOOST_AUTO_TEST_SUITE_END()
446 
447 
XmlNode add_node(const std::string &name, const std::string &value=std::string()) const
Definition: XmlNode.cpp:38
static const char * get_value_type(const XmlNode &node)
Definition: Map.cpp:281
Classes that implement the XML protocol for use in COOLFluiD.
Definition: Component.hpp:43
bool is_valid() const
Definition: XmlNode.cpp:102
BOOST_AUTO_TEST_CASE(set_value)
rapidxml::xml_node< char > * content
Pointer to the underlying XML implementation.
Definition: XmlNode.hpp:50
Conversions from and to std::string.
Common_API std::string to_str(const T &v)
Converts to std::string.
static const char * attr_array_type()
Definition: Protocol.cpp:34
static const char * node_value()
Definition: Protocol.cpp:64
void set_attribute(const std::string &name, const std::string &value)
Definition: XmlNode.cpp:54
static const char * attr_array_delimiter()
Definition: Protocol.cpp:30
static const char * attr_array_size()
Definition: Protocol.cpp:32
Top-level namespace for coolfluid.
Definition: Action.cpp:18
static const char * attr_key()
Definition: Protocol.cpp:42
std::string option_vector_to_str(const std::vector< T > &vec, const std::string &delim)
Helper function to convert a vector to string, skipping empty entries.
Definition: Option.hpp:284
static bool is_array_value(const XmlNode &node)
Definition: Map.cpp:274
static bool is_single_value(const XmlNode &node)
Definition: Map.cpp:267
common::Environment & environment() const
Definition: Core.cpp:168
unsigned int Uint
typedef for unsigned int
Definition: CF.hpp:90
coolfluid3 header, included almost everywhere
static Core & instance()
Definition: Core.cpp:37
static const char * node_array()
Definition: Protocol.cpp:56
OptionList & options()
Definition: Component.cpp:856
void set(const std::string &pname, const boost::any &val)
Definition: OptionList.cpp:132
static const char * node_map()
Definition: Protocol.cpp:62
void map(Field &field, Eigen::Map< Derived > &v, const Uint row_idx, const Uint var_idx)
Most basic kernel library.
Definition: Action.cpp:19
bool is_not_null(T ptr)
predicate for comparison to nullptr
Definition: CF.hpp:147
Send comments to:
COOLFluiD Web Admin