Skip to content

Commit d644f67

Browse files
committed
Add unit test for Any/Blackboard type casting
1 parent 6183340 commit d644f67

File tree

2 files changed

+190
-0
lines changed

2 files changed

+190
-0
lines changed

tests/gtest_any.cpp

Lines changed: 78 additions & 0 deletions
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

Lines changed: 112 additions & 0 deletions
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

@@ -854,3 +855,114 @@ TEST(BlackboardTest, SetBlackboard_WithPortRemapping)
854855
// Tick till the end with no crashes
855856
ASSERT_NO_THROW(tree.tickWhileRunning(););
856857
}
858+
859+
860+
class CreateHelloGreeter : public SyncActionNode
861+
{
862+
public:
863+
CreateHelloGreeter(const std::string& name, const NodeConfig& config)
864+
: SyncActionNode(name, config)
865+
{}
866+
867+
NodeStatus tick() override
868+
{
869+
auto hello_greeter = std::make_shared<HelloGreeter>();
870+
871+
setOutput("out_derived", hello_greeter);
872+
873+
return NodeStatus::SUCCESS;
874+
}
875+
876+
static PortsList providedPorts()
877+
{
878+
return { BT::OutputPort<HelloGreeter::Ptr>("out_derived") };
879+
}
880+
};
881+
882+
class SetDerivedParameter : public SyncActionNode
883+
{
884+
public:
885+
SetDerivedParameter(const std::string& name, const NodeConfig& config)
886+
: SyncActionNode(name, config)
887+
{}
888+
889+
NodeStatus tick() override
890+
{
891+
int n;
892+
HelloGreeter::Ptr hello_greeter{};
893+
894+
getInput("n", n);
895+
getInput("in_derived", hello_greeter);
896+
897+
hello_greeter->setDerivedParameter(n);
898+
hello_greeter->show_msg();
899+
900+
return NodeStatus::SUCCESS;
901+
}
902+
903+
static PortsList providedPorts()
904+
{
905+
return { BT::InputPort<int>("n"), BT::InputPort<HelloGreeter::Ptr>("in_derived") };
906+
}
907+
};
908+
909+
class ShowGreetMessage : public SyncActionNode
910+
{
911+
public:
912+
ShowGreetMessage(const std::string& name, const NodeConfig& config)
913+
: SyncActionNode(name, config)
914+
{}
915+
916+
NodeStatus tick() override
917+
{
918+
Greeter::Ptr greeter{};
919+
920+
getInput("in_base", greeter);
921+
greeter->show_msg();
922+
923+
return NodeStatus::SUCCESS;
924+
}
925+
926+
static PortsList providedPorts()
927+
{
928+
return { BT::InputPort<Greeter::Ptr>("in_base") };
929+
}
930+
};
931+
932+
TEST(BlackboardTest, Upcasting_Issue943)
933+
{
934+
auto bb = BT::Blackboard::create();
935+
936+
auto hello_greeter = std::make_shared<HelloGreeter>();
937+
bb->set("hello_greeter", hello_greeter);
938+
939+
std::shared_ptr<Greeter> g{};
940+
ASSERT_TRUE(bb->get("hello_greeter", g));
941+
ASSERT_STREQ("hello", g->show_msg().c_str());
942+
943+
std::shared_ptr<HelloGreeter> hg{};
944+
ASSERT_TRUE(bb->get("hello_greeter", hg));
945+
ASSERT_STREQ("hello", hg->show_msg().c_str());
946+
947+
std::string xml_txt = R"(
948+
<root BTCPP_format="4" >
949+
<BehaviorTree ID="Main">
950+
<Sequence>
951+
<CreateHelloGreeter out_derived="{hello_greeter}" />
952+
<SetDerivedParameter in_derived="{hello_greeter}" n="2" />
953+
<ShowGreetMessage in_base="{hello_greeter}" />
954+
</Sequence>
955+
</BehaviorTree>
956+
</root>)";
957+
958+
BehaviorTreeFactory factory;
959+
factory.registerNodeType<CreateHelloGreeter>("CreateHelloGreeter");
960+
factory.registerNodeType<SetDerivedParameter>("SetDerivedParameter");
961+
factory.registerNodeType<ShowGreetMessage>("ShowGreetMessage");
962+
963+
auto tree = factory.createTreeFromText(xml_txt);
964+
965+
NodeStatus status = tree.tickWhileRunning();
966+
967+
ASSERT_EQ(status, NodeStatus::SUCCESS);
968+
}

0 commit comments

Comments
 (0)