COOLFluiD  Release kernel
COOLFluiD is a Collaborative Simulation Environment (CSE) focused on complex MultiPhysics simulations.
utest-ui-core-cnode.cpp
Go to the documentation of this file.
1 // Copyright (C) 2010-2011 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 the ui CNode class"
9 
10 #include <QSignalSpy>
11 
12 #include <boost/assign/list_of.hpp>
13 
14 #include "rapidxml/rapidxml.hpp"
15 
17 #include "common/Log.hpp"
18 #include "common/OptionList.hpp"
19 #include "common/PropertyList.hpp"
20 #include "common/Signal.hpp"
21 
23 #include "common/XML/Protocol.hpp"
24 
25 #include "ui/core/TreeThread.hpp"
27 #include "ui/core/CNode.hpp"
28 #include "ui/core/NBrowser.hpp"
29 #include "ui/core/NGeneric.hpp"
30 #include "ui/core/NLog.hpp"
31 #include "ui/core/NLink.hpp"
32 #include "ui/core/NRoot.hpp"
33 #include "ui/core/NTree.hpp"
34 
36 
38 
39 //#include "test/ui/core/CommonFunctions.hpp"
40 #include "test/ui/MyNode.hpp"
41 //#include "test/ui/core/TreeHandler.hpp"
42 
43 using namespace boost::assign;
44 using namespace cf3;
45 using namespace cf3::common;
46 using namespace cf3::common::XML;
47 using namespace cf3::ui::core;
48 using namespace cf3::ui::CoreTest;
49 
51 {
52  static boost::shared_ptr< XmlDoc > doc = XML::parse_file(URI("./tree.xml"));
53 
54  static boost::shared_ptr< NRoot > root = boost::dynamic_pointer_cast<NRoot>(CNode::create_from_xml(doc->content->first_node("node")));
55  return Handle<NRoot>(root);
56 }
57 
60 
61 BOOST_AUTO_TEST_SUITE( uiCoreCNodeSuite )
62 
63 
66 {
67  application();
68 
69  ThreadManager::instance().tree();
70 
71  AssertionManager::instance().AssertionDumps = false;
72  AssertionManager::instance().AssertionThrows = true;
73  ExceptionManager::instance().ExceptionDumps = false;
74  ExceptionManager::instance().ExceptionOutputs = false;
75 }
76 
78 
79 BOOST_AUTO_TEST_CASE( component_type )
80 {
81  MyNode node("node");
82 
83  BOOST_CHECK_EQUAL( node.component_type().toStdString(), std::string("MyNode") );
84 }
85 
87 
88 BOOST_AUTO_TEST_CASE( is_client_component )
89 {
90  boost::shared_ptr<MyNode> node(new MyNode("Node"));
91  boost::shared_ptr<NBrowser> browser(new NBrowser());
92  boost::shared_ptr<NGeneric> group(new NGeneric("Group", "MyType"));
93  boost::shared_ptr<NLink> link(new NLink("Link"));
94  boost::shared_ptr<NLog> log(new NLog());
95  boost::shared_ptr<NGeneric> mesh(new NGeneric("Mesh", "MyType"));
96  boost::shared_ptr<NGeneric> method(new NGeneric("Method", "MyType"));
97  boost::shared_ptr<NRoot> root(new NRoot("Root"));
98  boost::shared_ptr<NTree> tree(new NTree(root->handle<NRoot>()));
99 
100  BOOST_CHECK( browser->is_local_component() );
101  BOOST_CHECK( !group->is_local_component() );
102  BOOST_CHECK( !link->is_local_component() );
103  BOOST_CHECK( log->is_local_component() );
104  BOOST_CHECK( !mesh->is_local_component() );
105  BOOST_CHECK( !method->is_local_component() );
106  BOOST_CHECK( !root->is_local_component() );
107  BOOST_CHECK( node->is_local_component() );
108  BOOST_CHECK( tree->is_local_component() );
109 }
110 
112 
113 BOOST_AUTO_TEST_CASE( set_properties )
114 {
115  MyNode node("Node");
116 
117  // an invalid tree (the type of fakePi option is unknown)
118  boost::shared_ptr< XmlDoc > wrong_opt = XML::parse_cstring(
119  "<node>"
120  " <map>"
121  " <value key=\"properties\">"
122  " <map>"
123  " <value key=\"pi\" descr=\"Pi value\" is_option=\"true\">"
124  " <real>3.141592</real>"
125  " </value>"
126  " <value key=\"fakePi\" descr=\"Pi value in an unknown type\" is_option=\"true\">"
127  " <type>3.141592</type>"
128  " </value>"
129  " </map>"
130  " </value>"
131  " </map>"
132  "</node>");
133 
134  // Legend for tree below:
135  // (1) a string property (because "is_option" attribute is not defined)
136  // (2) a bool property (because "is_option" attribute is set to false)
137  // (3) a Real option
138  boost::shared_ptr< XmlDoc > correct_opt = XML::parse_cstring(
139  "<node>"
140  " <map>"
141  " <value key=\"properties\">"
142  " <map>"
143  " <value key=\"prop\">" // (1)
144  " <string>Hello, World!</string>"
145  " </value>"
146  " <value key=\"anotherProp\" is_option=\"false\">" // (2)
147  " <bool>false</bool>"
148  " </value>"
149  " <value key=\"pi\" descr=\"Pi value\" is_option=\"true\">" // (3)
150  " <real>3.141592</real>"
151  " </value>"
152  " </map>"
153  " </value>"
154  " </map>"
155  "</node>");
156 
157  SignalArgs args_wrong(XmlNode(wrong_opt->content->first_node("node")));
158  BOOST_CHECK_THROW(MyNode("Node").set_properties(args_wrong), ValueNotFound);
159 
160  SignalArgs args_correct(XmlNode(correct_opt->content->first_node("node")));
161  BOOST_REQUIRE_NO_THROW(node.set_properties(args_correct));
162 
163  boost::any prop;
164 
165  //
166  // Checks for "prop"
167  //
168  // 1. should exist
169  BOOST_REQUIRE_NO_THROW( prop = node.properties()["prop"] );
170  // 2. should be of type "std::string"
171  BOOST_CHECK_EQUAL( any_type(prop), std::string(common::class_name<std::string>()) );
172  // 3. should have the value "Hello, World!"
173  BOOST_CHECK_EQUAL( any_to_value<std::string>(prop), std::string("Hello, World!") );
174 
175  //
176  // Checks for "anotherProp"
177  //
178  // 1. should exist
179  BOOST_REQUIRE_NO_THROW( prop = node.properties()["anotherProp"] );
180  // 2. should be of type "bool"
181  BOOST_CHECK_EQUAL( class_name_from_typeinfo(prop.type()), std::string(common::class_name<bool>()) );
182  // 3. should have the value false
183  BOOST_CHECK( !any_to_value<bool>(prop) );
184 
185  //
186  // Checks for "pi"
187  // Note: we only check that it exists and was treated as an option. The option
188  // parsing is fully tested in test_makeOption()
189  //
190  // 1. should exist
191  BOOST_REQUIRE_NO_THROW( Option & opt = node.options()["pi"] );
192 }
193 
195 
196 BOOST_AUTO_TEST_CASE( set_signals )
197 {
198  MyNode node("MyNode");
199 
200  // Legend for the tree below:
201  // my_signal1 : with readable name, description and hidden set to false
202  // my_signal2 : with readable name, description and hidden set to true
203  // my_signal3 : with readable name, description and missing hidden
204  // my_signal4 : with readable name and missing description and hidden
205  // my_signal5 : with nothing else but the mandatory key
206  boost::shared_ptr< XmlDoc > sigs = XML::parse_cstring(
207  "<node>"
208  " <map>"
209  " <value key=\"signals\">"
210  " <map key=\"my_signal1\" name=\"My signal 1\" descr=\"This is a 1st signal\" hidden=\"false\"/>"
211  " <map key=\"my_signal2\" name=\"My signal 2\" descr=\"This is a 2nd signal\" hidden=\"true\"/>"
212  " <map key=\"my_signal3\" name=\"My signal 3\" descr=\"This is a 3rd signal\"/>"
213  " <map key=\"my_signal4\" name=\"My signal 4\"/>"
214  " <map key=\"my_signal5\"/>"
215  " </value>"
216  " </map>"
217  "</node>");
218 
219  QList<ActionInfo> list;
220  node.list_signals(list);
221  int sigCount = list.size();
222 
223  SignalFrame frame(sigs->content->first_node("node"));
224  BOOST_REQUIRE_NO_THROW( node.set_signals(frame) );
225 
226  // 4 signals should have been added (my_signal1 is hidden and should have been ignored)
227  node.list_signals(list);
228  BOOST_CHECK_EQUAL( list.size(), sigCount + 4 );
229 
230  // Below, the key is empty, we should have an assertion failure
231  sigs = XML::parse_cstring(
232  "<node>"
233  " <map>"
234  " <value key=\"signals\">"
235  " <map key=\"\"/>"
236  " </value>"
237  " </map>"
238  "</node>");
239 
240  SignalFrame frame2(sigs->content->first_node("node"));
241  BOOST_CHECK_THROW( node.set_signals(frame2), FailedAssertion );
242 
243  // remote signals list should have been cleared as well
244  list.clear();
245  node.list_signals( list );
246  BOOST_CHECK_EQUAL( list.size(), sigCount );
247 
248  // Below, the key is missing, we should have an assertion failure
249  sigs = XML::parse_cstring(
250  "<node>"
251  " <map>"
252  " <value key=\"signals\">"
253  " <map/>"
254  " </value>"
255  " </map>"
256  "</node>");
257 
258  SignalFrame frame3(sigs->content->first_node("node"));
259  BOOST_CHECK_THROW( node.set_signals(frame3), FailedAssertion );
260 }
261 
263 
264 BOOST_AUTO_TEST_CASE( modify_options )
265 {
266  MyNode node("MyNode");
268 
269  // call with an empty map, nothing should change
270  BOOST_REQUIRE_NO_THROW( node.modify_options(map) );
271  BOOST_CHECK_EQUAL( node.options().value<int>("theAnswer"), int(42) );
272  BOOST_CHECK_EQUAL( node.options().value<bool>("someBool"), true );
273  BOOST_CHECK_EQUAL( node.options().value<std::string>("myString"), std::string("This is a string") );
274  BOOST_CHECK_EQUAL( node.properties().value<Real>("someProp"), Real(3.14) );
275 
276  // modify some options
277  map["someBool"] = QVariant(false).toString();
278  map["theAnswer"] = QString::number(-45782446);
279  BOOST_REQUIRE_NO_THROW( node.modify_options(map) );
280  BOOST_CHECK_EQUAL( node.options().value<int>("theAnswer"), int(-45782446) );
281  BOOST_CHECK_EQUAL( node.options().value<bool>("someBool"), false );
282  BOOST_CHECK_EQUAL( node.options().value<std::string>("myString"), std::string("This is a string") );
283  BOOST_CHECK_EQUAL( node.properties().value<Real>("someProp"), Real(3.14) );
284 
285  // try to modify a property (should fail)
286  map["someProp"] = QString::number(2.71);
287  BOOST_CHECK_THROW( node.modify_options(map), ValueNotFound );
288 
289  // option that does not exist
290  map.clear();
291  map["optionThatDoesNotExist"] = "Hello, World!";
292  BOOST_CHECK_THROW( node.modify_options(map), ValueNotFound );
293 
294  // wrong type
295  map.clear();
296  map["theAnswer"] = QString::number(2.15467654);
297  BOOST_CHECK_THROW( node.modify_options(map), CastingFailed );
298 }
299 
301 
302 BOOST_AUTO_TEST_CASE( list_properties )
303 {
304  boost::shared_ptr< MyNode > node( new MyNode("MyNode") );
305  PropertyList& list = node->properties();
306  int itemCount = list.store.size() + node->options().store.size();
308  PropertyList::PropertyStorage_t::iterator it = list.begin();
309 
310  node->list_properties( map );
311 
312  BOOST_CHECK_EQUAL( itemCount, map.size() );
313 
314  for( ; it != list.end() ; ++it )
315  BOOST_CHECK( map.contains( it->first.c_str() ) );
316 }
317 
319 
320 BOOST_AUTO_TEST_CASE( list_options )
321 {
322  MyNode node("MyNode");
324 
325  node.list_options(options);
326 
327  // MyNode has 3 options
328  BOOST_CHECK_EQUAL( options.size(), 3 );
329 }
330 
332 
333 BOOST_AUTO_TEST_CASE( create_from_xml )
334 {
335  Handle< Component > node;
338 
339  root = makeTreeFromFile();
340 
341  BOOST_REQUIRE_NO_THROW(node = root->get_child("Tools") );
342  BOOST_REQUIRE_NO_THROW(group = node->handle<NGeneric>());
343 }
344 
346 
348 {
349  boost::shared_ptr< NRoot > root(new NRoot("Root"));
350  boost::shared_ptr< NGeneric > node(new NGeneric("Node", "NGeneric"));
351  boost::shared_ptr< NLog > log( new NLog() );
352  QSignalSpy rootSpy(root->notifier(), SIGNAL(child_count_changed()));
353  QSignalSpy nodeSpy(node->notifier(), SIGNAL(child_count_changed()));
354 
355  BOOST_REQUIRE_NO_THROW( root->add_node(node));
356  // the component should have been added to the *real* root (Root)
357  BOOST_REQUIRE_NO_THROW( root->access_component("cpath:/Node")->handle<NGeneric>() );
358 
359  BOOST_CHECK_EQUAL(rootSpy.count(), 1);
360 
361  BOOST_REQUIRE_NO_THROW( node->add_node(log) );
362  BOOST_REQUIRE_NO_THROW( node->access_component("cpath:/Node/" CLIENT_LOG)->handle<NLog>() );
363 
364  BOOST_CHECK_EQUAL(nodeSpy.count(), 1);
365 }
366 
368 
369 BOOST_AUTO_TEST_CASE( remove_node )
370 {
371  boost::shared_ptr< NRoot > root(new NRoot("Root"));
372  boost::shared_ptr< NGeneric > node(new NGeneric("Node", "NGeneric"));
373  boost::shared_ptr< NLog > log( new NLog() );
374  Component * nullComp = (Component*)nullptr;
375 
376  root->add_node(node);
377  node->add_node(log);
378 
379  QSignalSpy rootSpy(root->notifier(), SIGNAL(child_count_changed()));
380  QSignalSpy nodeSpy(node->notifier(), SIGNAL(child_count_changed()));
381 
382  BOOST_REQUIRE_NO_THROW( root->remove_node("Node"));
383  // the component should have been removed from the REAL root (Root)
384  BOOST_CHECK_EQUAL( root->access_component("cpath:/Node").get(), nullComp);
385 
386  BOOST_CHECK_EQUAL(rootSpy.count(), 1);
387 
388  BOOST_REQUIRE_NO_THROW( node->remove_node( CLIENT_LOG ) );
389  BOOST_CHECK_EQUAL( root->access_component( "cpath:/Node/" CLIENT_LOG ).get(), nullComp );
390 
391  BOOST_CHECK_EQUAL( nodeSpy.count(), 1 );
392 }
393 
395 
396 BOOST_AUTO_TEST_CASE( list_child_paths )
397 {
398  /* The tree used to test:
399 
400  Root
401  |---> Log (local component)
402  | |---> Node1
403  |
404  |---> Node2
405  | |---> Node3
406  | |---> Tree (local component)
407  | |---> Node4
408  |
409  |---> Node5
410 
411  */
412 
413  QStringList list;
414  boost::shared_ptr< NRoot > root(new NRoot("Root"));
415  boost::shared_ptr< NLog > log(new NLog());
416  boost::shared_ptr< NTree > tree(new NTree(root->handle<NRoot>()));
417  boost::shared_ptr< NGeneric > node1(new NGeneric("Node1", "NGeneric"));
418  boost::shared_ptr< NGeneric > node2(new NGeneric("Node2", "NGeneric"));
419  boost::shared_ptr< NGeneric > node3(new NGeneric("Node3", "NGeneric"));
420  boost::shared_ptr< NGeneric > node4(new NGeneric("Node4", "NGeneric"));
421  boost::shared_ptr< NGeneric > node5(new NGeneric("Node5", "NGeneric"));
422 
423  root->add_node(log);
424  root->add_node(node2);
425  root->add_node(node5);
426 
427  log->add_node(node1);
428 
429  node2->add_node(node3);
430  node2->add_node(tree);
431  node2->add_node(node4);
432 
433  //
434  // 1. Get everything
435  //
436  root->list_child_paths(list, true, true);
437  // should have 8 strings
438  BOOST_CHECK_EQUAL( list.count(), 8);
439  // check the strings
440  // Nodes should be in the order they were added
441  BOOST_CHECK_EQUAL( list.at(0).toStdString(), std::string("/") );
442  BOOST_CHECK_EQUAL( list.at(1).toStdString(), std::string("/Log") );
443  BOOST_CHECK_EQUAL( list.at(2).toStdString(), std::string("/Log/Node1") );
444  BOOST_CHECK_EQUAL( list.at(3).toStdString(), std::string("/Node2") );
445  BOOST_CHECK_EQUAL( list.at(4).toStdString(), std::string("/Node2/Node3") );
446  BOOST_CHECK_EQUAL( list.at(5).toStdString(), std::string("/Node2/Tree") );
447  BOOST_CHECK_EQUAL( list.at(6).toStdString(), std::string("/Node2/Node4") );
448  BOOST_CHECK_EQUAL( list.at(7).toStdString(), std::string("/Node5") );
449 
450  list.clear();
451 
452  //
453  // 2. Skip local components
454  //
455  root->list_child_paths(list, true, false);
456  // should have 5 strings
457  BOOST_CHECK_EQUAL( list.count(), 5);
458  // check the strings
459  BOOST_CHECK_EQUAL( list.at(0).toStdString(), std::string("/") );
460  BOOST_CHECK_EQUAL( list.at(1).toStdString(), std::string("/Node2") );
461  BOOST_CHECK_EQUAL( list.at(2).toStdString(), std::string("/Node2/Node3") );
462  BOOST_CHECK_EQUAL( list.at(3).toStdString(), std::string("/Node2/Node4") );
463  BOOST_CHECK_EQUAL( list.at(4).toStdString(), std::string("/Node5") );
464 
465  list.clear();
466 
467  //
468  // 3. Not recursive
469  //
470  root->list_child_paths(list, false, true);
471  // should have 4 strings
472  BOOST_CHECK_EQUAL( list.count(), 4);
473  // check the strings
474  BOOST_CHECK_EQUAL( list.at(0).toStdString(), std::string("/") );
475  BOOST_CHECK_EQUAL( list.at(1).toStdString(), std::string("/Log") );
476  BOOST_CHECK_EQUAL( list.at(2).toStdString(), std::string("/Node2") );
477  BOOST_CHECK_EQUAL( list.at(3).toStdString(), std::string("/Node5") );
478 
479 
480  list.clear();
481 
482  //
483  // 4. Neither local components, nor recursive
484  //
485  root->list_child_paths(list, false, false);
486  // should have 3 strings
487  BOOST_CHECK_EQUAL( list.count(), 3);
488  // check the strings
489  BOOST_CHECK_EQUAL( list.at(0).toStdString(), std::string("/") );
490  BOOST_CHECK_EQUAL( list.at(1).toStdString(), std::string("/Node2") );
491  BOOST_CHECK_EQUAL( list.at(2).toStdString(), std::string("/Node5") );
492 
493  list.clear();
494 
495  //
496  // 5. From another component than the root
497  //
498  node2->list_child_paths(list, true, true);
499  // should have 4 strings
500  BOOST_CHECK_EQUAL( list.count(), 4);
501  // check the strings
502  // Nodes should be in the order they were added
503  BOOST_CHECK_EQUAL( list.at(0).toStdString(), std::string("/Node2") );
504  BOOST_CHECK_EQUAL( list.at(1).toStdString(), std::string("/Node2/Node3") );
505  BOOST_CHECK_EQUAL( list.at(2).toStdString(), std::string("/Node2/Tree") );
506  BOOST_CHECK_EQUAL( list.at(3).toStdString(), std::string("/Node2/Node4") );
507 }
508 
510 
511 BOOST_AUTO_TEST_SUITE_END()
Adds fonctionnalities to Property class.
Definition: Option.hpp:76
std::string class_name_from_typeinfo(const std::type_info &info)
Definition: TypeInfo.cpp:72
std::string any_type(const boost::any &value)
Gives the demangled type string of a boost::any value.
Log component.
Definition: NLog.hpp:34
boost::shared_ptr< XmlDoc > parse_cstring(const char *str, std::size_t length)
QApplication * application()
Definition: Application.hpp:11
Safe pointer to an object. This is the supported method for referring to components.
Definition: Handle.hpp:39
Common_TEMPLATE template bool any_to_value< bool >(const boost::any &)
Classes that implement the XML protocol for use in COOLFluiD.
Definition: Component.hpp:43
Basic Classes for client-core library used by coolfluid-client application.
Definition: CNode.cpp:57
void set_properties(const common::SignalArgs &node)
Definition: CNode.cpp:127
QString component_type() const
Definition: CNode.cpp:120
tuple root
Definition: coolfluid.py:24
Component that manages remote browsers. This class subclasses CNode class.
Definition: NBrowser.hpp:32
Manages a set of maps.
Definition: SignalFrame.hpp:31
Handle< NRoot > makeTreeFromFile()
void set_signals(const common::SignalArgs &node)
Definition: CNode.cpp:209
PropertyList & properties()
Definition: Component.cpp:842
TYPE value(const std::string &pname) const
Handle< Component > get_child(const std::string &name)
Definition: Component.cpp:441
Top-level namespace for coolfluid.
Definition: Action.cpp:18
const TYPE value(const std::string &opt_name) const
Get the value of the option with given name.
Definition: OptionList.hpp:104
void modify_options(const QMap< QString, QString > &options)
Modifies options.
Definition: CNode.cpp:281
static boost::proto::terminal< ExpressionGroupTag >::type group
Use group(expr1, expr2, ..., exprN) to evaluate a group of expressions.
Tree model.
Definition: NTree.hpp:39
void list_signals(QList< ActionInfo > &actions)
Definition: CNode.cpp:550
Client root. This class is wrapper for cf3::common::Root class on the client side. A NRoot object may never have any child. Add them to the internal Root componenent instead. It can be obtained by calling root() method.
Definition: NRoot.hpp:34
Client generic component.
Definition: NGeneric.hpp:29
Definition: CNode.hpp:22
Handle< Component > handle()
Get a handle to the component.
Definition: Component.hpp:179
#define CLIENT_LOG
OptionList & options()
Definition: Component.cpp:856
BOOST_AUTO_TEST_CASE(init)
Base class for defining CF components.
Definition: Component.hpp:82
void map(Field &field, Eigen::Map< Derived > &v, const Uint row_idx, const Uint var_idx)
void list_options(QList< boost::shared_ptr< common::Option > > &list)
Definition: CNode.cpp:507
Most basic kernel library.
Definition: Action.cpp:19
Definition: CNode.hpp:23
PropertyStorage_t store
storage of options
boost::shared_ptr< XmlDoc > parse_file(const URI &file)
Send comments to:
COOLFluiD Web Admin