gtest_preconditions.cpp
Go to the documentation of this file.
1 #include <gtest/gtest.h>
2 #include <string>
5 #include "test_helper.hpp"
6 
7 using namespace BT;
8 
9 TEST(PreconditionsDecorator, Integers)
10 {
11  BehaviorTreeFactory factory;
12  std::array<int, 3> counters;
13  RegisterTestTick(factory, "Test", counters);
14 
15  const std::string xml_text = R"(
16 
17  <root BTCPP_format="4" >
18  <BehaviorTree ID="MainTree">
19  <Sequence>
20  <Script code = "A:=1; B:=1; C:=3" />
21  <Precondition if="A==B" else="FAILURE">
22  <TestA/>
23  </Precondition>
24  <Precondition if="A==C" else="SUCCESS">
25  <TestB/>
26  </Precondition>
27  <Precondition if="A!=C" else="FAILURE">
28  <TestC/>
29  </Precondition>
30  </Sequence>
31  </BehaviorTree>
32  </root>)";
33 
34  auto tree = factory.createTreeFromText(xml_text);
35  const auto status = tree.tickWhileRunning();
36  ASSERT_EQ(status, NodeStatus::SUCCESS);
37  ASSERT_EQ(counters[0], 1);
38  ASSERT_EQ(counters[1], 0);
39  ASSERT_EQ(counters[2], 1);
40 }
41 
42 TEST(PreconditionsDecorator, DoubleEquals)
43 {
44  BehaviorTreeFactory factory;
45  std::array<int, 3> counters;
46  RegisterTestTick(factory, "Test", counters);
47 
48  const std::string xml_text = R"(
49 
50  <root BTCPP_format="4" >
51  <BehaviorTree ID="MainTree">
52  <Sequence>
53  <Script code = " A:=1.1; B:=(1.0+0.1); C:= 2.0 " />
54 
55  <Precondition if="A==B" else="FAILURE">
56  <TestA/>
57  </Precondition>
58 
59  <Precondition if="A==C" else="SUCCESS">
60  <TestB/>
61  </Precondition>
62 
63  <Precondition if="A!=C" else="FAILURE">
64  <TestC/>
65  </Precondition>
66  </Sequence>
67  </BehaviorTree>
68  </root>)";
69 
70  auto tree = factory.createTreeFromText(xml_text);
71  const auto status = tree.tickWhileRunning();
72  ASSERT_EQ(status, NodeStatus::SUCCESS);
73  ASSERT_EQ(counters[0], 1);
74  ASSERT_EQ(counters[1], 0);
75  ASSERT_EQ(counters[2], 1);
76 }
77 
78 TEST(PreconditionsDecorator, StringEquals)
79 {
80  BehaviorTreeFactory factory;
81  std::array<int, 2> counters;
82  RegisterTestTick(factory, "Test", counters);
83 
84  const std::string xml_text = R"(
85 
86  <root BTCPP_format="4" >
87  <BehaviorTree ID="MainTree">
88  <Sequence>
89  <Script code = "A:='hello'" />
90  <Script code = "B:='world'" />
91  <Script code = "C:='world'" />
92 
93  <Precondition if=" A==B " else="SUCCESS">
94  <TestA/>
95  </Precondition>
96  <Precondition if=" B==C " else="FAILURE">
97  <TestB/>
98  </Precondition>
99  </Sequence>
100  </BehaviorTree>
101  </root>)";
102 
103  auto tree = factory.createTreeFromText(xml_text);
104  const auto status = tree.tickWhileRunning();
105  ASSERT_EQ(status, NodeStatus::SUCCESS);
106  ASSERT_EQ(counters[0], 0);
107  ASSERT_EQ(counters[1], 1);
108 }
109 
110 TEST(Preconditions, Basic)
111 {
112  BehaviorTreeFactory factory;
113  std::array<int, 4> counters;
114  RegisterTestTick(factory, "Test", counters);
115 
116  const std::string xml_text = R"(
117 
118  <root BTCPP_format="4" >
119  <BehaviorTree ID="MainTree">
120  <Sequence>
121  <Script code = "A:=1" />
122  <TestA _successIf= "A==1"/>
123  <TestB _successIf= "A==2"/>
124  <Fallback>
125  <TestC _failureIf= "A==1"/>
126  <TestD _failureIf= "A!=1"/>
127  </Fallback>
128  </Sequence>
129  </BehaviorTree>
130  </root>)";
131 
132  auto tree = factory.createTreeFromText(xml_text);
133  const auto status = tree.tickWhileRunning();
134  ASSERT_EQ(status, NodeStatus::SUCCESS);
135  ASSERT_EQ(counters[0], 0); // skipped
136  ASSERT_EQ(counters[1], 1); // executed
137  ASSERT_EQ(counters[2], 0); // skipped
138  ASSERT_EQ(counters[3], 1); // executed
139 }
140 
141 TEST(Preconditions, Issue533)
142 {
143  BehaviorTreeFactory factory;
144  std::array<int, 3> counters;
145  RegisterTestTick(factory, "Test", counters);
146 
147  const std::string xml_text = R"(
148 
149  <root BTCPP_format="4" >
150  <BehaviorTree ID="MainTree">
151  <Sequence>
152  <TestA _skipIf="A!=1" />
153  <TestB _skipIf="A!=2" _onSuccess="A=1"/>
154  <TestC _skipIf="A!=3" _onSuccess="A=2"/>
155  </Sequence>
156  </BehaviorTree>
157  </root>)";
158 
159  auto tree = factory.createTreeFromText(xml_text);
160  tree.subtrees.front()->blackboard->set("A", 3);
161 
162  tree.tickOnce();
163  ASSERT_EQ(counters[0], 0);
164  ASSERT_EQ(counters[1], 0);
165  ASSERT_EQ(counters[2], 1);
166 
167  tree.tickOnce();
168  ASSERT_EQ(counters[0], 0);
169  ASSERT_EQ(counters[1], 1);
170  ASSERT_EQ(counters[2], 1);
171 
172  tree.tickOnce();
173  ASSERT_EQ(counters[0], 1);
174  ASSERT_EQ(counters[1], 1);
175  ASSERT_EQ(counters[2], 1);
176 }
177 
179 {
180 public:
181  CoroTestNode(const std::string& node_name, const BT::NodeConfig& config)
182  : BT::CoroActionNode(node_name, config)
183  {}
184 
185  virtual BT::NodeStatus tick() override
186  {
187  for(int i = 0; i < 10; i++)
188  {
189  times_ticked++;
190  setStatusRunningAndYield();
191  }
192  return NodeStatus::SUCCESS;
193  }
194 
196  {
197  return {};
198  }
199 
200  int times_ticked = 0;
201 };
202 
203 TEST(Preconditions, Issue585)
204 {
205  BehaviorTreeFactory factory;
206  factory.registerNodeType<CoroTestNode>("CoroTest");
207 
208  const std::string xml_text = R"(
209 
210  <root BTCPP_format="4" >
211  <BehaviorTree ID="MainTree">
212  <Sequence>
213  <Script code="A:=1" />
214  <CoroTest _skipIf="A==1" />
215  </Sequence>
216  </BehaviorTree>
217  </root>)";
218 
219  auto tree = factory.createTreeFromText(xml_text);
220  tree.tickWhileRunning();
221 
222  auto coro = dynamic_cast<CoroTestNode*>(tree.subtrees.front()->nodes.back().get());
223  ASSERT_EQ(coro->times_ticked, 0);
224 }
225 
226 TEST(Preconditions, Issue615_NoSkipWhenRunning_A)
227 {
228  static constexpr auto xml_text = R"(
229  <root BTCPP_format="4">
230  <BehaviorTree>
231  <KeepRunningUntilFailure _skipIf="check == true">
232  <AlwaysSuccess/>
233  </KeepRunningUntilFailure>
234  </BehaviorTree>
235  </root> )";
236 
237  BehaviorTreeFactory factory;
238  auto tree = factory.createTreeFromText(xml_text);
239 
240  tree.rootBlackboard()->set("check", false);
241  ASSERT_EQ(tree.tickOnce(), NodeStatus::RUNNING);
242 
243  // the precondition should NOT be called, because
244  // KeepRunningUntilFailure is in RUNNING state
245  tree.rootBlackboard()->set("check", true);
246  ASSERT_EQ(tree.tickOnce(), NodeStatus::RUNNING);
247 }
248 
250 {
251 public:
252  KeepRunning(const std::string& name, const BT::NodeConfig& config)
253  : BT::StatefulActionNode(name, config)
254  {}
255 
257  {
258  return {};
259  }
260 
262  {
264  }
265 
267  {
269  }
270 
271  void onHalted() override
272  {
273  std::cout << "Node halted\n";
274  }
275 };
276 
277 TEST(Preconditions, Issue615_NoSkipWhenRunning_B)
278 {
279  static constexpr auto xml_text = R"(
280  <root BTCPP_format="4">
281  <BehaviorTree>
282  <KeepRunning _skipIf="check==false"/>
283  </BehaviorTree>
284  </root>
285  )";
286 
287  BehaviorTreeFactory factory;
288  factory.registerNodeType<KeepRunning>("KeepRunning");
289  auto tree = factory.createTreeFromText(xml_text);
290 
291  tree.rootBlackboard()->set("check", false);
292  ASSERT_EQ(tree.tickOnce(), NodeStatus::SKIPPED);
293 
294  // Should not be skipped anymore
295  tree.rootBlackboard()->set("check", true);
296  ASSERT_EQ(tree.tickOnce(), NodeStatus::RUNNING);
297 
298  // skipIf should be ignored, because KeepRunning is RUNNING and not IDLE
299  tree.rootBlackboard()->set("check", false);
300  ASSERT_EQ(tree.tickOnce(), NodeStatus::RUNNING);
301 }
302 
304 {
305 public:
306  SimpleOutput(const std::string& name, const BT::NodeConfig& config)
307  : BT::SyncActionNode(name, config)
308  {}
309 
311  {
312  return { OutputPort<bool>("output") };
313  }
314 
315  BT::NodeStatus tick() override
316  {
317  setOutput("output", true);
319  }
320 };
321 
322 TEST(Preconditions, Remapping)
323 {
324  static constexpr auto xml_text = R"(
325  <root BTCPP_format="4">
326 
327  <BehaviorTree ID="Main">
328  <Sequence>
329  <SimpleOutput output="{param}" />
330  <Script code="value:=true" />
331 
332  <SubTree ID="Sub1" param="{param}"/>
333  <SubTree ID="Sub1" param="{value}"/>
334  <SubTree ID="Sub1" param="true"/>
335  <TestA/>
336  </Sequence>
337  </BehaviorTree>
338 
339  <BehaviorTree ID="Sub1">
340  <Sequence>
341  <SubTree ID="Sub2" _skipIf="param != true" />
342  </Sequence>
343  </BehaviorTree>
344 
345  <BehaviorTree ID="Sub2">
346  <TestB/>
347  </BehaviorTree>
348  </root>
349  )";
350 
351  BehaviorTreeFactory factory;
352 
353  std::array<int, 2> counters;
354  factory.registerNodeType<SimpleOutput>("SimpleOutput");
355  RegisterTestTick(factory, "Test", counters);
356 
358  auto tree = factory.createTree("Main");
359 
360  auto status = tree.tickWhileRunning();
361 
362  ASSERT_EQ(status, BT::NodeStatus::SUCCESS);
363  ASSERT_EQ(counters[0], 1);
364  ASSERT_EQ(counters[1], 3);
365 }
366 
367 TEST(Preconditions, WhileCallsOnHalt)
368 {
369  static constexpr auto xml_text = R"(
370  <root BTCPP_format="4">
371 
372  <BehaviorTree ID="Main">
373  <Sequence>
374  <KeepRunning _while="A==1" _onHalted="B=69" />
375  </Sequence>
376  </BehaviorTree>
377  </root>
378  )";
379 
380  BehaviorTreeFactory factory;
381 
382  factory.registerNodeType<KeepRunning>("KeepRunning");
384  auto tree = factory.createTree("Main");
385 
386  tree.rootBlackboard()->set("A", 1);
387  tree.rootBlackboard()->set("B", 0);
388  auto status = tree.tickOnce();
389 
390  ASSERT_EQ(status, BT::NodeStatus::RUNNING);
391  ASSERT_EQ(tree.rootBlackboard()->get<int>("B"), 0);
392 
393  // trigger halt
394  tree.rootBlackboard()->set("A", 0);
395  status = tree.tickOnce();
396 
397  ASSERT_EQ(status, BT::NodeStatus::SKIPPED);
398  ASSERT_EQ(tree.rootBlackboard()->get<int>("B"), 69);
399 }
BT
Definition: ex01_wrap_legacy.cpp:29
KeepRunning
Definition: gtest_preconditions.cpp:249
BT::BehaviorTreeFactory::createTree
Tree createTree(const std::string &tree_name, Blackboard::Ptr blackboard=Blackboard::create())
Definition: bt_factory.cpp:432
KeepRunning::KeepRunning
KeepRunning(const std::string &name, const BT::NodeConfig &config)
Definition: gtest_preconditions.cpp:252
KeepRunning::onRunning
BT::NodeStatus onRunning() override
method invoked when the action is already in the RUNNING state.
Definition: gtest_preconditions.cpp:266
basic_types.h
SimpleOutput::providedPorts
static BT::PortsList providedPorts()
Definition: gtest_preconditions.cpp:310
RegisterTestTick
void RegisterTestTick(BT::BehaviorTreeFactory &factory, const std::string &name_prefix, std::array< int, N > &tick_counters)
Definition: test_helper.hpp:15
SimpleOutput
Definition: gtest_preconditions.cpp:303
CoroTestNode::providedPorts
static PortsList providedPorts()
Definition: gtest_preconditions.cpp:195
bt_factory.h
test_helper.hpp
TEST
TEST(PreconditionsDecorator, Integers)
Definition: gtest_preconditions.cpp:9
BT::Tree::tickWhileRunning
NodeStatus tickWhileRunning(std::chrono::milliseconds sleep_time=std::chrono::milliseconds(10))
Definition: bt_factory.cpp:610
BT::PortsList
std::unordered_map< std::string, PortInfo > PortsList
Definition: basic_types.h:585
KeepRunning::onStart
BT::NodeStatus onStart() override
Definition: gtest_preconditions.cpp:261
KeepRunning::onHalted
void onHalted() override
Definition: gtest_preconditions.cpp:271
SimpleOutput::SimpleOutput
SimpleOutput(const std::string &name, const BT::NodeConfig &config)
Definition: gtest_preconditions.cpp:306
BT::NodeStatus::SKIPPED
@ SKIPPED
SimpleOutput::tick
BT::NodeStatus tick() override
Method to be implemented by the user.
Definition: gtest_preconditions.cpp:315
BT::BehaviorTreeFactory::registerNodeType
void registerNodeType(const std::string &ID, const PortsList &ports, ExtraArgs... args)
Definition: bt_factory.h:326
CoroTestNode::CoroTestNode
CoroTestNode(const std::string &node_name, const BT::NodeConfig &config)
Definition: gtest_preconditions.cpp:181
BT::BehaviorTreeFactory::createTreeFromText
Tree createTreeFromText(const std::string &text, Blackboard::Ptr blackboard=Blackboard::create())
createTreeFromText will parse the XML directly from string. The XML needs to contain either a single ...
Definition: bt_factory.cpp:395
BT::BehaviorTreeFactory
The BehaviorTreeFactory is used to create instances of a TreeNode at run-time.
Definition: bt_factory.h:209
KeepRunning::providedPorts
static BT::PortsList providedPorts()
Definition: gtest_preconditions.cpp:256
BT::NodeStatus::SUCCESS
@ SUCCESS
BT::Tree::subtrees
std::vector< Subtree::Ptr > subtrees
Definition: bt_factory.h:104
BT::NodeStatus::RUNNING
@ RUNNING
CoroTestNode
Definition: gtest_preconditions.cpp:178
BT::BehaviorTreeFactory::registerBehaviorTreeFromText
void registerBehaviorTreeFromText(const std::string &xml_text)
Definition: bt_factory.cpp:277
BT::Tree::rootBlackboard
Blackboard::Ptr rootBlackboard()
Definition: bt_factory.cpp:615
BT::NodeConfig
Definition: tree_node.h:73
xml_text
static const char * xml_text
Definition: ex01_wrap_legacy.cpp:52
CoroTestNode::tick
virtual BT::NodeStatus tick() override
Method to be implemented by the user.
Definition: gtest_preconditions.cpp:185
BT::SyncActionNode
The SyncActionNode is an ActionNode that explicitly prevents the status RUNNING and doesn't require a...
Definition: action_node.h:52
BT::NodeStatus
NodeStatus
Definition: basic_types.h:33
BT::CoroActionNode
The CoroActionNode class is an a good candidate for asynchronous actions which need to communicate wi...
Definition: action_node.h:196
BT::StatefulActionNode
The StatefulActionNode is the preferred way to implement asynchronous Actions. It is actually easier ...
Definition: action_node.h:159


behaviortree_cpp_v4
Author(s): Davide Faconti
autogenerated on Fri Dec 13 2024 03:19:16