gtest_factory.cpp
Go to the documentation of this file.
1 #include <gtest/gtest.h>
2 #include "action_test_node.h"
3 #include "condition_test_node.h"
5 #include "../sample_nodes/crossdoor_nodes.h"
6 #include "../sample_nodes/dummy_nodes.h"
7 
8 using namespace BT;
9 
10 // clang-format off
11 
12 static const char* xml_text = R"(
13 
14 <root main_tree_to_execute = "MainTree" >
15 
16  <BehaviorTree ID="MainTree">
17  <Fallback name="root_selector">
18 
19  <Sequence name="door_open_sequence">
20  <Action ID="IsDoorOpen" />
21  <Action ID="PassThroughDoor" />
22  </Sequence>
23 
24  <Sequence name="door_closed_sequence">
25  <Decorator ID="Inverter">
26  <Action ID="IsDoorOpen" />
27  </Decorator>
28  <Action ID="OpenDoor" />
29  <Action ID="PassThroughDoor" />
30  <Action ID="CloseDoor" />
31  </Sequence>
32 
33  <Action ID="PassThroughWindow" />
34 
35  </Fallback>
36  </BehaviorTree>
37 
38  <!-- TreeNodesModel is used only by the Graphic interface -->
39  <TreeNodesModel>
40  <Action ID="IsDoorOpen" />
41  <Action ID="PassThroughDoor" />
42  <Action ID="CloseDoor" />
43  <Action ID="OpenDoor" />
44  <Action ID="PassThroughWindow" />
45  </TreeNodesModel>
46 </root>
47  )";
48 
49 static const char* xml_text_subtree = R"(
50 
51 <root main_tree_to_execute = "MainTree" >
52 
53  <BehaviorTree ID="CrossDoorSubtree">
54  <Sequence name="door_sequence">
55  <Decorator ID="Inverter">
56  <Action ID="IsDoorLocked" />
57  </Decorator>
58  <Action ID="OpenDoor" />
59  <Action ID="PassThroughDoor" />
60  <Action ID="CloseDoor" />
61  </Sequence>
62  </BehaviorTree>
63 
64  <!-- This tree will include the other one -->
65  <BehaviorTree ID="MainTree">
66  <Fallback name="root_selector">
67  <SubTree ID="CrossDoorSubtree" />
68  <Action ID="PassThroughWindow" />
69  </Fallback>
70  </BehaviorTree>
71 
72 </root> )";
73 
74 // clang-format on
75 
76 TEST(BehaviorTreeFactory, VerifyLargeTree)
77 {
78  BehaviorTreeFactory factory;
79  CrossDoor::RegisterNodes(factory);
80 
81  Tree tree = factory.createTreeFromText(xml_text);
82 
84 
85  ASSERT_EQ(tree.rootNode()->name(), "root_selector");
86 
87  auto fallback = dynamic_cast<const FallbackNode*>(tree.rootNode());
88  ASSERT_TRUE(fallback != nullptr);
89 
90  ASSERT_EQ(fallback->children().size(), 3);
91  ASSERT_EQ(fallback->child(0)->name(), "door_open_sequence");
92  ASSERT_EQ(fallback->child(1)->name(), "door_closed_sequence");
93  ASSERT_EQ(fallback->child(2)->name(), "PassThroughWindow");
94 
95  auto sequence_open = dynamic_cast<const SequenceNode*>(fallback->child(0));
96  ASSERT_TRUE(sequence_open != nullptr);
97 
98  ASSERT_EQ(sequence_open->children().size(), 2);
99  ASSERT_EQ(sequence_open->child(0)->name(), "IsDoorOpen");
100  ASSERT_EQ(sequence_open->child(1)->name(), "PassThroughDoor");
101 
102  auto sequence_closed = dynamic_cast<const SequenceNode*>(fallback->child(1));
103  ASSERT_TRUE(sequence_closed != nullptr);
104 
105  ASSERT_EQ(sequence_closed->children().size(), 4);
106  ASSERT_EQ(sequence_closed->child(0)->name(), "Inverter");
107  ASSERT_EQ(sequence_closed->child(1)->name(), "OpenDoor");
108  ASSERT_EQ(sequence_closed->child(2)->name(), "PassThroughDoor");
109  ASSERT_EQ(sequence_closed->child(3)->name(), "CloseDoor");
110 
111  auto decorator = dynamic_cast<const InverterNode*>(sequence_closed->child(0));
112  ASSERT_TRUE(decorator != nullptr);
113 
114  ASSERT_EQ(decorator->child()->name(), "IsDoorOpen");
115 }
116 
118 {
119  BehaviorTreeFactory factory;
120  CrossDoor::RegisterNodes(factory);
121 
122  Tree tree = factory.createTreeFromText(xml_text_subtree);
123 
125 
126  ASSERT_EQ(tree.rootNode()->name(), "root_selector");
127 
128  auto root_selector = dynamic_cast<const FallbackNode*>(tree.rootNode());
129  ASSERT_TRUE(root_selector != nullptr);
130  ASSERT_EQ(root_selector->children().size(), 2);
131  ASSERT_EQ(root_selector->child(0)->name(), "CrossDoorSubtree");
132  ASSERT_EQ(root_selector->child(1)->name(), "PassThroughWindow");
133 
134  auto subtree = dynamic_cast<const SubtreeNode*>(root_selector->child(0));
135  ASSERT_TRUE(subtree != nullptr);
136 
137  auto sequence = dynamic_cast<const SequenceNode*>(subtree->child());
138  ASSERT_TRUE(sequence != nullptr);
139 
140  ASSERT_EQ(sequence->children().size(), 4);
141  ASSERT_EQ(sequence->child(0)->name(), "Inverter");
142  ASSERT_EQ(sequence->child(1)->name(), "OpenDoor");
143  ASSERT_EQ(sequence->child(2)->name(), "PassThroughDoor");
144  ASSERT_EQ(sequence->child(3)->name(), "CloseDoor");
145 
146  auto decorator = dynamic_cast<const InverterNode*>(sequence->child(0));
147  ASSERT_TRUE(decorator != nullptr);
148 
149  ASSERT_EQ(decorator->child()->name(), "IsDoorLocked");
150 }
151 
153 {
154 const std::string xml_text_issue = R"(
155 <root>
156  <BehaviorTree ID="ReceiveGuest">
157  </BehaviorTree>
158 </root> )";
159 
160  BehaviorTreeFactory factory;
161  XMLParser parser(factory);
162 
163  EXPECT_THROW( parser.loadFromText(xml_text_issue), RuntimeError );
164 }
165 
166 
167 // clang-format off
168 
169 static const char* xml_ports_subtree = R"(
170 
171 <root main_tree_to_execute = "MainTree" >
172 
173  <BehaviorTree ID="TalkToMe">
174  <Sequence>
175  <SaySomething message="{hello_msg}" />
176  <SaySomething message="{bye_msg}" />
177  <SetBlackboard output_key="output" value="done!" />
178  </Sequence>
179  </BehaviorTree>
180 
181  <BehaviorTree ID="MainTree">
182  <Sequence>
183  <SetBlackboard output_key="talk_hello" value="hello" />
184  <SetBlackboard output_key="talk_bye" value="bye bye" />
185  <SubTree ID="TalkToMe" hello_msg="talk_hello"
186  bye_msg="talk_bye"
187  output="talk_out" />
188  <SaySomething message="{talk_out}" />
189  </Sequence>
190  </BehaviorTree>
191 
192 </root> )";
193 
194 // clang-format on
195 
196 TEST(BehaviorTreeFactory, SubTreeWithRemapping)
197 {
198  BehaviorTreeFactory factory;
199  factory.registerNodeType<DummyNodes::SaySomething>("SaySomething");
200 
201  Tree tree = factory.createTreeFromText(xml_ports_subtree);
202 
203  auto main_bb = tree.blackboard_stack.at(0);
204  auto talk_bb = tree.blackboard_stack.at(1);
205 
206  std::cout << "\n --------------------------------- \n" << std::endl;
207  main_bb->debugMessage();
208  std::cout << "\n ----- \n" << std::endl;
209  talk_bb->debugMessage();
210  std::cout << "\n --------------------------------- \n" << std::endl;
211 
212  ASSERT_EQ( main_bb->portInfo("talk_hello")->type(), &typeid(std::string) );
213  ASSERT_EQ( main_bb->portInfo("talk_bye")->type(), &typeid(std::string) );
214  ASSERT_EQ( main_bb->portInfo("talk_out")->type(), &typeid(std::string) );
215 
216  ASSERT_EQ( talk_bb->portInfo("bye_msg")->type(), &typeid(std::string) );
217  ASSERT_EQ( talk_bb->portInfo("hello_msg")->type(), &typeid(std::string) );
218 
219  // Should not throw
220  tree.tickRoot();
221 
222  std::cout << "\n --------------------------------- \n" << std::endl;
223  main_bb->debugMessage();
224  std::cout << "\n ----- \n" << std::endl;
225  talk_bb->debugMessage();
226  std::cout << "\n --------------------------------- \n" << std::endl;
227 
228  ASSERT_EQ( main_bb->portInfo("talk_hello")->type(), &typeid(std::string) );
229  ASSERT_EQ( main_bb->portInfo("talk_bye")->type(), &typeid(std::string) );
230  ASSERT_EQ( main_bb->portInfo("talk_out")->type(), &typeid(std::string) );
231 
232  ASSERT_EQ( talk_bb->portInfo("bye_msg")->type(), &typeid(std::string) );
233  ASSERT_EQ( talk_bb->portInfo("hello_msg")->type(), &typeid(std::string) );
234  ASSERT_EQ( talk_bb->portInfo("output")->type(), &typeid(std::string) );
235 
236 
237  ASSERT_EQ( main_bb->get<std::string>("talk_hello"), "hello");
238  ASSERT_EQ( main_bb->get<std::string>("talk_bye"), "bye bye");
239  ASSERT_EQ( main_bb->get<std::string>("talk_out"), "done!");
240 
241  // these ports should not be present in the subtree TalkToMe
242  ASSERT_FALSE( talk_bb->getAny("talk_hello") );
243  ASSERT_FALSE( talk_bb->getAny("talk_bye") );
244  ASSERT_FALSE( talk_bb->getAny("talk_out") );
245 }
246 
const std::string & name() const
Name of the instance, not the type.
Definition: tree_node.cpp:73
void registerNodeType(const std::string &ID)
Definition: bt_factory.h:290
TEST(BehaviorTreeFactory, VerifyLargeTree)
static const char * xml_ports_subtree
std::vector< Blackboard::Ptr > blackboard_stack
Definition: bt_factory.h:135
static const char * xml_text_subtree
TreeNode * rootNode() const
Definition: bt_factory.h:176
void RegisterNodes(BT::BehaviorTreeFactory &factory)
The BehaviorTreeFactory is used to create instances of a TreeNode at run-time.
Definition: bt_factory.h:207
Tree createTreeFromText(const std::string &text, Blackboard::Ptr blackboard=Blackboard::create())
Definition: bt_factory.cpp:249
void printTreeRecursively(const TreeNode *root_node, std::ostream &stream=std::cout)
The SubtreeNode is a way to wrap an entire Subtree, creating a separated BlackBoard. If you want to have data flow through ports, you need to explicitly remap the ports.
Definition: subtree_node.h:15
The InverterNode returns SUCCESS if child fails of FAILURE is child succeeds. RUNNING status is propa...
Definition: inverter_node.h:26
Struct used to store a tree. If this object goes out of scope, the tree is destroyed.
Definition: bt_factory.h:130
The XMLParser is a class used to read the model of a BehaviorTree from file or text and instantiate t...
Definition: xml_parsing.h:14
void loadFromText(const std::string &xml_text) override
The FallbackNode is used to try different strategies, until one succeeds. If any child returns RUNNIN...
Definition: fallback_node.h:33
static const char * xml_text
The SequenceNode is used to tick children in an ordered sequence. If any child returns RUNNING...
Definition: sequence_node.h:34


behaviotree_cpp_v3
Author(s): Michele Colledanchise, Davide Faconti
autogenerated on Tue May 4 2021 02:56:24