diff --git a/src/xml_parsing.cpp b/src/xml_parsing.cpp index 15a045713..de0732142 100644 --- a/src/xml_parsing.cpp +++ b/src/xml_parsing.cpp @@ -789,7 +789,7 @@ TreeNode::Ptr XMLParser::PImpl::createNodeFromXML(const XMLElement* element, if(it == port_remap.end() && !do_autoremap) { // remapping is not explicitly defined in the XML: use the model - if(port_info.defaultValueString().empty()) + if(port_info.defaultValue().empty()) { auto msg = StrCat("In the the is defining a mandatory port called [", port_name, diff --git a/tests/gtest_subtree.cpp b/tests/gtest_subtree.cpp index 0bf48f8ae..29f5b01a3 100644 --- a/tests/gtest_subtree.cpp +++ b/tests/gtest_subtree.cpp @@ -732,6 +732,62 @@ TEST(SubTree, WhitespaceInSubtreeModel) FAIL() << "Exception was not thrown."; } +TEST(SubTree, EmptyModelDefaultIsNotMandatory) +{ + struct TestCase + { + const char* name; + const char* port_model; + const char* invocation_attributes; + const char* expected_value; + bool should_build; + }; + + const TestCase test_cases[] = { + { "empty default, not remapped", R"()", "", "", + true }, + { "empty default, explicitly empty", R"()", + R"( note="")", "", true }, + { "non-empty default, not remapped", + R"()", "", "something", true }, + { "no default, not remapped", R"()", "", "", false }, + }; + + for(const auto& test_case : test_cases) + { + const auto xml_text = StrCat( + R"( + + )", + test_case.port_model, + R"( + + + + + + + +)"); + + BehaviorTreeFactory factory; + if(test_case.should_build) + { + Tree tree; + ASSERT_NO_THROW(tree = factory.createTreeFromText(xml_text)) << test_case.name; + EXPECT_EQ(tree.tickWhileRunning(), NodeStatus::SUCCESS) << test_case.name; + } + else + { + EXPECT_THROW(factory.createTreeFromText(xml_text), RuntimeError) << test_case.name; + } + } +} + class PrintToConsole : public BT::SyncActionNode { public: