Skip to content

Commit f16e4f6

Browse files
committed
Add unit test for Any/Blackboard type casting
1 parent 4658964 commit f16e4f6

File tree

2 files changed

+190
-0
lines changed

2 files changed

+190
-0
lines changed

tests/gtest_any.cpp

+78
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include <gtest/gtest.h>
1818

1919
#include <behaviortree_cpp/utils/safe_any.hpp>
20+
#include "greeter_test.h"
2021

2122
using namespace BT;
2223

@@ -249,4 +250,81 @@ TEST(Any, Cast)
249250
Any a(v);
250251
EXPECT_EQ(a.cast<std::vector<int>>(), v);
251252
}
253+
254+
/// Issue 943
255+
// Type casting: polymorphic class w/ registered base class
256+
{
257+
auto g = std::make_shared<Greeter>();
258+
Any any_g(g);
259+
EXPECT_NO_THROW(auto res = any_g.cast<Greeter::Ptr>());
260+
EXPECT_ANY_THROW(auto res = any_g.cast<HelloGreeter::Ptr>());
261+
EXPECT_ANY_THROW(auto res = any_g.cast<FancyHelloGreeter::Ptr>());
262+
EXPECT_TRUE(any_g.castPtr<Greeter::Ptr>());
263+
EXPECT_FALSE(any_g.castPtr<HelloGreeter::Ptr>());
264+
EXPECT_FALSE(any_g.castPtr<FancyHelloGreeter::Ptr>());
265+
266+
auto hg = std::make_shared<HelloGreeter>();
267+
Any any_hg(hg);
268+
EXPECT_NO_THROW(auto res = any_hg.cast<Greeter::Ptr>());
269+
EXPECT_NO_THROW(auto res = any_hg.cast<HelloGreeter::Ptr>());
270+
EXPECT_ANY_THROW(auto res = any_hg.cast<FancyHelloGreeter::Ptr>());
271+
EXPECT_TRUE(any_hg.castPtr<Greeter::Ptr>());
272+
EXPECT_TRUE(any_hg.castPtr<HelloGreeter::Ptr>());
273+
EXPECT_FALSE(any_hg.castPtr<FancyHelloGreeter::Ptr>());
274+
275+
auto fhg = std::make_shared<FancyHelloGreeter>();
276+
Any any_fhg(fhg);
277+
EXPECT_NO_THROW(auto res = any_fhg.cast<Greeter::Ptr>());
278+
EXPECT_NO_THROW(auto res = any_fhg.cast<HelloGreeter::Ptr>());
279+
EXPECT_NO_THROW(auto res = any_fhg.cast<FancyHelloGreeter::Ptr>());
280+
EXPECT_TRUE(any_fhg.castPtr<Greeter::Ptr>());
281+
EXPECT_TRUE(any_fhg.castPtr<HelloGreeter::Ptr>());
282+
EXPECT_TRUE(any_fhg.castPtr<FancyHelloGreeter::Ptr>());
283+
284+
// Try to upcast to an incorrectly registered base
285+
auto u = std::make_shared<Unwelcomer>();
286+
287+
// OK, fails to compile -> invalid static cast
288+
// Any any_u(u);
289+
// EXPECT_ANY_THROW(auto res = any_g.cast<Unwelcomer::Ptr>());
290+
}
291+
292+
// Type casting: polymorphic class w/o registered base class
293+
{
294+
auto g = std::make_shared<GreeterNoReg>();
295+
Any any_g(g);
296+
EXPECT_NO_THROW(auto res = any_g.cast<GreeterNoReg::Ptr>());
297+
EXPECT_ANY_THROW(auto res = any_g.cast<HelloGreeterNoReg::Ptr>());
298+
EXPECT_TRUE(any_g.castPtr<GreeterNoReg::Ptr>());
299+
EXPECT_FALSE(any_g.castPtr<HelloGreeterNoReg::Ptr>());
300+
301+
auto hg = std::make_shared<HelloGreeterNoReg>();
302+
Any any_hg(hg);
303+
EXPECT_ANY_THROW(auto res = any_hg.cast<GreeterNoReg::Ptr>());
304+
EXPECT_NO_THROW(auto res = any_hg.cast<HelloGreeterNoReg::Ptr>());
305+
EXPECT_FALSE(any_hg.castPtr<GreeterNoReg::Ptr>());
306+
EXPECT_TRUE(any_hg.castPtr<HelloGreeterNoReg::Ptr>());
307+
}
308+
309+
// Type casting: non polymorphic class w/ registered base class
310+
{
311+
// OK: static_assert(std::is_polymorphic_v<Base>, "Base must be polymorphic")
312+
}
313+
314+
// Type casting: non polymorphic class w/o registered base class
315+
{
316+
auto g = std::make_shared<GreeterNoPolyReg>();
317+
Any any_g(g);
318+
EXPECT_NO_THROW(auto res = any_g.cast<GreeterNoPolyReg::Ptr>());
319+
EXPECT_ANY_THROW(auto res = any_g.cast<HelloGreeterNoPolyReg::Ptr>());
320+
EXPECT_TRUE(any_g.castPtr<GreeterNoPolyReg::Ptr>());
321+
EXPECT_FALSE(any_g.castPtr<HelloGreeterNoPolyReg::Ptr>());
322+
323+
auto hg = std::make_shared<HelloGreeterNoPolyReg>();
324+
Any any_hg(hg);
325+
EXPECT_ANY_THROW(auto res = any_hg.cast<GreeterNoPolyReg::Ptr>());
326+
EXPECT_NO_THROW(auto res = any_hg.cast<HelloGreeterNoPolyReg::Ptr>());
327+
EXPECT_FALSE(any_hg.castPtr<GreeterNoPolyReg::Ptr>());
328+
EXPECT_TRUE(any_hg.castPtr<HelloGreeterNoPolyReg::Ptr>());
329+
}
252330
}

