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