| 462 | } |
| 463 | |
| 464 | void VerifyXML(const std::string& xml_text, |
| 465 | const std::unordered_map<std::string, BT::NodeType>& registered_nodes) |
| 466 | { |
| 467 | XMLDocument doc; |
| 468 | auto xml_error = doc.Parse(xml_text.c_str(), xml_text.size()); |
| 469 | if(xml_error != tinyxml2::XML_SUCCESS) |
| 470 | { |
| 471 | char buffer[512]; |
| 472 | std::ignore = |
| 473 | snprintf(buffer, sizeof buffer, "Error parsing the XML: %s", doc.ErrorName()); |
| 474 | throw RuntimeError(buffer); |
| 475 | } |
| 476 | |
| 477 | //-------- Helper functions (lambdas) ----------------- |
| 478 | auto ThrowError = [&](int line_num, const std::string& text) { |
| 479 | char buffer[512]; |
| 480 | std::ignore = snprintf(buffer, sizeof buffer, "Error at line %d: -> %s", line_num, |
| 481 | text.c_str()); |
| 482 | throw RuntimeError(buffer); |
| 483 | }; |
| 484 | |
| 485 | auto ChildrenCount = [](const XMLElement* parent_node) { |
| 486 | int count = 0; |
| 487 | for(auto node = parent_node->FirstChildElement(); node != nullptr; |
| 488 | node = node->NextSiblingElement()) |
| 489 | { |
| 490 | count++; |
| 491 | } |
| 492 | return count; |
| 493 | }; |
| 494 | //----------------------------- |
| 495 | |
| 496 | const XMLElement* xml_root = doc.RootElement(); |
| 497 | |
| 498 | if(xml_root == nullptr || !StrEqual(xml_root->Name(), "root")) |
| 499 | { |
| 500 | throw RuntimeError("The XML must have a root node called <root>"); |
| 501 | } |
| 502 | //------------------------------------------------- |
| 503 | auto models_root = xml_root->FirstChildElement("TreeNodesModel"); |
| 504 | auto meta_sibling = models_root != nullptr ? models_root->NextSiblingElement("TreeNodes" |
| 505 | "Model") : |
| 506 | nullptr; |
| 507 | |
| 508 | if(meta_sibling != nullptr) |
| 509 | { |
| 510 | ThrowError(meta_sibling->GetLineNum(), " Only a single node <TreeNodesModel> is " |
| 511 | "supported"); |
| 512 | } |
| 513 | if(models_root != nullptr) |
| 514 | { |
| 515 | // not having a MetaModel is not an error. But consider that the |
| 516 | // Graphical editor needs it. |
| 517 | for(auto node = xml_root->FirstChildElement(); node != nullptr; |
| 518 | node = node->NextSiblingElement()) |
| 519 | { |
| 520 | const std::string name = node->Name(); |
| 521 | if(name == "Action" || name == "Decorator" || name == "SubTree" || |
no test coverage detected