Skip to content

Commit 1802926

Browse files
facontidavideclaude
andcommitted
Fix #982: handle json: prefix in vector convertFromString specializations
When a port of type std::vector<T> has a default empty value {} and no input is specified in XML, toStr() converts the empty vector to "json:[]". The explicit convertFromString specializations for vector types did not handle the "json:" prefix (unlike the generic template), so this string was split by ';' producing a vector with one literal "json:[]" element. Fix: add "json:" prefix detection at the top of all four vector convertFromString specializations (int, double, bool, string). When detected, parse directly with nlohmann::json instead of splitting by ';'. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent b3dbe30 commit 1802926

File tree

2 files changed

+77
-0
lines changed

2 files changed

+77
-0
lines changed

src/basic_types.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,11 @@ float convertFromString<float>(StringView str)
222222
template <>
223223
std::vector<int> convertFromString<std::vector<int>>(StringView str)
224224
{
225+
if(StartWith(str, "json:"))
226+
{
227+
str.remove_prefix(5);
228+
return nlohmann::json::parse(str).get<std::vector<int>>();
229+
}
225230
auto parts = splitString(str, ';');
226231
std::vector<int> output;
227232
output.reserve(parts.size());
@@ -235,6 +240,11 @@ std::vector<int> convertFromString<std::vector<int>>(StringView str)
235240
template <>
236241
std::vector<double> convertFromString<std::vector<double>>(StringView str)
237242
{
243+
if(StartWith(str, "json:"))
244+
{
245+
str.remove_prefix(5);
246+
return nlohmann::json::parse(str).get<std::vector<double>>();
247+
}
238248
auto parts = splitString(str, ';');
239249
std::vector<double> output;
240250
output.reserve(parts.size());
@@ -248,6 +258,11 @@ std::vector<double> convertFromString<std::vector<double>>(StringView str)
248258
template <>
249259
std::vector<bool> convertFromString<std::vector<bool>>(StringView str)
250260
{
261+
if(StartWith(str, "json:"))
262+
{
263+
str.remove_prefix(5);
264+
return nlohmann::json::parse(str).get<std::vector<bool>>();
265+
}
251266
auto parts = splitString(str, ';');
252267
std::vector<bool> output;
253268
output.reserve(parts.size());
@@ -261,6 +276,11 @@ std::vector<bool> convertFromString<std::vector<bool>>(StringView str)
261276
template <>
262277
std::vector<std::string> convertFromString<std::vector<std::string>>(StringView str)
263278
{
279+
if(StartWith(str, "json:"))
280+
{
281+
str.remove_prefix(5);
282+
return nlohmann::json::parse(str).get<std::vector<std::string>>();
283+
}
264284
auto parts = splitString(str, ';');
265285
std::vector<std::string> output;
266286
output.reserve(parts.size());

tests/gtest_ports.cpp

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -581,3 +581,60 @@ TEST(PortTest, DefaultWronglyOverriden)
581581
// This is correct
582582
ASSERT_NO_THROW(auto tree = factory.createTreeFromText(xml_txt_correct));
583583
}
584+
585+
// Issue #982: A port of type std::vector<std::string> with a default empty value {}
586+
// gets initialized with the literal string "json:[]" instead of being empty.
587+
// This happens because toStr() converts {} to "json:[]", and the vector
588+
// convertFromString specialization doesn't handle the "json:" prefix.
589+
class ActionWithDefaultEmptyVector : public SyncActionNode
590+
{
591+
public:
592+
ActionWithDefaultEmptyVector(const std::string& name, const NodeConfig& config,
593+
std::vector<std::string>* out_vec)
594+
: SyncActionNode(name, config), out_vec_(out_vec)
595+
{}
596+
597+
NodeStatus tick() override
598+
{
599+
if(!getInput("string_vector", *out_vec_))
600+
{
601+
return NodeStatus::FAILURE;
602+
}
603+
return NodeStatus::SUCCESS;
604+
}
605+
606+
static PortsList providedPorts()
607+
{
608+
return { BT::InputPort<std::vector<std::string>>("string_vector", {},
609+
"A string vector") };
610+
}
611+
612+
private:
613+
std::vector<std::string>* out_vec_;
614+
};
615+
616+
TEST(PortTest, DefaultEmptyVector_Issue982)
617+
{
618+
// Port has default value {} (empty vector) and no input specified in XML.
619+
// The vector should be empty, not contain "json:[]".
620+
std::string xml_txt = R"(
621+
<root BTCPP_format="4">
622+
<BehaviorTree ID="MainTree">
623+
<ActionWithDefaultEmptyVector />
624+
</BehaviorTree>
625+
</root>
626+
)";
627+
628+
std::vector<std::string> result;
629+
630+
BehaviorTreeFactory factory;
631+
factory.registerNodeType<ActionWithDefaultEmptyVector>("ActionWithDefaultEmptyVector",
632+
&result);
633+
auto tree = factory.createTreeFromText(xml_txt);
634+
auto status = tree.tickWhileRunning();
635+
636+
ASSERT_EQ(status, NodeStatus::SUCCESS);
637+
ASSERT_TRUE(result.empty()) << "Expected empty vector, but got " << result.size()
638+
<< " element(s). First element: \""
639+
<< (result.empty() ? "" : result[0]) << "\"";
640+
}

0 commit comments

Comments
 (0)