Skip to content

Commit

Permalink
test moved and port remapping fixed
Browse files Browse the repository at this point in the history
  • Loading branch information
facontidavide committed Mar 9, 2024
1 parent 11aebe7 commit 0a3393c
Show file tree
Hide file tree
Showing 3 changed files with 129 additions and 68 deletions.
24 changes: 14 additions & 10 deletions src/xml_parsing.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -881,15 +881,19 @@ void BT::XMLParser::PImpl::recursivelyCreateSubtree(const std::string& tree_ID,
{
auto new_bb = Blackboard::create(blackboard);
const std::string subtree_ID = element->Attribute("ID");
std::unordered_map<std::string, std::string> remapping;
std::unordered_map<std::string, std::string> subtree_remapping;
bool do_autoremap = false;

for(auto attr = element->FirstAttribute(); attr != nullptr; attr = attr->Next())
{
const char* attr_name = attr->Name();
const char* attr_value = attr->Value();
std::string attr_name = attr->Name();
std::string attr_value = attr->Value();
if(attr_value == "{=}")
{
attr_value = StrCat("{", attr_name, "}");
}

if(StrEqual(attr_name, "_autoremap"))
if(attr_name == "_autoremap")
{
do_autoremap = convertFromString<bool>(attr_value);
new_bb->enableAutoRemapping(do_autoremap);
Expand All @@ -899,10 +903,10 @@ void BT::XMLParser::PImpl::recursivelyCreateSubtree(const std::string& tree_ID,
{
continue;
}
remapping.insert({ attr_name, attr_value });
subtree_remapping.insert({ attr_name, attr_value });
}
// check if this subtree has a model. If it does,
// we want o check if all the mandatory ports were remapped and
// we want to check if all the mandatory ports were remapped and
// add default ones, if necessary
auto subtree_model_it = subtree_models.find(subtree_ID);
if(subtree_model_it != subtree_models.end())
Expand All @@ -913,9 +917,9 @@ void BT::XMLParser::PImpl::recursivelyCreateSubtree(const std::string& tree_ID,
// - if any of these has default value
for(const auto& [port_name, port_info] : subtree_model_ports)
{
auto it = remapping.find(port_name);
auto it = subtree_remapping.find(port_name);
// don't override existing remapping
if(it == remapping.end() && !do_autoremap)
if(it == subtree_remapping.end() && !do_autoremap)
{
// remapping is not explicitly defined in the XML: use the model
if(port_info.defaultValueString().empty())
Expand All @@ -927,13 +931,13 @@ void BT::XMLParser::PImpl::recursivelyCreateSubtree(const std::string& tree_ID,
}
else
{
remapping.insert({ port_name, port_info.defaultValueString() });
subtree_remapping.insert({ port_name, port_info.defaultValueString() });
}
}
}
}

for(const auto& [attr_name, attr_value] : remapping)
for(const auto& [attr_name, attr_value] : subtree_remapping)
{
if(TreeNode::isBlackboardPointer(attr_value))
{
Expand Down
115 changes: 115 additions & 0 deletions tests/gtest_enums.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -124,3 +124,118 @@ TEST(Enums, SwitchNodeWithEnum)

ASSERT_EQ(status, NodeStatus::SUCCESS);
}

enum BatteryStatus
{
NO_FAULT = 0,
LOW_BATTERY = 1
};

class PrintEnum : public BT::ConditionNode
{
public:
explicit PrintEnum(const std::string& name, const BT::NodeConfig& config)
: ConditionNode(name, config)
{}

~PrintEnum() override = default;

static BT::PortsList providedPorts()
{
return {
BT::InputPort<BatteryStatus>("enum", "Name of the check"),
};
}

private:
BT::NodeStatus tick() override
{
auto enum_value = getInput<BatteryStatus>("enum");
if(!enum_value)
{
std::cout << "missing required input [enum]" << std::endl;
return BT::NodeStatus::FAILURE;
}
std::cout << "Enum value: " << (enum_value == NO_FAULT ? "NO_FAULT" : "LOW_BATTERY")
<< std::endl;
return BT::NodeStatus::SUCCESS;
}
};

class IsHealthOk : public BT::ConditionNode
{
public:
explicit IsHealthOk(const std::string& name, const BT::NodeConfig& config)
: BT::ConditionNode(name, config)
{}

~IsHealthOk() override = default;

static BT::PortsList providedPorts()
{
return { BT::InputPort<std::string>("check_name"), BT::InputPort<bool>("health") };
}

private:
BT::NodeStatus tick() override
{
auto health = getInput<bool>("health");
if(!health)
{
std::cout << "missing required input [health]" << std::endl;
return BT::NodeStatus::FAILURE;
}

if(health.value())
{
return BT::NodeStatus::SUCCESS;
}
else
{
std::cerr << "IsHealthOk FAILED " << std::endl;
return BT::NodeStatus::FAILURE;
}
return BT::NodeStatus::SUCCESS;
}
};

TEST(Enums, SubtreeRemapping)
{
const std::string xml_txt = R"(
<root BTCPP_format="4" >
<BehaviorTree ID="MainTree">
<Sequence>
<Script code=" fault_status := NO_FAULT " />
<PrintEnum enum="{fault_status}"/>
<SubTree ID="FailsafeCheck"
health="false"
trigger_fault_status="LOW_BATTERY"
fault_status="{=}" />
<PrintEnum enum="{fault_status}"/>
</Sequence>
</BehaviorTree>
<BehaviorTree ID="FailsafeCheck">
<ForceSuccess>
<IsHealthOk
health="{health}"
_onFailure="fault_status = trigger_fault_status"/>
</ForceSuccess>
</BehaviorTree>
</root>)";

BehaviorTreeFactory factory;
factory.registerScriptingEnums<BatteryStatus>();
factory.registerNodeType<PrintEnum>("PrintEnum");
factory.registerNodeType<IsHealthOk>("IsHealthOk");

factory.registerBehaviorTreeFromText(xml_txt);

auto tree = factory.createTree("MainTree");
NodeStatus status = tree.tickWhileRunning();

ASSERT_EQ(status, NodeStatus::SUCCESS);
ASSERT_EQ(tree.rootBlackboard()->get<BatteryStatus>("fault_status"), LOW_BATTERY);
}
58 changes: 0 additions & 58 deletions tests/gtest_postconditions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -85,61 +85,3 @@ TEST(PostConditions, Issue601)

ASSERT_EQ(tree.rootBlackboard()->get<std::string>("test"), "halted");
}

enum BatteryStatus
{
BATTERY_OK,
LOW_BATTERY
};

class BatteryCheck : public BT::SyncActionNode
{
public:
BatteryCheck(const std::string& name, const BT::NodeConfig& config)
: BT::SyncActionNode(name, config)
{}

static BT::PortsList providedPorts()
{
return { InputPort<int>("health") };
}

BT::NodeStatus tick() override
{
int health = getInput<int>("health").value();
return health > 10 ? NodeStatus::SUCCESS : NodeStatus::FAILURE;
}
};

TEST(PostConditions, OnFailure)
{
const std::string xml_text = R"(
<root BTCPP_format="4" >
<BehaviorTree ID="Main">
<Sequence>
<Script code="battery_voltage := 7"/>
<Script code="battery_status := BATTERY_OK"/>
<SubTree ID="Sub" _autoremap="true"
fault_status="LOW_BATTERY"
health="{battery_voltage}" />
</Sequence>
</BehaviorTree>
<BehaviorTree ID="Sub">
<BatteryCheck health="{health}"
_onFailure="battery_status := fault_status" />
</BehaviorTree>
</root>)";

BehaviorTreeFactory factory;
factory.registerNodeType<BatteryCheck>("BatteryCheck");
factory.registerScriptingEnums<BatteryStatus>();

factory.registerBehaviorTreeFromText(xml_text);

auto tree = factory.createTree("Main");
const auto status = tree.tickWhileRunning();

ASSERT_EQ(status, NodeStatus::FAILURE);
ASSERT_EQ(tree.rootBlackboard()->get<BatteryStatus>("battery_status"), LOW_BATTERY);
}

0 comments on commit 0a3393c

Please sign in to comment.