@@ -856,7 +856,6 @@ TEST(BlackboardTest, SetBlackboard_WithPortRemapping)
856
856
ASSERT_NO_THROW (tree.tickWhileRunning (););
857
857
}
858
858
859
-
860
859
class CreateHelloGreeter : public SyncActionNode
861
860
{
862
861
public:
@@ -929,22 +928,68 @@ class ShowGreetMessage : public SyncActionNode
929
928
}
930
929
};
931
930
932
- TEST (BlackboardTest, Upcasting_Issue943)
931
+ class ShowFancyGreetMessage : public SyncActionNode
933
932
{
934
- auto bb = BT::Blackboard::create ();
933
+ public:
934
+ ShowFancyGreetMessage (const std::string& name, const NodeConfig& config)
935
+ : SyncActionNode(name, config)
936
+ {}
935
937
936
- auto hello_greeter = std::make_shared<HelloGreeter>();
937
- bb->set (" hello_greeter" , hello_greeter);
938
+ NodeStatus tick () override
939
+ {
940
+ FancyHelloGreeter::Ptr greeter{};
941
+
942
+ getInput (" in_invalid_derived" , greeter);
943
+ if (!greeter)
944
+ return NodeStatus::FAILURE;
938
945
939
- std::shared_ptr<Greeter> g{};
940
- ASSERT_TRUE (bb->get (" hello_greeter" , g));
941
- ASSERT_STREQ (" hello" , g->show_msg ().c_str ());
946
+ greeter->show_msg ();
942
947
943
- std::shared_ptr<HelloGreeter> hg{};
944
- ASSERT_TRUE (bb->get (" hello_greeter" , hg));
945
- ASSERT_STREQ (" hello" , hg->show_msg ().c_str ());
948
+ return NodeStatus::SUCCESS;
949
+ }
946
950
947
- std::string xml_txt = R"(
951
+ static PortsList providedPorts ()
952
+ {
953
+ return { BT::InputPort<FancyHelloGreeter::Ptr>(" in_invalid_derived" ) };
954
+ }
955
+ };
956
+
957
+ TEST (BlackboardTest, Upcasting_Issue943)
958
+ {
959
+ {
960
+ auto bb = BT::Blackboard::create ();
961
+
962
+ // set hello_greeter
963
+ auto hello_greeter = std::make_shared<HelloGreeter>();
964
+ bb->set (" hello_greeter" , hello_greeter);
965
+
966
+ // retrieve as base class -> OK
967
+ std::shared_ptr<Greeter> g{};
968
+ ASSERT_TRUE (bb->get (" hello_greeter" , g));
969
+ ASSERT_STREQ (" hello" , g->show_msg ().c_str ());
970
+
971
+ // retrieve as derived class -> OK
972
+ std::shared_ptr<HelloGreeter> hg{};
973
+ ASSERT_TRUE (bb->get (" hello_greeter" , hg));
974
+ ASSERT_STREQ (" hello" , hg->show_msg ().c_str ());
975
+
976
+ // retrieve as most-derived class -> should throw (type mismatch)
977
+ std::shared_ptr<FancyHelloGreeter> fhg{};
978
+ std::cout << " D" << std::endl;
979
+ ASSERT_ANY_THROW (auto rc = bb->get (" hello_greeter" , fhg));
980
+
981
+ // overwrite hello_greeter bb key
982
+ ASSERT_ANY_THROW (bb->set (" hello_greeter" , g));
983
+ ASSERT_NO_THROW (bb->set (" hello_greeter" , hg));
984
+ ASSERT_ANY_THROW (bb->set (" hello_greeter" , fhg));
985
+ }
986
+
987
+ // This test verifies that polymorphic upcasting works correctly during tree creation.
988
+ // The port "hello_greeter" is produced as HelloGreeter and later consumed as both
989
+ // HelloGreeter and its base type Greeter. The tree should execute successfully,
990
+ // confirming safe polymorphic compatibility through the base_chain mechanism.
991
+ {
992
+ std::string xml_txt = R"(
948
993
<root BTCPP_format="4" >
949
994
<BehaviorTree ID="Main">
950
995
<Sequence>
@@ -955,14 +1000,59 @@ TEST(BlackboardTest, Upcasting_Issue943)
955
1000
</BehaviorTree>
956
1001
</root>)" ;
957
1002
958
- BehaviorTreeFactory factory;
959
- factory.registerNodeType <CreateHelloGreeter>(" CreateHelloGreeter" );
960
- factory.registerNodeType <SetDerivedParameter>(" SetDerivedParameter" );
961
- factory.registerNodeType <ShowGreetMessage>(" ShowGreetMessage" );
1003
+ BehaviorTreeFactory factory;
1004
+ factory.registerNodeType <CreateHelloGreeter>(" CreateHelloGreeter" );
1005
+ factory.registerNodeType <SetDerivedParameter>(" SetDerivedParameter" );
1006
+ factory.registerNodeType <ShowGreetMessage>(" ShowGreetMessage" );
962
1007
963
- auto tree = factory.createTreeFromText (xml_txt);
1008
+ auto tree = factory.createTreeFromText (xml_txt);
964
1009
965
- NodeStatus status = tree.tickWhileRunning ();
1010
+ NodeStatus status = tree.tickWhileRunning ();
966
1011
967
- ASSERT_EQ (status, NodeStatus::SUCCESS);
1012
+ ASSERT_EQ (status, NodeStatus::SUCCESS);
1013
+ }
1014
+
1015
+ // This test ensures that an invalid polymorphic downcast is correctly detected
1016
+ // during tree creation. The port "hello_greeter" is first created with HelloGreeter,
1017
+ // then later expected as FancyHelloGreeter (a more derived type), which fails.
1018
+ {
1019
+ std::string xml_txt = R"(
1020
+ <root BTCPP_format="4" >
1021
+ <BehaviorTree ID="Main">
1022
+ <Sequence>
1023
+ <Script code="test := false"/>
1024
+ <CreateHelloGreeter out_derived="{hello_greeter}" />
1025
+ <SetDerivedParameter in_derived="{hello_greeter}" n="2" />
1026
+ <ShowGreetMessage in_base="{hello_greeter}" />
1027
+ <ShowFancyGreetMessage in_invalid_derived="{hello_greeter}" />
1028
+ </Sequence>
1029
+ </BehaviorTree>
1030
+ </root>)" ;
1031
+
1032
+ BehaviorTreeFactory factory;
1033
+ factory.registerNodeType <CreateHelloGreeter>(" CreateHelloGreeter" );
1034
+ factory.registerNodeType <SetDerivedParameter>(" SetDerivedParameter" );
1035
+ factory.registerNodeType <ShowGreetMessage>(" ShowGreetMessage" );
1036
+ factory.registerNodeType <ShowFancyGreetMessage>(" ShowFancyGreetMessage" );
1037
+
1038
+ try
1039
+ {
1040
+ auto tree = factory.createTreeFromText (xml_txt);
1041
+ FAIL () << " Expected BT::RuntimeError to be thrown" ;
1042
+ }
1043
+ catch (const BT::RuntimeError& e)
1044
+ {
1045
+ std::string expected_msg = " The creation of the tree failed because the port "
1046
+ " [hello_greeter] was initially "
1047
+ " created with type [std::shared_ptr<HelloGreeter>] and, "
1048
+ " later type "
1049
+ " [std::shared_ptr<FancyHelloGreeter>] was used "
1050
+ " somewhere else." ;
1051
+ ASSERT_EQ (e.what (), expected_msg);
1052
+ }
1053
+ catch (...)
1054
+ {
1055
+ FAIL () << " Expected BT::RuntimeError but caught a different exception" ;
1056
+ }
1057
+ }
968
1058
}
0 commit comments