tests/gtest_blackboard.cpp

+112
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include "behaviortree_cpp/blackboard.h"
1616

1717
#include "../sample_nodes/dummy_nodes.h"
18+
#include "greeter_test.h"
1819

1920
using namespace BT;
2021

@@ -654,3 +655,114 @@ TEST(BlackboardTest, TimestampedInterface)
654655
ASSERT_EQ(stamp_opt->seq, 2);
655656
ASSERT_GE(stamp_opt->time.count(), nsec_before);
656657
}
658+
659+
class CreateHelloGreeter : public SyncActionNode
660+
{
661+
public:
662+
CreateHelloGreeter(const std::string& name, const NodeConfig& config)
663+
: SyncActionNode(name, config)
664+
{}
665+
666+
NodeStatus tick() override
667+
{
668+
auto hello_greeter = std::make_shared<HelloGreeter>();
669+
670+
setOutput("out_derived", hello_greeter);
671+
672+
return NodeStatus::SUCCESS;
673+
}
674+
675+
static PortsList providedPorts()
676+
{
677+
return { BT::OutputPort<HelloGreeter::Ptr>("out_derived") };
678+
}
679+
};
680+
681+
class SetDerivedParameter : public SyncActionNode
682+
{
683+
public:
684+
SetDerivedParameter(const std::string& name, const NodeConfig& config)
685+
: SyncActionNode(name, config)
686+
{}
687+
688+
NodeStatus tick() override
689+
{
690+
int n;
691+
HelloGreeter::Ptr hello_greeter{};
692+
693+
getInput("n", n);
694+
getInput("in_derived", hello_greeter);
695+
696+
hello_greeter->setDerivedParameter(n);
697+
hello_greeter->show_msg();
698+
699+
return NodeStatus::SUCCESS;
700+
}
701+
702+
static PortsList providedPorts()
703+
{
704+
return { BT::InputPort<int>("n"), BT::InputPort<HelloGreeter::Ptr>("in_derived") };
705+
}
706+
};
707+
708+
class ShowGreetMessage : public SyncActionNode
709+
{
710+
public:
711+
ShowGreetMessage(const std::string& name, const NodeConfig& config)
712+
: SyncActionNode(name, config)
713+
{}
714+
715+
NodeStatus tick() override
716+
{
717+
Greeter::Ptr greeter{};
718+
719+
getInput("in_base", greeter);
720+
greeter->show_msg();
721+
722+
return NodeStatus::SUCCESS;
723+
}
724+
725+
static PortsList providedPorts()
726+
{
727+
return { BT::InputPort<Greeter::Ptr>("in_base") };
728+
}
729+
};
730+
731+
TEST(BlackboardTest, Upcasting_Issue943)
732+
{
733+
auto bb = BT::Blackboard::create();
734+
735+
auto hello_greeter = std::make_shared<HelloGreeter>();
736+
bb->set("hello_greeter", hello_greeter);
737+
738+
std::shared_ptr<Greeter> g{};
739+
std::shared_ptr<HelloGreeter> hg{};
740+
ASSERT_TRUE(bb->get("hello_greeter", g));
741+
g->show_msg();
742+
ASSERT_TRUE(bb->get("hello_greeter", hg));
743+
hg->show_msg();
744+
745+
746+
// 2nd
747+
std::string xml_txt = R"(
748+
<root BTCPP_format="4" >
749+
<BehaviorTree ID="Main">
750+
<Sequence>
751+
<CreateHelloGreeter out_derived="{hello_greeter}" />
752+
<SetDerivedParameter in_derived="{hello_greeter}" n="2" />
753+
<ShowGreetMessage in_base="{hello_greeter}" />
754+
</Sequence>
755+
</BehaviorTree>
756+
</root>)";
757+
758+
BehaviorTreeFactory factory;
759+
factory.registerNodeType<CreateHelloGreeter>("CreateHelloGreeter");
760+
factory.registerNodeType<SetDerivedParameter>("SetDerivedParameter");
761+
factory.registerNodeType<ShowGreetMessage>("ShowGreetMessage");
762+
763+
auto tree = factory.createTreeFromText(xml_txt);
764+
765+
NodeStatus status = tree.tickWhileRunning();
766+
767+
ASSERT_EQ(status, NodeStatus::SUCCESS);
768+
}

0 commit comments

Comments
 (0)