Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 21 additions & 1 deletion src/json_export.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#include "behaviortree_cpp/json_export.h"

#include <limits>

namespace BT
{

Expand Down Expand Up @@ -72,9 +74,27 @@ JsonExporter::ExpectedEntry JsonExporter::fromJson(const nlohmann::json& source)
return Entry{ BT::Any(source.get<std::string>()),
BT::TypeInfo::Create<std::string>() };
}
// get<int>() silently wraps any value outside the int range, so keep the
// width when the number doesn't fit. This lets an int64_t/uint64_t entry
// survive an export/import round-trip instead of coming back truncated.
if(source.is_number_unsigned())
{
const uint64_t value = source.get<uint64_t>();
if(value <= static_cast<uint64_t>(std::numeric_limits<int>::max()))
{
return Entry{ BT::Any(static_cast<int>(value)), BT::TypeInfo::Create<int>() };
}
return Entry{ BT::Any(value), BT::TypeInfo::Create<uint64_t>() };
}
if(source.is_number_integer())
{
return Entry{ BT::Any(source.get<int>()), BT::TypeInfo::Create<int>() };
const int64_t value = source.get<int64_t>();
if(value >= static_cast<int64_t>(std::numeric_limits<int>::min()) &&
value <= static_cast<int64_t>(std::numeric_limits<int>::max()))
{
return Entry{ BT::Any(static_cast<int>(value)), BT::TypeInfo::Create<int>() };
}
return Entry{ BT::Any(value), BT::TypeInfo::Create<int64_t>() };
}
if(source.is_number_float())
{
Expand Down
36 changes: 36 additions & 0 deletions tests/gtest_json.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,42 @@ TEST_F(JsonTest, BlackboardInOut)
ASSERT_EQ(vect_out.z, 3.3);
}

TEST_F(JsonTest, LargeIntegerPreserved)
{
BT::JsonExporter& exporter = BT::JsonExporter::get();

// Values outside the int32 range used to be silently wrapped by get<int>().
{
auto json = nlohmann::json::parse(R"({"a": 2147483648, "b": 5000000000,
"c": 4294967296})");
auto bb = BT::Blackboard::create();
ImportBlackboardFromJSON(json, *bb);
ASSERT_EQ(bb->get<int64_t>("a"), 2147483648LL);
ASSERT_EQ(bb->get<int64_t>("b"), 5000000000LL);
ASSERT_EQ(bb->get<int64_t>("c"), 4294967296LL);
}
// Negative values below the int32 minimum are preserved too.
{
auto res = exporter.fromJson(nlohmann::json(int64_t(-5000000000LL)));
ASSERT_TRUE(res) << res.error();
ASSERT_EQ(res->first.cast<int64_t>(), -5000000000LL);
}
// Values that fit keep the int type, unchanged from before.
{
auto res = exporter.fromJson(nlohmann::json(100));
ASSERT_TRUE(res) << res.error();
ASSERT_EQ(res->first.cast<int>(), 100);
}
// An int64_t entry survives an Export/Import round-trip.
{
auto bb_in = BT::Blackboard::create();
bb_in->set("big", int64_t(5000000000LL));
auto bb_out = BT::Blackboard::create();
ImportBlackboardFromJSON(ExportBlackboardToJSON(*bb_in), *bb_out);
ASSERT_EQ(bb_out->get<int64_t>("big"), 5000000000LL);
}
}

TEST_F(JsonTest, VectorInteger)
{
BT::JsonExporter& exporter = BT::JsonExporter::get();
Expand Down
Loading