From 9a871fc0038097e412deb393e95ea09acd6c7d49 Mon Sep 17 00:00:00 2001 From: Sachin Kumar Date: Sun, 17 Aug 2025 18:10:48 +0200 Subject: [PATCH 1/6] test added for xml schema validation - urdf files added for validation and unvalidation - schema xsd file added --- hardware_interface/CMakeLists.txt | 12 ++ hardware_interface/schema/ros2_control.xsd | 105 ++++++++++++++++ .../test/test_validate_xml_schema.cpp | 118 ++++++++++++++++++ .../urdf/test_hardware_components.urdf | 90 +++++++++++++ .../test_hardware_components_with_error.urdf | 90 +++++++++++++ 5 files changed, 415 insertions(+) create mode 100644 hardware_interface/schema/ros2_control.xsd create mode 100644 hardware_interface/test/test_validate_xml_schema.cpp create mode 100644 hardware_interface/urdf/test_hardware_components.urdf create mode 100644 hardware_interface/urdf/test_hardware_components_with_error.urdf diff --git a/hardware_interface/CMakeLists.txt b/hardware_interface/CMakeLists.txt index e10f7ec16f..7fcd18e434 100644 --- a/hardware_interface/CMakeLists.txt +++ b/hardware_interface/CMakeLists.txt @@ -73,6 +73,9 @@ if(BUILD_TESTING) find_package(ament_cmake_gmock REQUIRED) find_package(ros2_control_test_assets REQUIRED) + find_package(ament_index_cpp REQUIRED) + find_package(PkgConfig REQUIRED) + pkg_check_modules(LIBXML2 REQUIRED IMPORTED_TARGET libxml-2.0) ament_add_gmock(test_macros test/test_macros.cpp) target_include_directories(test_macros PRIVATE include) @@ -101,6 +104,10 @@ if(BUILD_TESTING) ament_add_gmock(test_component_parser test/test_component_parser.cpp) target_link_libraries(test_component_parser hardware_interface ros2_control_test_assets::ros2_control_test_assets) + # Test XML Schema Validator + ament_add_gmock(test_validate_xml_schema test/test_validate_xml_schema.cpp) + target_link_libraries(test_validate_xml_schema PkgConfig::LIBXML2 ament_index_cpp::ament_index_cpp) + add_library(test_hardware_components SHARED test/test_hardware_components/test_single_joint_actuator.cpp test/test_hardware_components/test_force_torque_sensor.cpp @@ -135,6 +142,11 @@ install( LIBRARY DESTINATION lib ) +install( + DIRECTORY schema urdf + DESTINATION share/hardware_interface +) + ament_export_targets(export_hardware_interface HAS_LIBRARY_TARGET) ament_export_dependencies(${THIS_PACKAGE_INCLUDE_DEPENDS}) ament_package() diff --git a/hardware_interface/schema/ros2_control.xsd b/hardware_interface/schema/ros2_control.xsd new file mode 100644 index 0000000000..a9c237c090 --- /dev/null +++ b/hardware_interface/schema/ros2_control.xsd @@ -0,0 +1,105 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/hardware_interface/test/test_validate_xml_schema.cpp b/hardware_interface/test/test_validate_xml_schema.cpp new file mode 100644 index 0000000000..cfb65d95eb --- /dev/null +++ b/hardware_interface/test/test_validate_xml_schema.cpp @@ -0,0 +1,118 @@ +// Copyright 2025 ros2_control development team +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include +#include + +#include + +#include + +class XmlParser +{ +public: + XmlParser(const std::string & xmlFilePath, const std::string & xsdFilePath) + : doc(nullptr), schema(nullptr), schemaCtx(nullptr) + { + this->xmlFile = xmlFilePath; + this->xsdFile = xsdFilePath; + } + + ~XmlParser() + { + if (doc) + { + xmlFreeDoc(doc); + } + if (schemaCtx) + { + xmlSchemaFreeParserCtxt(schemaCtx); + } + if (schema) + { + xmlSchemaFree(schema); + } + xmlCleanupParser(); + } + + bool parseAndValidate() + { + doc = xmlReadFile(xmlFile.c_str(), nullptr, 0); + if (!doc) + { + return false; + } + + schemaCtx = xmlSchemaNewParserCtxt(xsdFile.c_str()); + if (!schemaCtx) + { + return false; + } + schema = xmlSchemaParse(schemaCtx); + if (!schema) + { + return false; + } + + xmlSchemaValidCtxtPtr validCtx = xmlSchemaNewValidCtxt(schema); + if (!validCtx) + { + return false; + } + int ret = xmlSchemaValidateDoc(validCtx, doc); + xmlSchemaFreeValidCtxt(validCtx); + + return ret == 0; + } + +private: + std::string xmlFile; + std::string xsdFile; + xmlDocPtr doc; + xmlSchemaPtr schema; + xmlSchemaParserCtxtPtr schemaCtx; +}; + +// Test fixture for XML schema validation +class XmlSchemaValidationTest : public ::testing::Test +{ +protected: + std::string valid_xml; + std::string invalid_xml; + std::string xsd; + + void SetUp() override + { + // Use ament_index_cpp to get the package share directory + std::string package_share_dir = + ament_index_cpp::get_package_share_directory("hardware_interface"); + valid_xml = package_share_dir + "/urdf/test_hardware_components.urdf"; + invalid_xml = package_share_dir + "/urdf/test_hardware_components_with_error.urdf"; + xsd = package_share_dir + "/schema/ros2_control.xsd"; + } +}; + +TEST_F(XmlSchemaValidationTest, ValidXmlPasses) +{ + XmlParser parser(valid_xml, xsd); + EXPECT_TRUE(parser.parseAndValidate()); +} + +TEST_F(XmlSchemaValidationTest, InvalidXmlFails) +{ + XmlParser parser(invalid_xml, xsd); + EXPECT_FALSE(parser.parseAndValidate()); +} diff --git a/hardware_interface/urdf/test_hardware_components.urdf b/hardware_interface/urdf/test_hardware_components.urdf new file mode 100644 index 0000000000..611a7b4385 --- /dev/null +++ b/hardware_interface/urdf/test_hardware_components.urdf @@ -0,0 +1,90 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + test_hardware_components/TestForceTorqueSensor + 0 + + + + + + + + + + + + + + test_hardware_components/TestTwoJointSystem + + + + -1 + 1 + + + + + + + + + + 0 + 1 + + + + + diff --git a/hardware_interface/urdf/test_hardware_components_with_error.urdf b/hardware_interface/urdf/test_hardware_components_with_error.urdf new file mode 100644 index 0000000000..34b01aa5c1 --- /dev/null +++ b/hardware_interface/urdf/test_hardware_components_with_error.urdf @@ -0,0 +1,90 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + test_hardware_components/TestForceTorqueSensor + 0 + + + + + + + + + + + + + + test_hardware_components/TestTwoJointSystem + + + + -1 + 1 + + + + + + + + + + 0 + 1 + + + + + From c1c0a0005b72918d319fd73a452add648606c39b Mon Sep 17 00:00:00 2001 From: Sachin Kumar Date: Sun, 17 Aug 2025 18:15:56 +0200 Subject: [PATCH 2/6] test dependencies updated --- hardware_interface/package.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/hardware_interface/package.xml b/hardware_interface/package.xml index 8c448a1b12..6d320cf037 100644 --- a/hardware_interface/package.xml +++ b/hardware_interface/package.xml @@ -31,6 +31,8 @@ rcutils ament_cmake_gmock + ament_index_cpp + libxml2 ros2_control_test_assets From 097c4d76f8d70fc07e19ec31e5a48fc32d66122a Mon Sep 17 00:00:00 2001 From: Sachin Kumar Date: Mon, 18 Aug 2025 11:56:19 +0200 Subject: [PATCH 3/6] Apply suggestions from code review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit reformatting and sort ascending Co-authored-by: Christoph Fröhlich --- hardware_interface/CMakeLists.txt | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/hardware_interface/CMakeLists.txt b/hardware_interface/CMakeLists.txt index 7fcd18e434..19a2d0e43b 100644 --- a/hardware_interface/CMakeLists.txt +++ b/hardware_interface/CMakeLists.txt @@ -74,8 +74,7 @@ if(BUILD_TESTING) find_package(ament_cmake_gmock REQUIRED) find_package(ros2_control_test_assets REQUIRED) find_package(ament_index_cpp REQUIRED) - find_package(PkgConfig REQUIRED) - pkg_check_modules(LIBXML2 REQUIRED IMPORTED_TARGET libxml-2.0) + find_package(LibXml2) ament_add_gmock(test_macros test/test_macros.cpp) target_include_directories(test_macros PRIVATE include) @@ -106,7 +105,10 @@ if(BUILD_TESTING) # Test XML Schema Validator ament_add_gmock(test_validate_xml_schema test/test_validate_xml_schema.cpp) - target_link_libraries(test_validate_xml_schema PkgConfig::LIBXML2 ament_index_cpp::ament_index_cpp) + target_link_libraries(test_validate_xml_schema + ament_index_cpp::ament_index_cpp + LibXml2::LibXml2 + ) add_library(test_hardware_components SHARED test/test_hardware_components/test_single_joint_actuator.cpp From be56d2050e55e3c83203552f544701f62b8ac87a Mon Sep 17 00:00:00 2001 From: Sachin Kumar Date: Mon, 18 Aug 2025 11:59:55 +0200 Subject: [PATCH 4/6] urdf files moved to ros2_control_test_assets --- .../urdf/test_hardware_components.urdf | 90 ------------------- .../urdf/test_hardware_components.urdf | 13 ++- .../test_hardware_components_with_error.urdf | 0 3 files changed, 12 insertions(+), 91 deletions(-) delete mode 100644 hardware_interface/urdf/test_hardware_components.urdf rename {hardware_interface => ros2_control_test_assets}/urdf/test_hardware_components_with_error.urdf (100%) diff --git a/hardware_interface/urdf/test_hardware_components.urdf b/hardware_interface/urdf/test_hardware_components.urdf deleted file mode 100644 index 611a7b4385..0000000000 --- a/hardware_interface/urdf/test_hardware_components.urdf +++ /dev/null @@ -1,90 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - test_hardware_components/TestForceTorqueSensor - 0 - - - - - - - - - - - - - - test_hardware_components/TestTwoJointSystem - - - - -1 - 1 - - - - - - - - - - 0 - 1 - - - - - diff --git a/ros2_control_test_assets/urdf/test_hardware_components.urdf b/ros2_control_test_assets/urdf/test_hardware_components.urdf index c49c79bf55..611a7b4385 100644 --- a/ros2_control_test_assets/urdf/test_hardware_components.urdf +++ b/ros2_control_test_assets/urdf/test_hardware_components.urdf @@ -52,6 +52,7 @@ test_hardware_components/TestForceTorqueSensor + 0 @@ -68,12 +69,22 @@ test_hardware_components/TestTwoJointSystem - + + -1 + 1 + + + + 0 + 1 + + + diff --git a/hardware_interface/urdf/test_hardware_components_with_error.urdf b/ros2_control_test_assets/urdf/test_hardware_components_with_error.urdf similarity index 100% rename from hardware_interface/urdf/test_hardware_components_with_error.urdf rename to ros2_control_test_assets/urdf/test_hardware_components_with_error.urdf From 8c3008b41484c46300716bb9b8c56129f21655ed Mon Sep 17 00:00:00 2001 From: Sachin Kumar Date: Mon, 18 Aug 2025 12:20:43 +0200 Subject: [PATCH 5/6] urdf directory code updated package path updated to find urdf and xsd file --- hardware_interface/CMakeLists.txt | 9 ++------- hardware_interface/test/test_validate_xml_schema.cpp | 10 ++++++---- ros2_control_test_assets/CMakeLists.txt | 2 +- 3 files changed, 9 insertions(+), 12 deletions(-) diff --git a/hardware_interface/CMakeLists.txt b/hardware_interface/CMakeLists.txt index 19a2d0e43b..60080f5cbb 100644 --- a/hardware_interface/CMakeLists.txt +++ b/hardware_interface/CMakeLists.txt @@ -106,8 +106,8 @@ if(BUILD_TESTING) # Test XML Schema Validator ament_add_gmock(test_validate_xml_schema test/test_validate_xml_schema.cpp) target_link_libraries(test_validate_xml_schema - ament_index_cpp::ament_index_cpp - LibXml2::LibXml2 + ament_index_cpp::ament_index_cpp + LibXml2::LibXml2 ) add_library(test_hardware_components SHARED @@ -144,11 +144,6 @@ install( LIBRARY DESTINATION lib ) -install( - DIRECTORY schema urdf - DESTINATION share/hardware_interface -) - ament_export_targets(export_hardware_interface HAS_LIBRARY_TARGET) ament_export_dependencies(${THIS_PACKAGE_INCLUDE_DEPENDS}) ament_package() diff --git a/hardware_interface/test/test_validate_xml_schema.cpp b/hardware_interface/test/test_validate_xml_schema.cpp index cfb65d95eb..66124195d2 100644 --- a/hardware_interface/test/test_validate_xml_schema.cpp +++ b/hardware_interface/test/test_validate_xml_schema.cpp @@ -97,11 +97,13 @@ class XmlSchemaValidationTest : public ::testing::Test void SetUp() override { // Use ament_index_cpp to get the package share directory - std::string package_share_dir = + std::string urdf_package_share_dir = + ament_index_cpp::get_package_share_directory("ros2_control_test_assets"); + std::string xsd_package_share_dir = ament_index_cpp::get_package_share_directory("hardware_interface"); - valid_xml = package_share_dir + "/urdf/test_hardware_components.urdf"; - invalid_xml = package_share_dir + "/urdf/test_hardware_components_with_error.urdf"; - xsd = package_share_dir + "/schema/ros2_control.xsd"; + valid_xml = urdf_package_share_dir + "/urdf/test_hardware_components.urdf"; + invalid_xml = urdf_package_share_dir + "/urdf/test_hardware_components_with_error.urdf"; + xsd = xsd_package_share_dir + "/schema/ros2_control.xsd"; } }; diff --git a/ros2_control_test_assets/CMakeLists.txt b/ros2_control_test_assets/CMakeLists.txt index d63fb52c86..9450ba9d35 100644 --- a/ros2_control_test_assets/CMakeLists.txt +++ b/ros2_control_test_assets/CMakeLists.txt @@ -15,7 +15,7 @@ install( DESTINATION include/ros2_control_test_assets ) install( - FILES urdf/test_hardware_components.urdf + FILES urdf/test_hardware_components.urdf urdf/test_hardware_components_with_error.urdf DESTINATION share/ros2_control_test_assets/urdf ) install(TARGETS ros2_control_test_assets From babbcda9c49bd05e1035473d17a61bee37fbfaa1 Mon Sep 17 00:00:00 2001 From: Sachin Kumar Date: Mon, 18 Aug 2025 12:50:15 +0200 Subject: [PATCH 6/6] accidentely removed the code to add schema to directory --- hardware_interface/CMakeLists.txt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/hardware_interface/CMakeLists.txt b/hardware_interface/CMakeLists.txt index 60080f5cbb..a243a6ed77 100644 --- a/hardware_interface/CMakeLists.txt +++ b/hardware_interface/CMakeLists.txt @@ -134,6 +134,12 @@ install( DIRECTORY include/ DESTINATION include/hardware_interface ) + +install( + DIRECTORY schema + DESTINATION share/hardware_interface +) + install( TARGETS mock_components