gtest_blackboard.cpp
Go to the documentation of this file.
1 /* Copyright (C) 2018-2023 Davide Faconti, Eurecat - All Rights Reserved
2 *
3 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"),
4 * to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
5 * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
9 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
10 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
11 */
12 
13 #include <gtest/gtest.h>
16 
17 #include "../sample_nodes/dummy_nodes.h"
18 
19 using namespace BT;
20 
22 {
23 public:
24  BB_TestNode(const std::string& name, const NodeConfiguration& config) :
25  SyncActionNode(name, config)
26  {}
27 
29  {
30  int value = 0;
31  auto res = getInput<int>("in_port");
32  if (!res)
33  {
34  throw RuntimeError("BB_TestNode needs input", res.error());
35  }
36  value = res.value() * 2;
37  if (!setOutput("out_port", value))
38  {
39  throw RuntimeError("BB_TestNode failed output");
40  }
41  return NodeStatus::SUCCESS;
42  }
43 
45  {
46  return {BT::InputPort<int>("in_port"), BT::OutputPort<int>("out_port")};
47  }
48 };
49 
51 {
52 public:
53  BB_TypedTestNode(const std::string& name, const NodeConfiguration& config) :
54  SyncActionNode(name, config)
55  {}
56 
58  {
59  return NodeStatus::SUCCESS;
60  }
61 
63  {
64  return {BT::InputPort("input"),
65  BT::InputPort<int>("input_int"),
66  BT::InputPort<std::string>("input_string"),
67 
68  BT::OutputPort("output"),
69  BT::OutputPort<int>("output_int"),
70  BT::OutputPort<std::string>("output_string")};
71  }
72 };
73 
74 TEST(BlackboardTest, GetInputsFromBlackboard)
75 {
76  auto bb = Blackboard::create();
77 
78  NodeConfiguration config;
79  assignDefaultRemapping<BB_TestNode>(config);
80 
81  config.blackboard = bb;
82  bb->set("in_port", 11);
83 
84  BB_TestNode node("good_one", config);
85 
86  // this should read and write "my_entry" in tick()
87  node.executeTick();
88 
89  ASSERT_EQ(bb->get<int>("out_port"), 22);
90 }
91 
92 TEST(BlackboardTest, BasicRemapping)
93 {
94  auto bb = Blackboard::create();
95 
96  NodeConfiguration config;
97 
98  config.blackboard = bb;
99  config.input_ports["in_port"] = "{my_input_port}";
100  config.output_ports["out_port"] = "{my_output_port}";
101  bb->set("my_input_port", 11);
102 
103  BB_TestNode node("good_one", config);
104  node.executeTick();
105 
106  ASSERT_EQ(bb->get<int>("my_output_port"), 22);
107 }
108 
109 TEST(BlackboardTest, GetInputsFromText)
110 {
111  auto bb = Blackboard::create();
112 
113  NodeConfiguration config;
114  config.input_ports["in_port"] = "11";
115 
116  BB_TestNode missing_out("missing_output", config);
117  EXPECT_THROW(missing_out.executeTick(), RuntimeError);
118 
119  config.blackboard = bb;
120  config.output_ports["out_port"] = "=";
121 
122  BB_TestNode node("good_one", config);
123  node.executeTick();
124 
125  ASSERT_EQ(bb->get<int>("out_port"), 22);
126 }
127 
128 TEST(BlackboardTest, SetOutputFromText)
129 {
130  const char* xml_text = R"(
131 
132  <root main_tree_to_execute = "MainTree" >
133  <BehaviorTree ID="MainTree">
134  <Sequence>
135  <BB_TestNode in_port="11" out_port="{my_port}"/>
136  <SetBlackboard output_key="my_port" value="-43" />
137  </Sequence>
138  </BehaviorTree>
139  </root>
140  )";
141 
142  BehaviorTreeFactory factory;
143  factory.registerNodeType<BB_TestNode>("BB_TestNode");
144 
145  auto bb = Blackboard::create();
146 
147  auto tree = factory.createTreeFromText(xml_text, bb);
148  tree.tickRoot();
149 }
150 
151 TEST(BlackboardTest, WithFactory)
152 {
153  BehaviorTreeFactory factory;
154 
155  factory.registerNodeType<BB_TestNode>("BB_TestNode");
156 
157  const std::string xml_text = R"(
158 
159  <root main_tree_to_execute = "MainTree" >
160  <BehaviorTree ID="MainTree">
161  <Sequence>
162  <BB_TestNode name = "first" in_port="11"
163  out_port="{my_input_port}"/>
164 
165  <BB_TestNode name = "second" in_port="{my_input_port}"
166  out_port="{my_input_port}" />
167 
168  <BB_TestNode name = "third" in_port="{my_input_port}"
169  out_port="{my_output_port}" />
170  </Sequence>
171  </BehaviorTree>
172  </root>)";
173 
174  auto bb = Blackboard::create();
175 
176  auto tree = factory.createTreeFromText(xml_text, bb);
177  NodeStatus status = tree.tickRoot();
178 
179  ASSERT_EQ(status, NodeStatus::SUCCESS);
180  ASSERT_EQ(bb->get<int>("my_input_port"), 44);
181  ASSERT_EQ(bb->get<int>("my_output_port"), 88);
182 }
183 
184 TEST(BlackboardTest, TypoInPortName)
185 {
186  BehaviorTreeFactory factory;
187  factory.registerNodeType<BB_TestNode>("BB_TestNode");
188 
189  const std::string xml_text = R"(
190 
191  <root main_tree_to_execute = "MainTree" >
192  <BehaviorTree ID="MainTree">
193  <BB_TestNode inpuuuut_port="{value}" />
194  </BehaviorTree>
195  </root>)";
196 
197  ASSERT_THROW(factory.createTreeFromText(xml_text), RuntimeError);
198 }
199 
200 TEST(BlackboardTest, CheckPortType)
201 {
202  BehaviorTreeFactory factory;
203  factory.registerNodeType<BB_TypedTestNode>("TypedNode");
204 
205  //-----------------------------
206  std::string good_one = R"(
207  <root main_tree_to_execute = "MainTree" >
208  <BehaviorTree ID="MainTree">
209  <Sequence>
210  <TypedNode name = "first" output_int="{matching}" output_string="{whatever}" output="{no_problem}" />
211  <TypedNode name = "second" input_int="{matching}" input="{whatever}" input_string="{no_problem}" />
212  </Sequence>
213  </BehaviorTree>
214  </root>)";
215 
216  auto tree = factory.createTreeFromText(good_one);
217  ASSERT_NE(tree.rootNode(), nullptr);
218  //-----------------------------
219  std::string bad_one = R"(
220  <root main_tree_to_execute = "MainTree" >
221  <BehaviorTree ID="MainTree">
222  <Sequence>
223  <TypedNode name = "first" output_int="{value}" />
224  <TypedNode name = "second" input_string="{value}" />
225  </Sequence>
226  </BehaviorTree>
227  </root>)";
228 
229  ASSERT_THROW(factory.createTreeFromText(bad_one), RuntimeError);
230 }
231 
233 {
234 public:
235  RefCountClass(std::shared_ptr<int> value) : sptr_(std::move(value))
236  {
237  std::cout << "Constructor: ref_count " << sptr_.use_count() << std::endl;
238  }
239 
240  RefCountClass(const RefCountClass& from) : sptr_(from.sptr_)
241  {
242  std::cout << "ctor copy: ref_count " << sptr_.use_count() << std::endl;
243  }
244 
246  {
247  sptr_ = (from.sptr_);
248  std::cout << "equal copied: ref_count " << sptr_.use_count() << std::endl;
249  return *this;
250  }
251 
252  virtual ~RefCountClass()
253  {
254  std::cout << ("Destructor") << std::endl;
255  }
256 
257  int refCount() const
258  {
259  return sptr_.use_count();
260  }
261 
262 private:
263  std::shared_ptr<int> sptr_;
264 };
265 
266 TEST(BlackboardTest, MoveVsCopy)
267 {
268  auto blackboard = Blackboard::create();
269 
270  RefCountClass test(std::make_shared<int>());
271 
272  ASSERT_EQ(test.refCount(), 1);
273 
274  std::cout << ("----- before set -----") << std::endl;
275  blackboard->set("testmove", test);
276  std::cout << (" ----- after set -----") << std::endl;
277 
278  ASSERT_EQ(test.refCount(), 2);
279 
280  RefCountClass other(blackboard->get<RefCountClass>("testmove"));
281 
282  ASSERT_EQ(test.refCount(), 3);
283 }
284 
285 TEST(BlackboardTest, CheckTypeSafety)
286 {
287  //TODO check type safety when ports are created.
288  // remember that std::string is considered a type erased type.
289 
290  bool is = std::is_constructible<BT::StringView, char*>::value;
291  ASSERT_TRUE(is);
292 
293  is = std::is_constructible<BT::StringView, std::string>::value;
294  ASSERT_TRUE(is);
295 }
296 
297 struct Point {
298  double x;
299  double y;
300 };
301 
302 TEST(BlackboardTest, SetBlackboard_Issue725)
303 {
304  BT::BehaviorTreeFactory factory;
305 
306  const std::string xml_text = R"(
307  <root main_tree_to_execute = "MainTree" >
308  <BehaviorTree ID="MainTree">
309  <SetBlackboard value="{first_point}" output_key="other_point" />
310  </BehaviorTree>
311  </root> )";
312 
313  factory.registerNodeType<DummyNodes::SaySomething>("SaySomething");
315  auto tree = factory.createTree("MainTree");
316  auto& blackboard = tree.blackboard_stack.front();
317 
318  const Point point = {2,7};
319  blackboard->set("first_point", point);
320 
321  const auto status = tree.tickRoot();
322 
323  Point other_point = blackboard->get<Point>("other_point");
324 
325  ASSERT_EQ(status, BT::NodeStatus::SUCCESS);
326  ASSERT_EQ(other_point.x, point.x);
327  ASSERT_EQ(other_point.y, point.y);
328 }
329 
BT
Definition: ex01_wrap_legacy.cpp:29
BT::Tree::tickRoot
NodeStatus tickRoot()
tickRoot send the tick signal to the root node. It will propagate through the entire tree.
Definition: bt_factory.h:210
BT::BehaviorTreeFactory::createTree
Tree createTree(const std::string &tree_name, Blackboard::Ptr blackboard=Blackboard::create())
Definition: bt_factory.cpp:313
BT::BehaviorTreeFactory::registerNodeType
void registerNodeType(const std::string &ID)
Definition: bt_factory.h:364
BB_TestNode
Definition: gtest_blackboard.cpp:21
RefCountClass
Definition: gtest_blackboard.cpp:232
BT::InputPort
std::pair< std::string, PortInfo > InputPort(StringView name, StringView description={})
Definition: basic_types.h:302
RefCountClass::sptr_
std::shared_ptr< int > sptr_
Definition: gtest_blackboard.cpp:263
BT::PortsList
std::unordered_map< std::string, PortInfo > PortsList
Definition: basic_types.h:342
RefCountClass::RefCountClass
RefCountClass(const RefCountClass &from)
Definition: gtest_blackboard.cpp:240
bt_factory.h
BT::NodeConfiguration::input_ports
PortsRemapping input_ports
Definition: tree_node.h:50
TEST
TEST(BlackboardTest, GetInputsFromBlackboard)
Definition: gtest_blackboard.cpp:74
BT::NodeConfiguration
Definition: tree_node.h:44
BT::NodeConfiguration::output_ports
PortsRemapping output_ports
Definition: tree_node.h:51
BT::SyncActionNode::executeTick
virtual NodeStatus executeTick() override
throws if the derived class return RUNNING.
Definition: action_node.cpp:54
BB_TypedTestNode::providedPorts
static PortsList providedPorts()
Definition: gtest_blackboard.cpp:62
BB_TestNode::BB_TestNode
BB_TestNode(const std::string &name, const NodeConfiguration &config)
Definition: gtest_blackboard.cpp:24
BT::BehaviorTreeFactory::createTreeFromText
Tree createTreeFromText(const std::string &text, Blackboard::Ptr blackboard=Blackboard::create())
Definition: bt_factory.cpp:278
Point
Definition: gtest_blackboard.cpp:297
BT::RuntimeError
Definition: exceptions.h:58
RefCountClass::RefCountClass
RefCountClass(std::shared_ptr< int > value)
Definition: gtest_blackboard.cpp:235
DummyNodes::SaySomething
Definition: dummy_nodes.h:50
BB_TypedTestNode::tick
NodeStatus tick()
Method to be implemented by the user.
Definition: gtest_blackboard.cpp:57
BT::BehaviorTreeFactory
The BehaviorTreeFactory is used to create instances of a TreeNode at run-time.
Definition: bt_factory.h:251
BT::Blackboard::create
static Blackboard::Ptr create(Blackboard::Ptr parent={})
Definition: blackboard.h:36
RefCountClass::refCount
int refCount() const
Definition: gtest_blackboard.cpp:257
BT::NodeStatus::SUCCESS
@ SUCCESS
BT::NodeConfiguration::blackboard
Blackboard::Ptr blackboard
Definition: tree_node.h:49
BB_TypedTestNode::BB_TypedTestNode
BB_TypedTestNode(const std::string &name, const NodeConfiguration &config)
Definition: gtest_blackboard.cpp:53
RefCountClass::operator=
RefCountClass & operator=(const RefCountClass &from)
Definition: gtest_blackboard.cpp:245
RefCountClass::~RefCountClass
virtual ~RefCountClass()
Definition: gtest_blackboard.cpp:252
BT::OutputPort
std::pair< std::string, PortInfo > OutputPort(StringView name, StringView description={})
Definition: basic_types.h:309
std
Definition: any.hpp:455
BT::BehaviorTreeFactory::registerBehaviorTreeFromText
void registerBehaviorTreeFromText(const std::string &xml_text)
Definition: bt_factory.cpp:228
BT::Tree::blackboard_stack
std::vector< Blackboard::Ptr > blackboard_stack
Definition: bt_factory.h:129
BB_TypedTestNode
Definition: gtest_blackboard.cpp:50
Point::y
double y
Definition: gtest_blackboard.cpp:299
Point::x
double x
Definition: gtest_blackboard.cpp:298
blackboard.h
BB_TestNode::tick
NodeStatus tick()
Method to be implemented by the user.
Definition: gtest_blackboard.cpp:28
xml_text
static const char * xml_text
Definition: ex01_wrap_legacy.cpp:52
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:35
BB_TestNode::providedPorts
static PortsList providedPorts()
Definition: gtest_blackboard.cpp:44


behaviortree_cpp_v3
Author(s): Michele Colledanchise, Davide Faconti
autogenerated on Wed Jun 26 2024 02:51:19