gtest_subtree.cpp
Go to the documentation of this file.
1 #include <gtest/gtest.h>
3 #include "../sample_nodes/dummy_nodes.h"
4 
5 using namespace BT;
6 
7 TEST(SubTree, SiblingPorts_Issue_72)
8 {
9  static const char* xml_text = R"(
10 
11 <root main_tree_to_execute = "MainTree" >
12 
13  <BehaviorTree ID="MainTree">
14  <Sequence>
15  <SetBlackboard value="hello" output_key="myParam" />
16  <SubTree ID="mySubtree" param="myParam" />
17  <SetBlackboard value="world" output_key="myParam" />
18  <SubTree ID="mySubtree" param="myParam" />
19  </Sequence>
20  </BehaviorTree>
21 
22  <BehaviorTree ID="mySubtree">
23  <SaySomething message="{param}" />
24  </BehaviorTree>
25 </root> )";
26 
27  BehaviorTreeFactory factory;
28  factory.registerNodeType<DummyNodes::SaySomething>("SaySomething");
29 
30  Tree tree = factory.createTreeFromText(xml_text);
31 
32  for (auto& bb : tree.blackboard_stack)
33  {
34  bb->debugMessage();
35  std::cout << "-----" << std::endl;
36  }
37 
38  auto ret = tree.tickRoot();
39 
40  ASSERT_EQ(ret, NodeStatus::SUCCESS);
41  ASSERT_EQ(tree.blackboard_stack.size(), 3);
42 }
43 
45 {
46 public:
47  CopyPorts(const std::string& name, const BT::NodeConfiguration& config) :
48  BT::SyncActionNode(name, config)
49  {}
50 
51  BT::NodeStatus tick() override
52  {
53  auto msg = getInput<std::string>("in");
54  if (!msg)
55  {
56  throw BT::RuntimeError("missing required input [message]: ", msg.error());
57  }
58  setOutput("out", msg.value());
60  }
61 
63  {
64  return {BT::InputPort<std::string>("in"), BT::OutputPort<std::string>("out")};
65  }
66 };
67 
68 TEST(SubTree, GoodRemapping)
69 {
70  static const char* xml_text = R"(
71 
72 <root main_tree_to_execute = "MainTree" >
73 
74  <BehaviorTree ID="MainTree">
75  <Sequence>
76  <SetBlackboard value="hello" output_key="thoughts" />
77  <SubTree ID="CopySubtree" in_arg="thoughts" out_arg="greetings"/>
78  <SaySomething message="{greetings}" />
79  </Sequence>
80  </BehaviorTree>
81 
82  <BehaviorTree ID="CopySubtree">
83  <CopyPorts in="{in_arg}" out="{out_arg}"/>
84  </BehaviorTree>
85 </root> )";
86 
87  BehaviorTreeFactory factory;
88  factory.registerNodeType<DummyNodes::SaySomething>("SaySomething");
89  factory.registerNodeType<CopyPorts>("CopyPorts");
90 
91  Tree tree = factory.createTreeFromText(xml_text);
92  auto ret = tree.tickRoot();
93  ASSERT_EQ(ret, NodeStatus::SUCCESS);
94 }
95 
96 TEST(SubTree, BadRemapping)
97 {
98  BehaviorTreeFactory factory;
99  factory.registerNodeType<DummyNodes::SaySomething>("SaySomething");
100  factory.registerNodeType<CopyPorts>("CopyPorts");
101 
102  static const char* xml_text_bad_in = R"(
103 <root main_tree_to_execute = "MainTree" >
104 
105  <BehaviorTree ID="MainTree">
106  <Sequence>
107  <SetBlackboard value="hello" output_key="thoughts" />
108  <SubTree ID="CopySubtree" out_arg="greetings"/>
109  <SaySomething message="{greetings}" />
110  </Sequence>
111  </BehaviorTree>
112 
113  <BehaviorTree ID="CopySubtree">
114  <CopyPorts in="{in_arg}" out="{out_arg}"/>
115  </BehaviorTree>
116 </root> )";
117 
118  Tree tree_bad_in = factory.createTreeFromText(xml_text_bad_in);
119  EXPECT_ANY_THROW(tree_bad_in.tickRoot());
120 
121  static const char* xml_text_bad_out = R"(
122 <root main_tree_to_execute = "MainTree" >
123 
124  <BehaviorTree ID="MainTree">
125  <Sequence>
126  <SetBlackboard value="hello" output_key="thoughts" />
127  <SubTree ID="CopySubtree" in_arg="thoughts"/>
128  <SaySomething message="{greetings}" />
129  </Sequence>
130  </BehaviorTree>
131 
132  <BehaviorTree ID="CopySubtree">
133  <CopyPorts in="{in_arg}" out="{out_arg}"/>
134  </BehaviorTree>
135 </root> )";
136 
137  Tree tree_bad_out = factory.createTreeFromText(xml_text_bad_out);
138  EXPECT_ANY_THROW(tree_bad_out.tickRoot());
139 }
140 
141 TEST(SubTree, SubtreePlusA)
142 {
143  static const char* xml_text = R"(
144 
145 <root main_tree_to_execute = "MainTree" >
146 
147  <BehaviorTree ID="MainTree">
148  <Sequence>
149  <SetBlackboard value="Auto remapped" output_key="param" />
150  <SubTreePlus ID="mySubtree" __autoremap="1" />
151  </Sequence>
152  </BehaviorTree>
153 
154  <BehaviorTree ID="mySubtree">
155  <SaySomething message="{param}" />
156  </BehaviorTree>
157 </root> )";
158 
159  BehaviorTreeFactory factory;
160  factory.registerNodeType<DummyNodes::SaySomething>("SaySomething");
161 
162  Tree tree = factory.createTreeFromText(xml_text);
163  auto ret = tree.tickRoot();
164  ASSERT_EQ(ret, NodeStatus::SUCCESS);
165 }
166 
167 TEST(SubTree, SubtreePlusB)
168 {
169  static const char* xml_text = R"(
170 
171 <root main_tree_to_execute = "MainTree" >
172 
173  <BehaviorTree ID="MainTree">
174  <Sequence>
175  <SetBlackboard value="Hello World" output_key="myParam" />
176  <SetBlackboard value="Auto remapped" output_key="param3" />
177  <SubTreePlus ID="mySubtree" __autoremap="1" param1="{myParam}" param2="Straight Talking" />
178  </Sequence>
179  </BehaviorTree>
180 
181  <BehaviorTree ID="mySubtree">
182  <Sequence>
183  <SaySomething message="{param1}" />
184  <SaySomething message="{param2}" />
185  <SaySomething message="{param3}" />
186  </Sequence>
187  </BehaviorTree>
188 </root> )";
189 
190  BehaviorTreeFactory factory;
191  factory.registerNodeType<DummyNodes::SaySomething>("SaySomething");
192 
193  Tree tree = factory.createTreeFromText(xml_text);
194  auto ret = tree.tickRoot();
195  ASSERT_EQ(ret, NodeStatus::SUCCESS);
196 }
197 
198 TEST(SubTree, SubtreePlusC)
199 {
200  static const char* xml_text = R"(
201 
202 <root main_tree_to_execute = "MainTree" >
203 
204  <BehaviorTree ID="MainTree">
205  <Sequence>
206  <SetBlackboard value="Hello" output_key="param1" />
207  <SetBlackboard value="World" output_key="param2" />
208  <SubTree ID="mySubtree" __shared_blackboard="true"/>
209  </Sequence>
210  </BehaviorTree>
211 
212  <BehaviorTree ID="mySubtree">
213  <Sequence>
214  <SaySomething message="{param1}" />
215  <SaySomething message="{param2}" />
216  </Sequence>
217  </BehaviorTree>
218 </root> )";
219 
220  BehaviorTreeFactory factory;
221  factory.registerNodeType<DummyNodes::SaySomething>("SaySomething");
222 
223  Tree tree = factory.createTreeFromText(xml_text);
224  auto ret = tree.tickRoot();
225  ASSERT_EQ(ret, NodeStatus::SUCCESS);
226 }
227 
229 {
230 public:
231  ReadInConstructor(const std::string& name, const BT::NodeConfiguration& config) :
232  BT::SyncActionNode(name, config)
233  {
234  auto msg = getInput<std::string>("message");
235  if (!msg)
236  {
237  throw BT::RuntimeError("missing required input [message]: ", msg.error());
238  }
239  }
240 
241  BT::NodeStatus tick() override
242  {
244  }
246  {
247  return {BT::InputPort<std::string>("message")};
248  }
249 };
250 
251 TEST(SubTree, SubtreePlusD)
252 {
253  BT::NodeConfiguration config;
255  static const char* xml_text = R"(
256 
257 <root main_tree_to_execute = "MainTree" >
258 
259  <BehaviorTree ID="MainTree">
260  <Sequence>
261  <SubTreePlus ID="mySubtree" __autoremap="1"/>
262  </Sequence>
263  </BehaviorTree>
264  <BehaviorTree ID="mySubtree">
265  <ReadInConstructor message="{message}" />
266  </BehaviorTree>
267 </root> )";
268 
269  BT::BehaviorTreeFactory factory;
270  factory.registerNodeType<ReadInConstructor>("ReadInConstructor");
271  config.blackboard->set("message", "hello");
272  BT::Tree tree = factory.createTreeFromText(xml_text, config.blackboard);
273  auto ret = tree.tickRoot();
274  ASSERT_EQ(ret, BT::NodeStatus::SUCCESS);
275 }
276 
277 TEST(SubTree, SubtreeIssue433)
278 {
279  BT::NodeConfiguration config;
281  static const char* xml_text = R"(
282 
283 <root main_tree_to_execute = "TestTree" >
284  <BehaviorTree ID="Subtree1">
285  <Decorator ID="Repeat" num_cycles="{port_to_use}">
286  <Action ID="AlwaysSuccess"/>
287  </Decorator>
288  </BehaviorTree>
289 
290  <BehaviorTree ID="Subtree2">
291  <Action ID="SetBlackboard" output_key="test_port" value="{port_to_read}"/>
292  </BehaviorTree>
293 
294  <BehaviorTree ID="TestTree">
295  <Sequence>
296  <Action ID="SetBlackboard" output_key="test_port" value="1"/>
297  <SubTree ID="Subtree1" port_to_use="test_port"/>
298  <SubTree ID="Subtree2" port_to_read="test_port"/>
299  </Sequence>
300  </BehaviorTree>
301 </root> )";
302 
303  BT::BehaviorTreeFactory factory;
304 
305  BT::Tree tree = factory.createTreeFromText(xml_text, config.blackboard);
306  auto ret = tree.tickRoot();
307 
308  ASSERT_EQ(ret, BT::NodeStatus::SUCCESS);
309 }
310 
311 
313 {
314 public:
315  NaughtyNav2Node(const std::string& name, const BT::NodeConfiguration& config) :
316  BT::SyncActionNode(name, config)
317  {
318  std::cout << "CTOR:" << config.blackboard->get<std::string>("ros_node") << std::endl;
319  }
320 
321  BT::NodeStatus tick() override
322  {
323  std::cout << "tick:" << config().blackboard->get<std::string>("ros_node") << std::endl;
325  }
327  {
328  return {};
329  }
330 };
331 
332 TEST(SubTree, SubtreeIssue563)
333 {
334  static const char* xml_text = R"(
335 <root main_tree_to_execute="Tree1">
336 
337 <BehaviorTree ID="Tree1">
338  <Sequence>
339  <SetBlackboard output_key="the_message" value="hello world"/>
340  <SubTreePlus ID="Tree2" __autoremap="true"/>
341  <SaySomething message="{reply}" />
342  </Sequence>
343 </BehaviorTree>
344 
345 <BehaviorTree ID="Tree2">
346  <SubTreePlus ID="Tree3" __autoremap="true"/>
347 </BehaviorTree>
348 
349 <BehaviorTree ID="Tree3">
350  <SubTreePlus ID="Talker" __autoremap="true"/>
351 </BehaviorTree>
352 
353 <BehaviorTree ID="Talker">
354  <Sequence>
355  <SaySomething message="{the_message}" />
356  <SetBlackboard output_key="reply" value="done"/>
357  <NaughtyNav2Node/>
358  </Sequence>
359 </BehaviorTree>
360 
361 </root>)";
362 
363  BehaviorTreeFactory factory;
364  factory.registerNodeType<DummyNodes::SaySomething>("SaySomething");
365  factory.registerNodeType<NaughtyNav2Node>("NaughtyNav2Node");
366 
367  auto blackboard = BT::Blackboard::create();
368  blackboard->set<std::string>("ros_node", "nav2_shouldnt_do_this");
369 
370  Tree tree = factory.createTreeFromText(xml_text, blackboard);
371 
372  auto ret = tree.tickRoot();
373  ASSERT_EQ(ret, NodeStatus::SUCCESS);
374 }
static Blackboard::Ptr create(Blackboard::Ptr parent={})
Definition: blackboard.h:36
void registerNodeType(const std::string &ID)
Definition: bt_factory.h:364
CopyPorts(const std::string &name, const BT::NodeConfiguration &config)
static BT::PortsList providedPorts()
TEST(SubTree, SiblingPorts_Issue_72)
BT::NodeStatus tick() override
Method to be implemented by the user.
static BT::PortsList providedPorts()
static const char * xml_text
Blackboard::Ptr blackboard
Definition: tree_node.h:49
static BT::PortsList providedPorts()
BT::NodeStatus tick() override
Method to be implemented by the user.
The SyncActionNode is an ActionNode that explicitly prevents the status RUNNING and doesn&#39;t require a...
Definition: action_node.h:52
The BehaviorTreeFactory is used to create instances of a TreeNode at run-time.
Definition: bt_factory.h:251
NodeStatus tickRoot()
tickRoot send the tick signal to the root node. It will propagate through the entire tree...
Definition: bt_factory.h:210
Tree createTreeFromText(const std::string &text, Blackboard::Ptr blackboard=Blackboard::create())
Definition: bt_factory.cpp:278
Struct used to store a tree. If this object goes out of scope, the tree is destroyed.
Definition: bt_factory.h:125
BT::NodeStatus tick() override
Method to be implemented by the user.
std::unordered_map< std::string, PortInfo > PortsList
Definition: basic_types.h:333
NaughtyNav2Node(const std::string &name, const BT::NodeConfiguration &config)
ReadInConstructor(const std::string &name, const BT::NodeConfiguration &config)
NodeStatus
Definition: basic_types.h:35


behaviortree_cpp_v3
Author(s): Michele Colledanchise, Davide Faconti
autogenerated on Mon Jul 3 2023 02:50:14