Skip to content

Commit e6e7241

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 8c784dd commit e6e7241

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
@@ -665,3 +665,60 @@ TEST(PortTest, LoopNodeAcceptsVector_Issue969)
665665
EXPECT_DOUBLE_EQ(collected[1], 20.0);
666666
EXPECT_DOUBLE_EQ(collected[2], 30.0);
667667
}
668+
669+
// Issue #982: A port of type std::vector<std::string> with a default empty value {}
670+
// gets initialized with the literal string "json:[]" instead of being empty.
671+
// This happens because toStr() converts {} to "json:[]", and the vector
672+
// convertFromString specialization doesn't handle the "json:" prefix.
673+
class ActionWithDefaultEmptyVector : public SyncActionNode
674+
{
675+
public:
676+
ActionWithDefaultEmptyVector(const std::string& name, const NodeConfig& config,
677+
std::vector<std::string>* out_vec)
678+
: SyncActionNode(name, config), out_vec_(out_vec)
679+
{}
680+
681+
NodeStatus tick() override
682+
{
683+
if(!getInput("string_vector", *out_vec_))
684+
{
685+
return NodeStatus::FAILURE;
686+
}
687+
return NodeStatus::SUCCESS;
688+
}
689+
690+
static PortsList providedPorts()
691+
{
692+
return { BT::InputPort<std::vector<std::string>>("string_vector", {},
693+
"A string vector") };
694+
}
695+
696+
private:
697+
std::vector<std::string>* out_vec_;
698+
};
699+
700+
TEST(PortTest, DefaultEmptyVector_Issue982)
701+
{
702+
// Port has default value {} (empty vector) and no input specified in XML.
703+
// The vector should be empty, not contain "json:[]".
704+
std::string xml_txt = R"(
705+
<root BTCPP_format="4">
706+
<BehaviorTree ID="MainTree">
707+
<ActionWithDefaultEmptyVector />
708+
</BehaviorTree>
709+
</root>
710+
)";
711+
712+
std::vector<std::string> result;
713+
714+
BehaviorTreeFactory factory;
715+
factory.registerNodeType<ActionWithDefaultEmptyVector>("ActionWithDefaultEmptyVector",
716+
&result);
717+
auto tree = factory.createTreeFromText(xml_txt);
718+
auto status = tree.tickWhileRunning();
719+
720+
ASSERT_EQ(status, NodeStatus::SUCCESS);
721+
ASSERT_TRUE(result.empty()) << "Expected empty vector, but got " << result.size()
722+
<< " element(s). First element: \""
723+
<< (result.empty() ? "" : result[0]) << "\"";
724+
}

0 commit comments

Comments
 (0)