13 #include <gtest/gtest.h>
17 #include "../sample_nodes/dummy_nodes.h"
31 auto res = getInput<int>(
"in_port");
34 throw RuntimeError(
"BB_TestNode needs input: ", res.error());
36 value = res.value() * 2;
37 if(!setOutput(
"out_port", value))
46 return { BT::InputPort<int>(
"in_port"), BT::OutputPort<int>(
"out_port") };
65 BT::InputPort<int>(
"input_int"),
66 BT::InputPort<std::string>(
"input_string"),
69 BT::OutputPort<int>(
"output_int"),
70 BT::OutputPort<std::string>(
"output_string") };
74 TEST(BlackboardTest, GetInputsFromBlackboard)
79 assignDefaultRemapping<BB_TestNode>(config);
82 bb->set(
"in_port", 11);
89 ASSERT_EQ(bb->get<
int>(
"out_port"), 22);
92 TEST(BlackboardTest, BasicRemapping)
101 bb->set(
"my_input_port", 11);
106 ASSERT_EQ(bb->get<
int>(
"my_output_port"), 22);
109 TEST(BlackboardTest, GetInputsFromText)
125 ASSERT_EQ(bb->get<
int>(
"out_port"), 22);
128 TEST(BlackboardTest, SetOutputFromText)
132 <root BTCPP_format="4" >
133 <BehaviorTree ID="MainTree">
135 <BB_TestNode in_port="11" out_port="{my_port}"/>
136 <Script code="my_port=-43" />
151 TEST(BlackboardTest, WithFactory)
159 <root BTCPP_format="4" >
160 <BehaviorTree ID="MainTree">
162 <BB_TestNode in_port="11"
163 out_port="{my_input_port}"/>
165 <BB_TestNode in_port="{my_input_port}"
166 out_port="{my_input_port}" />
168 <BB_TestNode in_port="{my_input_port}"
169 out_port="{my_output_port}" />
180 ASSERT_EQ(bb->get<
int>(
"my_input_port"), 44);
181 ASSERT_EQ(bb->get<
int>(
"my_output_port"), 88);
184 TEST(BlackboardTest, TypoInPortName)
191 <root BTCPP_format="4" >
192 <BehaviorTree ID="MainTree">
193 <BB_TestNode inpuuuut_port="{value}" />
200 TEST(BlackboardTest, CheckPortType)
206 std::string good_one = R
"(
207 <root BTCPP_format="4" >
208 <BehaviorTree ID="MainTree">
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}" />
217 ASSERT_NE(tree.rootNode(),
nullptr);
219 std::string bad_one = R
"(
220 <root BTCPP_format="4" >
221 <BehaviorTree ID="MainTree">
223 <TypedNode name = "first" output_int="{value}" />
224 <TypedNode name = "second" input_string="{value}" />
237 std::cout <<
"Constructor: ref_count " << sptr_.use_count() << std::endl;
242 std::cout <<
"ctor copy: ref_count " << sptr_.use_count() << std::endl;
247 sptr_ = (from.
sptr_);
248 std::cout <<
"equal copied: ref_count " << sptr_.use_count() << std::endl;
254 std::cout << (
"Destructor") << std::endl;
259 return sptr_.use_count();
266 TEST(BlackboardTest, MoveVsCopy)
274 std::cout << (
"----- before set -----") << std::endl;
275 blackboard->set(
"testmove", test);
276 std::cout << (
" ----- after set -----") << std::endl;
285 TEST(BlackboardTest, CheckTypeSafety)
301 long* test_obj = &value;
303 blackboard->set(
"testmove", test_obj);
305 auto const timeout = std::chrono::milliseconds(250);
309 std::atomic_llong cycles = 0;
311 auto start = std::chrono::system_clock::now();
312 while((std::chrono::system_clock::now() - start) < timeout)
314 auto r1 = blackboard->getAnyLocked(
"testmove");
315 auto value_ptr = (r1.get()->cast<
long*>());
321 auto t1 = std::thread(func);
326 ASSERT_EQ(cycles, value);
331 std::atomic_llong cycles = 0;
333 auto start = std::chrono::system_clock::now();
334 while((std::chrono::system_clock::now() - start) < timeout)
336 auto value_ptr = blackboard->get<
long*>(
"testmove");
342 auto t1 = std::thread(func);
346 ASSERT_NE(cycles, value);
350 TEST(BlackboardTest, SetStringView)
355 bb->set(
"string_view", string_view_const);
357 ASSERT_NO_THROW(bb->set(
"string_view", string_view_const));
360 TEST(ParserTest, Issue605_whitespaces)
365 <root BTCPP_format="4" >
366 <BehaviorTree ID="MySubtree">
367 <Script code=" sub_value:=false " />
370 <BehaviorTree ID="MainTree">
372 <Script code=" my_value:=true " />
373 <SubTree ID="MySubtree" sub_value="{my_value} "/>
382 for(
auto const& subtree : tree.subtrees)
384 subtree->blackboard->debugMessage();
388 ASSERT_EQ(
false, tree.rootBlackboard()->get<
bool>(
"my_value"));
400 return { BT::InputPort<int32_t>(
"first"), BT::InputPort<int32_t>(
"second"),
401 BT::InputPort<std::string>(
"operator") };
406 int32_t firstValue = 0;
407 int32_t secondValue = 0;
408 std::string inputOperator;
409 if(!getInput(
"first", firstValue) || !getInput(
"second", secondValue) ||
410 !getInput(
"operator", inputOperator))
414 if((inputOperator ==
"==" && firstValue == secondValue) ||
415 (inputOperator ==
"!=" && firstValue != secondValue) ||
416 (inputOperator ==
"<=" && firstValue <= secondValue) ||
417 (inputOperator ==
">=" && firstValue >= secondValue) ||
418 (inputOperator ==
"<" && firstValue < secondValue) ||
419 (inputOperator ==
">" && firstValue > secondValue))
428 TEST(BlackboardTest, IssueSetBlackboard)
433 <root BTCPP_format="4" >
434 <BehaviorTree ID="MySubtree">
435 <ComparisonNode first="{value}" second="42" operator="==" />
438 <BehaviorTree ID="MainTree">
440 <SetBlackboard value="42" output_key="value" />
441 <SubTree ID="MySubtree" value="{value} "/>
452 ASSERT_EQ(42, tree.rootBlackboard()->get<
int>(
"value"));
469 if(parts.size() != 2)
475 Point output{ 0.0, 0.0 };
484 TEST(BlackboardTest, SetBlackboard_Issue725)
489 <root BTCPP_format="4">
490 <BehaviorTree ID="MainTree">
491 <SetBlackboard value="{first_point}" output_key="other_point" />
498 auto& blackboard = tree.
subtrees.front()->blackboard;
500 const Point point = { 2, 7 };
501 blackboard->set(
"first_point", point);
503 const auto status = tree.tickOnce();
505 Point other_point = blackboard->get<
Point>(
"other_point");
508 ASSERT_EQ(other_point.
x, point.
x);
509 ASSERT_EQ(other_point.
y, point.
y);
512 TEST(BlackboardTest, NullOutputRemapping)
521 bb->set(
"my_input_port", 11);
534 <root BTCPP_format="4" >
535 <BehaviorTree ID="MySubtree">
537 <Script code=" important_value:= sub_value " />
538 <Script code=" my_value=false " />
539 <SaySomething message="{message}" />
542 <BehaviorTree ID="MainTree">
544 <Script code=" my_value:=true; another_value:='hi' " />
545 <SubTree ID="MySubtree" sub_value="true" message="{another_value}" _autoremap="true" />
557 std::vector<std::vector<std::string>> expected_keys;
558 for(
const auto& sub : tree.subtrees)
560 std::vector<std::string> keys;
561 for(
const auto& str_view : sub->blackboard->getKeys())
563 keys.push_back(std::string(str_view));
565 expected_keys.push_back(keys);
568 auto status = tree.tickWhileRunning();
573 ASSERT_EQ(bb_backup.size(), tree.subtrees.size());
576 for(
size_t i = 0; i < tree.subtrees.size(); i++)
578 const auto keys = tree.subtrees[i]->blackboard->getKeys();
579 ASSERT_EQ(expected_keys[i].
size(), keys.size());
580 for(
size_t a = 0; a < keys.size(); a++)
582 ASSERT_EQ(expected_keys[i][a], keys[a]);
585 status = tree.tickWhileRunning();
589 TEST(BlackboardTest, RootBlackboard)
594 <root BTCPP_format="4" >
595 <BehaviorTree ID="SubA">
597 <SubTree ID="SubB" />
598 <Script code=" @var3:=3 " />
602 <BehaviorTree ID="SubB">
604 <SaySomething message="{@msg}" />
605 <Script code=" @var4:=4 " />
609 <BehaviorTree ID="Sub_Issue823">
610 <BB_TestNode in_port="2" out_port="{@var5}" />
613 <BehaviorTree ID="MainTree">
615 <Script code=" msg:='hello' " />
616 <SubTree ID="SubA" />
618 <Script code="@var5:=0" />
619 <SubTree ID="Sub_Issue823" />
621 <Script code=" var1:=1 " />
622 <Script code=" @var2:=2 " />
635 ASSERT_EQ(1, tree.rootBlackboard()->get<
int>(
"var1"));
636 ASSERT_EQ(2, tree.rootBlackboard()->get<
int>(
"var2"));
637 ASSERT_EQ(3, tree.rootBlackboard()->get<
int>(
"var3"));
638 ASSERT_EQ(4, tree.rootBlackboard()->get<
int>(
"var4"));
639 ASSERT_EQ(4, tree.rootBlackboard()->get<
int>(
"var5"));
642 TEST(BlackboardTest, TimestampedInterface)
648 ASSERT_FALSE(bb->getStamped<
int>(
"value"));
649 ASSERT_FALSE(bb->getStamped(
"value", value));
651 auto nsec_before = std::chrono::steady_clock::now().time_since_epoch().count();
652 bb->set(
"value", 42);
653 auto result = bb->getStamped<
int>(
"value");
654 auto stamp_opt = bb->getStamped<
int>(
"value", value);
656 ASSERT_EQ(result->value, 42);
657 ASSERT_EQ(result->stamp.seq, 1);
658 ASSERT_GE(result->stamp.time.count(), nsec_before);
660 ASSERT_EQ(value, 42);
661 ASSERT_TRUE(stamp_opt);
662 ASSERT_EQ(stamp_opt->seq, 1);
663 ASSERT_GE(stamp_opt->time.count(), nsec_before);
666 nsec_before = std::chrono::steady_clock::now().time_since_epoch().count();
667 bb->set(
"value", 69);
668 result = bb->getStamped<
int>(
"value");
669 stamp_opt = bb->getStamped<
int>(
"value", value);
671 ASSERT_EQ(result->value, 69);
672 ASSERT_EQ(result->stamp.seq, 2);
673 ASSERT_GE(result->stamp.time.count(), nsec_before);
675 ASSERT_EQ(value, 69);
676 ASSERT_TRUE(stamp_opt);
677 ASSERT_EQ(stamp_opt->seq, 2);
678 ASSERT_GE(stamp_opt->time.count(), nsec_before);
681 TEST(BlackboardTest, SetBlackboard_Upd_Ts_SeqId)
686 <root BTCPP_format="4">
687 <BehaviorTree ID="MainTree">
689 <Script code="other_point:=first_point" />
691 <SetBlackboard value="{second_point}" output_key="other_point" />
698 auto& blackboard = tree.
subtrees.front()->blackboard;
700 const Point point1 = { 2, 2 };
701 const Point point2 = { 3, 3 };
702 blackboard->set(
"first_point", point1);
703 blackboard->set(
"second_point", point2);
705 tree.tickExactlyOnce();
706 const auto entry_ptr = blackboard->getEntry(
"other_point");
707 const auto ts1 = entry_ptr->stamp;
708 const auto seq_id1 = entry_ptr->sequence_id;
709 tree.tickWhileRunning();
710 const auto ts2 = entry_ptr->stamp;
711 const auto seq_id2 = entry_ptr->sequence_id;
713 ASSERT_GT(ts2.count(), ts1.count());
714 ASSERT_GT(seq_id2, seq_id1);
717 TEST(BlackboardTest, SetBlackboard_ChangeType1)
722 <root BTCPP_format="4">
723 <BehaviorTree ID="MainTree">
725 <SetBlackboard value="{first_point}" output_key="other_point" />
727 <SetBlackboard value="{random_str}" output_key="other_point" />
734 auto& blackboard = tree.
subtrees.front()->blackboard;
736 const Point point = { 2, 7 };
737 blackboard->set(
"first_point", point);
738 blackboard->set(
"random_str",
"Hello!");
741 ASSERT_NO_THROW(tree.tickExactlyOnce());
742 const auto entry_ptr = blackboard->getEntry(
"other_point");
743 std::this_thread::sleep_for(std::chrono::milliseconds{ 5 });
748 TEST(BlackboardTest, SetBlackboard_ChangeType2)
753 <root BTCPP_format="4">
754 <BehaviorTree ID="MainTree">
756 <SetBlackboard value="{first_point}" output_key="other_point" />
758 <SetBlackboard value="{random_num}" output_key="other_point" />
765 auto& blackboard = tree.
subtrees.front()->blackboard;
767 const Point point = { 2, 7 };
768 blackboard->set(
"first_point", point);
769 blackboard->set(
"random_num", 57);
772 ASSERT_NO_THROW(tree.tickExactlyOnce());
773 const auto entry_ptr = blackboard->getEntry(
"other_point");
774 std::this_thread::sleep_for(std::chrono::milliseconds{ 5 });
789 const auto in_pos = getInput<Point>(
"pos_in");
790 if(!in_pos.has_value())
792 Point _pos = in_pos.value();
793 _pos.
x += getInput<double>(
"x").value_or(0.0);
794 _pos.
y += getInput<double>(
"y").value_or(0.0);
795 setOutput(
"pos_out", _pos);
801 return { BT::InputPort<Point>(
"pos_in", { 0.0, 0.0 },
"Initial position"),
802 BT::InputPort<double>(
"x"), BT::InputPort<double>(
"y"),
803 BT::OutputPort<Point>(
"pos_out") };
809 TEST(BlackboardTest, SetBlackboard_WithPortRemapping)
814 <?xml version="1.0"?>
815 <root BTCPP_format="4" main_tree_to_execute="MainTree">
816 <BehaviorTree ID="MainTree">
818 <SetBlackboard output_key="pos" value="0.0;0.0" />
819 <Repeat num_cycles="3">
821 <UpdatePosition pos_in="{pos}" x="0.1" y="0.2" pos_out="{pos}"/>
822 <SubTree ID="UpdPosPlus" _autoremap="true" new_pos="2.2;2.4" />
824 <SetBlackboard output_key="pos" value="22.0;22.0" />
829 <BehaviorTree ID="UpdPosPlus">
831 <SetBlackboard output_key="pos" value="3.0;5.0" />
832 <SetBlackboard output_key="pos" value="{new_pos}" />
841 auto& blackboard = tree.
subtrees.front()->blackboard;
844 ASSERT_NO_THROW(tree.tickExactlyOnce());
846 const auto entry_ptr = blackboard->getEntry(
"pos");
847 ASSERT_EQ(entry_ptr->value.type(),
typeid(
Point));
849 const auto x = entry_ptr->value.cast<
Point>().x;
850 const auto y = entry_ptr->value.cast<
Point>().y;
855 ASSERT_NO_THROW(tree.tickWhileRunning(););