diff --git a/include/behaviortree_cpp/scripting/operators.hpp b/include/behaviortree_cpp/scripting/operators.hpp index 913c2a072..285b5fc3d 100644 --- a/include/behaviortree_cpp/scripting/operators.hpp +++ b/include/behaviortree_cpp/scripting/operators.hpp @@ -141,6 +141,18 @@ struct ExprUnaryArithmetic : ExprBase } else if(rhs_v.isString()) { + if(op == logical_not) + { + const auto str = rhs_v.cast(); + if(str == "true" || str == "True" || str == "TRUE" || str == "1") + { + return Any(0.0); + } + if(str == "false" || str == "False" || str == "FALSE" || str == "0") + { + return Any(1.0); + } + } throw RuntimeError("Invalid operator for std::string"); } throw RuntimeError("ExprUnaryArithmetic: undefined"); diff --git a/tests/gtest_subtree.cpp b/tests/gtest_subtree.cpp index cda5d68a8..82a0a23bb 100644 --- a/tests/gtest_subtree.cpp +++ b/tests/gtest_subtree.cpp @@ -1012,3 +1012,81 @@ TEST(SubTree, LiteralNumericPortsPreserveType) const auto status = tree.tickWhileRunning(); ASSERT_EQ(status, NodeStatus::SUCCESS); } + +// Regression test: logical NOT should accept literal boolean values passed to +// subtrees without changing their string representation in the blackboard. +TEST(SubTree, LiteralBooleanPortsSupportLogicalNot) +{ + // clang-format off + static const char* xml_text = R"( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +)"; + // clang-format on + + BehaviorTreeFactory factory; + auto tree = factory.createTreeFromText(xml_text); + tree.rootBlackboard()->set("enabled_numeric", std::string("1")); + tree.rootBlackboard()->set("disabled_numeric", std::string("0")); + + ASSERT_EQ(tree.tickWhileRunning(), NodeStatus::SUCCESS); + ASSERT_EQ(tree.subtrees[1]->blackboard->get("enabled"), "true"); + ASSERT_EQ(tree.subtrees[1]->blackboard->get("disabled"), "false"); + ASSERT_EQ(tree.subtrees[1]->blackboard->get("enabled_upper"), "TRUE"); + ASSERT_EQ(tree.subtrees[1]->blackboard->get("disabled_title"), "False"); +} + +TEST(SubTree, LiteralNonBooleanPortsRejectLogicalNot) +{ + // clang-format off + static const char* xml_text = R"( + + + + + + + + + + + +)"; + // clang-format on + + BehaviorTreeFactory factory; + auto tree = factory.createTreeFromText(xml_text); + + ASSERT_THROW((void)tree.tickWhileRunning(), RuntimeError); + ASSERT_EQ(tree.subtrees[1]->blackboard->get("value"), "1not_bool"); +}