Skip to content

Commit 6c9929c

Browse files
committed
fixes and checks in default values, based on PR #773
1 parent 21ab495 commit 6c9929c

File tree

4 files changed

+96
-8
lines changed

4 files changed

+96
-8
lines changed

include/behaviortree_cpp/actions/script_node.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ class ScriptNode : public SyncActionNode
3131

3232
static PortsList providedPorts()
3333
{
34-
return {InputPort("code", "Piece of code that can be parsed")};
34+
return {InputPort<std::string>("code", "Piece of code that can be parsed")};
3535
}
3636

3737
private:

include/behaviortree_cpp/basic_types.h

+10-3
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,11 @@ using StringView = std::string_view;
6161
// vector of key/value pairs
6262
using KeyValueVector = std::vector<std::pair<std::string, std::string>>;
6363

64+
65+
struct AnyTypeAllowed
66+
{};
67+
68+
6469
/**
6570
* convertFromString is used to convert a string into a custom type.
6671
*
@@ -142,6 +147,11 @@ inline StringConverter GetAnyFromStringFunctor()
142147
{
143148
return [](StringView str) { return Any(str); };
144149
}
150+
else if constexpr(std::is_same_v<BT::AnyTypeAllowed, T> ||
151+
std::is_enum_v<T>)
152+
{
153+
return {};
154+
}
145155
else {
146156
return [](StringView str) { return Any(convertFromString<T>(str)); };
147157
}
@@ -265,9 +275,6 @@ using Result = Expected<std::monostate>;
265275
[[nodiscard]]
266276
bool IsAllowedPortName(StringView str);
267277

268-
struct AnyTypeAllowed
269-
{};
270-
271278
class TypeInfo
272279
{
273280
public:

src/xml_parsing.cpp

+35-3
Original file line numberDiff line numberDiff line change
@@ -636,7 +636,7 @@ TreeNode::Ptr XMLParser::PImpl::createNodeFromXML(const XMLElement* element,
636636

637637
const TreeNodeManifest* manifest = nullptr;
638638

639-
auto manifest_it = factory.manifests().find(type_ID);
639+
auto manifest_it = factory.manifests().find(type_ID);
640640
if(manifest_it != factory.manifests().end())
641641
{
642642
manifest = &manifest_it->second;
@@ -647,8 +647,40 @@ TreeNode::Ptr XMLParser::PImpl::createNodeFromXML(const XMLElement* element,
647647
{
648648
if (IsAllowedPortName(att->Name()))
649649
{
650-
const std::string attribute_name = att->Name();
651-
port_remap[attribute_name] = att->Value();
650+
const std::string port_name = att->Name();
651+
const std::string port_value = att->Value();
652+
653+
if(manifest)
654+
{
655+
auto port_model_it = manifest->ports.find(port_name);
656+
if(port_model_it == manifest->ports.end())
657+
{
658+
throw RuntimeError(StrCat("a port with name [", port_name,
659+
"] is found in the XML, but not in the providedPorts()"));
660+
}
661+
else {
662+
const auto& port_model = port_model_it->second;
663+
bool is_blacbkboard = port_value.size() >= 3 &&
664+
port_value.front() == '{' &&
665+
port_value.back() == '}';
666+
// let's test already if conversion is possible
667+
if(!is_blacbkboard && port_model.converter() && port_model.isStronglyTyped())
668+
{
669+
// This may throw
670+
try {
671+
port_model.converter()(port_value);
672+
}
673+
catch(std::exception& ex)
674+
{
675+
auto msg = StrCat("The port with name \"", port_name, "\" and value \"", port_value,
676+
"\" can not be converted to ", port_model.typeName());
677+
throw LogicError(msg);
678+
}
679+
}
680+
}
681+
}
682+
683+
port_remap[port_name] = port_value;
652684
}
653685
}
654686

tests/gtest_ports.cpp

+50-1
Original file line numberDiff line numberDiff line change
@@ -533,8 +533,32 @@ TEST(PortTest, DefaultInputStrings)
533533
ASSERT_EQ(status, NodeStatus::SUCCESS);
534534
}
535535

536+
struct TestStruct
537+
{
538+
int a;
539+
double b;
540+
std::string c;
541+
};
536542

537-
TEST(PortTest, Default_Issues_767_768)
543+
class NodeWithDefaultNullptr : public SyncActionNode
544+
{
545+
public:
546+
NodeWithDefaultNullptr(const std::string& name, const NodeConfig& config) :
547+
SyncActionNode(name, config) {}
548+
549+
NodeStatus tick() override
550+
{
551+
return NodeStatus::SUCCESS;
552+
}
553+
554+
static PortsList providedPorts()
555+
{
556+
return {BT::InputPort< std::shared_ptr<TestStruct> >("input", nullptr, "default value is nullptr")};
557+
}
558+
};
559+
560+
561+
TEST(PortTest, Default_Issues_767)
538562
{
539563
using namespace BT;
540564

@@ -545,4 +569,29 @@ TEST(PortTest, Default_Issues_767_768)
545569
ASSERT_NO_THROW(auto p = InputPort<std::shared_ptr<std::string>>("ptr_B", nullptr, "default nullptr"));
546570
}
547571

572+
TEST(PortTest, DefaultWronglyOverriden)
573+
{
574+
BT::BehaviorTreeFactory factory;
575+
factory.registerNodeType<NodeWithDefaultNullptr>("NodeWithDefaultNullptr");
576+
577+
std::string xml_txt_wrong = R"(
578+
<root BTCPP_format="4" >
579+
<BehaviorTree>
580+
<NodeWithDefaultNullptr input=""/>
581+
</BehaviorTree>
582+
</root>)";
583+
584+
std::string xml_txt_correct = R"(
585+
<root BTCPP_format="4" >
586+
<BehaviorTree>
587+
<NodeWithDefaultNullptr/>
588+
</BehaviorTree>
589+
</root>)";
548590

591+
// this should throw, because we are NOT using the default,
592+
// but overriding it with an empty string instead.
593+
// See issue 768 for reference
594+
ASSERT_ANY_THROW( auto tree = factory.createTreeFromText(xml_txt_wrong));
595+
// This is correct
596+
ASSERT_NO_THROW( auto tree = factory.createTreeFromText(xml_txt_correct));
597+
}

0 commit comments

Comments
 (0)