diff --git a/.gitignore b/.gitignore index e43b0f9..64eef94 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ .DS_Store +__pycache__ +*.pyc diff --git a/rosidl_generator_dds_idl/CMakeLists.txt b/rosidl_generator_dds_idl/CMakeLists.txt index a12e451..c6feaf6 100644 --- a/rosidl_generator_dds_idl/CMakeLists.txt +++ b/rosidl_generator_dds_idl/CMakeLists.txt @@ -8,8 +8,10 @@ find_package(ament_cmake_python REQUIRED) ament_python_install_package(${PROJECT_NAME}) if(BUILD_TESTING) + find_package(ament_cmake_pytest REQUIRED) find_package(ament_lint_auto REQUIRED) ament_lint_auto_find_test_dependencies() + ament_add_pytest_test(pytest test) endif() ament_package( diff --git a/rosidl_generator_dds_idl/bin/rosidl_generator_dds_idl b/rosidl_generator_dds_idl/bin/rosidl_generator_dds_idl index d551150..c9872c1 100755 --- a/rosidl_generator_dds_idl/bin/rosidl_generator_dds_idl +++ b/rosidl_generator_dds_idl/bin/rosidl_generator_dds_idl @@ -29,13 +29,13 @@ def main(argv=sys.argv[1:]): help='The Python module extending the generator') args = parser.parse_args(argv) - return generate_dds_idl( + generate_dds_idl( args.generator_arguments_file, args.subfolders, args.extension, args.additional_service_templates, ) - + return 0 if __name__ == '__main__': sys.exit(main()) diff --git a/rosidl_generator_dds_idl/package.xml b/rosidl_generator_dds_idl/package.xml index 6b9722b..86980c7 100644 --- a/rosidl_generator_dds_idl/package.xml +++ b/rosidl_generator_dds_idl/package.xml @@ -13,6 +13,10 @@ ament_cmake rosidl_cmake + ament_index_python + rosidl_cli + + ament_cmake_pytest ament_lint_auto ament_lint_common diff --git a/rosidl_generator_dds_idl/pytest.ini b/rosidl_generator_dds_idl/pytest.ini new file mode 100644 index 0000000..fe55d2e --- /dev/null +++ b/rosidl_generator_dds_idl/pytest.ini @@ -0,0 +1,2 @@ +[pytest] +junit_family=xunit2 diff --git a/rosidl_generator_dds_idl/rosidl_generator_dds_idl/__init__.py b/rosidl_generator_dds_idl/rosidl_generator_dds_idl/__init__.py index 00cd04d..1ffc21f 100644 --- a/rosidl_generator_dds_idl/rosidl_generator_dds_idl/__init__.py +++ b/rosidl_generator_dds_idl/rosidl_generator_dds_idl/__init__.py @@ -48,8 +48,7 @@ def generate_dds_idl( if hasattr(module, entity_name): additional_context[entity_name] = \ getattr(module, entity_name) - generate_files(generator_arguments_file, mapping, additional_context, keep_case=True) - return 0 + return generate_files(generator_arguments_file, mapping, additional_context, keep_case=True) # used by the template diff --git a/rosidl_generator_dds_idl/rosidl_generator_dds_idl/cli.py b/rosidl_generator_dds_idl/rosidl_generator_dds_idl/cli.py new file mode 100644 index 0000000..5bd5d06 --- /dev/null +++ b/rosidl_generator_dds_idl/rosidl_generator_dds_idl/cli.py @@ -0,0 +1,60 @@ +# Copyright 2021 Open Source Robotics Foundation, Inc. +# +# 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. + +import pathlib + +from ament_index_python import get_package_share_directory +from rosidl_cli.command.helpers import legacy_generator_arguments_file +from rosidl_cli.command.translate.extensions import TranslateCommandExtension + +from rosidl_generator_dds_idl import generate_dds_idl + + +class TranslateIDLToDDSIDL(TranslateCommandExtension): + + input_format = 'idl' + output_format = 'dds_idl' + + def translate( + self, + package_name, + interface_files, + include_paths, + output_path + ): + package_share_path = pathlib.Path( + get_package_share_directory('rosidl_generator_dds_idl')) + templates_path = package_share_path / 'resource' + + with legacy_generator_arguments_file( + package_name=package_name, + interface_files=interface_files, + include_paths=include_paths, + templates_path=templates_path, + output_path=output_path + ) as path_to_arguments_file: + generated_files = generate_dds_idl( + path_to_arguments_file, + subfolders=[], + extension_module_name=None, + additional_service_templates=[] + ) + translated_interface_files = [] + for path in generated_files: + path = pathlib.Path(path) + relative_path = path.relative_to(output_path) + translated_interface_files.append( + f'{output_path}:{relative_path.as_posix()}' + ) + return translated_interface_files diff --git a/rosidl_generator_dds_idl/setup.cfg b/rosidl_generator_dds_idl/setup.cfg new file mode 100644 index 0000000..c374238 --- /dev/null +++ b/rosidl_generator_dds_idl/setup.cfg @@ -0,0 +1,3 @@ +[options.entry_points] +rosidl_cli.command.translate.extensions = + idl2ddsidl = rosidl_generator_dds_idl.cli:TranslateIDLToDDSIDL diff --git a/rosidl_generator_dds_idl/test/data/msg/Test.idl b/rosidl_generator_dds_idl/test/data/msg/Test.idl new file mode 100644 index 0000000..71694d3 --- /dev/null +++ b/rosidl_generator_dds_idl/test/data/msg/Test.idl @@ -0,0 +1,36 @@ +// generated from rosidl_adapter/resource/msg.idl.em +// with input from test_msgs/msg/Test.msg +// generated code does not contain a copyright notice + + +module test_msgs { + module msg { + struct Test { + boolean bool_value; + + octet byte_value; + + uint8 char_value; + + float float32_value; + + double float64_value; + + int8 int8_value; + + uint8 uint8_value; + + int16 int16_value; + + uint16 uint16_value; + + int32 int32_value; + + uint32 uint32_value; + + int64 int64_value; + + uint64 uint64_value; + }; + }; +}; diff --git a/rosidl_generator_dds_idl/test/data/msg/Test_.expected.idl b/rosidl_generator_dds_idl/test/data/msg/Test_.expected.idl new file mode 100644 index 0000000..bbee4a3 --- /dev/null +++ b/rosidl_generator_dds_idl/test/data/msg/Test_.expected.idl @@ -0,0 +1,41 @@ +// generated from rosidl_generator_dds_idl/resource/idl.idl.em +// with input from test_msgs:msg/Test.idl +// generated code does not contain a copyright notice + +#ifndef __test_msgs__msg__test__idl__ +#define __test_msgs__msg__test__idl__ + + +module test_msgs { + +module msg { + +module dds_ { + + +struct Test_ { +boolean bool_value_; +octet byte_value_; +octet char_value_; +float float32_value_; +double float64_value_; +octet int8_value_; +octet uint8_value_; +short int16_value_; +unsigned short uint16_value_; +long int32_value_; +unsigned long uint32_value_; +long long int64_value_; +unsigned long long uint64_value_; + +}; + + +}; // module dds_ + +}; // module msg + +}; // module test_msgs + + +#endif // __test_msgs__msg__test__idl__ diff --git a/rosidl_generator_dds_idl/test/test_cli_extensions.py b/rosidl_generator_dds_idl/test/test_cli_extensions.py new file mode 100644 index 0000000..3f17444 --- /dev/null +++ b/rosidl_generator_dds_idl/test/test_cli_extensions.py @@ -0,0 +1,49 @@ +# Copyright 2021 Open Source Robotics Foundation, Inc. +# +# 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. + +import filecmp +import pathlib + +from rosidl_cli.command.translate.api import translate + + +DATA_PATH = pathlib.Path(__file__).parent / 'data' + + +def test_idl2ddsidl_translation(tmp_path, capsys): + # NOTE(hidmic): pytest and empy do not play along, + # the latter expects some proxy will stay in sys.stdout + # and the former insists in overwriting it + import sys + print(sys.path) + + with capsys.disabled(): + # Test .idl to _.idl translation + idl_files = translate( + package_name='test_msgs', + interface_files=[ + f'{DATA_PATH}:msg/Test.idl'], + output_path=tmp_path, + output_format='dds_idl', + translators=['idl2ddsidl'] + ) + + assert len(idl_files) == 1 + idl_file = idl_files[0] + assert idl_file == f'{tmp_path}:msg/Test_.idl' + assert filecmp.cmp( + tmp_path / 'msg' / 'Test_.idl', + DATA_PATH / 'msg' / 'Test_.expected.idl', + shallow=False + )