diff --git a/perception/autoware_detected_object_feature_remover/CMakeLists.txt b/perception/autoware_detected_object_feature_remover/CMakeLists.txt index 54763f8bff9ab..58384613f7d3f 100644 --- a/perception/autoware_detected_object_feature_remover/CMakeLists.txt +++ b/perception/autoware_detected_object_feature_remover/CMakeLists.txt @@ -13,6 +13,20 @@ rclcpp_components_register_node(${PROJECT_NAME} EXECUTABLE detected_object_feature_remover_node ) +if(BUILD_TESTING) + find_package(ament_cmake_ros REQUIRED) + # run node unit testings with ROS_DOMAIN_ID isolation + ament_add_ros_isolated_gtest(test_${PROJECT_NAME}_node + test/test_detected_object_feature_remover_node.cpp + ) + target_include_directories(test_${PROJECT_NAME}_node PRIVATE src) + target_link_libraries(test_${PROJECT_NAME}_node ${${PROJECT_NAME}_LIBRARIES}) + ament_target_dependencies(test_${PROJECT_NAME}_node + ${${PROJECT_NAME}_FOUND_BUILD_DEPENDS} + ${${PROJECT_NAME}_FOUND_TEST_DEPENDS} + ) +endif() + ament_auto_package( INSTALL_TO_SHARE launch diff --git a/perception/autoware_detected_object_feature_remover/package.xml b/perception/autoware_detected_object_feature_remover/package.xml index eb64490df1f0f..8726e2bf26071 100644 --- a/perception/autoware_detected_object_feature_remover/package.xml +++ b/perception/autoware_detected_object_feature_remover/package.xml @@ -21,6 +21,7 @@ ament_cmake_ros ament_lint_auto autoware_lint_common + autoware_test_utils ament_cmake diff --git a/perception/autoware_detected_object_feature_remover/test/test_detected_object_feature_remover_node.cpp b/perception/autoware_detected_object_feature_remover/test/test_detected_object_feature_remover_node.cpp new file mode 100644 index 0000000000000..e54151786278a --- /dev/null +++ b/perception/autoware_detected_object_feature_remover/test/test_detected_object_feature_remover_node.cpp @@ -0,0 +1,182 @@ +// Copyright 2024 TIER IV, 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. + +#include "detected_object_feature_remover_node.hpp" + +#include +#include + +#include "tier4_perception_msgs/msg/detail/detected_object_with_feature__struct.hpp" + +#include + +namespace +{ +using autoware::detected_object_feature_remover::DetectedObjectFeatureRemover; +using autoware::test_utils::AutowareTestManager; +using autoware_perception_msgs::msg::DetectedObject; +using autoware_perception_msgs::msg::DetectedObjects; +using tier4_perception_msgs::msg::DetectedObjectsWithFeature; +using tier4_perception_msgs::msg::DetectedObjectWithFeature; + +/** + * @brief Return a new `autoware::test_utils::AutowareTestManager` instance as a shared pointer. + * + * @return Shared pointer of `autoware::test_utils::AutowareTestManager`. + */ +std::shared_ptr generate_test_manager() +{ + return std::make_shared(); +} + +/** + * @brief Return a new `autoware::detected_object_feature_remover::DetectedObjectFeatureRemover` + * instance as a shared pointer. + * + * @return Shared pointer of + * `autoware::detected_object_feature_remover::DetectedObjectFeatureRemover`. + */ +std::shared_ptr generate_node( + const std::string & input_topic, const std::string & output_topic) +{ + auto node_options = rclcpp::NodeOptions{}; + node_options.arguments( + {"--ros-args", "-r", "~/input:=" + input_topic, "-r", "~/output:=" + output_topic}); + + return std::make_shared(node_options); +} + +/** + * @brief Return a new `autoware_perception_msgs::msg::DetectedObject` instance. + * + * @return New instance of `autoware_perception_msgs::msg::DetectedObject`. + */ +DetectedObject generate_detected_object() +{ + DetectedObject output; + output.kinematics.pose_with_covariance.pose.position.x = 1.0; + output.kinematics.pose_with_covariance.pose.position.y = 2.0; + output.kinematics.pose_with_covariance.pose.position.z = 3.0; + output.kinematics.pose_with_covariance.pose.orientation.x = 0.0; + output.kinematics.pose_with_covariance.pose.orientation.y = 0.0; + output.kinematics.pose_with_covariance.pose.orientation.z = 0.0; + output.kinematics.pose_with_covariance.pose.orientation.w = 1.0; + return output; +} + +/** + * @brief Return a new `tier4_perception_msgs::msg::DetectedObjectWithFeature` instance. + * @details Return a object including a single object created by `generate_detected_object`. + * + * @return New instance of `tier4_perception_msgs::msg::DetectedObjectWithFeature`. + */ +DetectedObjectWithFeature generate_feature_object() +{ + DetectedObjectWithFeature output; + output.object = generate_detected_object(); + return output; +} + +/** + * @brief Return a new `tier4_perception_msgs::msg::DetectedObjectsWithFeature` instance. + * @details If `as_emtpy=true`, returns a instance without any objects. Otherwise, returns a + * instance including a single object created by `generate_feature_object`. + * + * @param stamp Timestamp of the message. + * @param as_empty Whether to return a instance without any objects. + * @return New instance of `tier4_perception_mgs::msg::DetectedObjectsWIthFeature`. + */ +DetectedObjectsWithFeature generate_feature_objects(const rclcpp::Time & stamp, bool as_empty) +{ + DetectedObjectsWithFeature output; + output.header.frame_id = "base_link"; + output.header.stamp = stamp; + if (!as_empty) { + auto object = generate_feature_object(); + output.feature_objects.emplace_back(object); + } + return output; +} +} // namespace + +/** + * Test suite of DetectedObjectFeatureRemover. + * + * This test case checks whether the node works if the arbitrary object is input. + */ +TEST(FeatureRemoverTest, TestArbitraryObject) +{ + const std::string input_topic = "/detected_object_feature_remover/input"; + const std::string output_topic = "/detected_object_feature_remover/output"; + auto test_manager = generate_test_manager(); + auto node = generate_node(input_topic, output_topic); + + // set output subscriber + DetectedObjects output; + auto callback = [&output](const DetectedObjects::ConstSharedPtr msg) { + output.header = msg->header; + output.objects = msg->objects; + }; + test_manager->set_subscriber(output_topic, callback); + + // prepare input + auto stamp = node->get_clock()->now(); + constexpr bool as_empty = false; + auto input = generate_feature_objects(stamp, as_empty); + test_manager->test_pub_msg(node, input_topic, input); + + // Check output + auto expect = generate_detected_object(); + EXPECT_EQ(1, output.objects.size()); + EXPECT_EQ(expect, output.objects.front()); +} + +/** + * Test suite of DetectedObjectFeatureRemover. + * + * This test case checks whether the node works if the empty object is input. + */ +TEST(FeatureRemoverTest, TestEmptyObject) +{ + const std::string input_topic = "/detected_object_feature_remover/input"; + const std::string output_topic = "/detected_object_feature_remover/output"; + auto test_manager = generate_test_manager(); + auto node = generate_node(input_topic, output_topic); + + // set output subscriber + DetectedObjects output; + auto callback = [&output](const DetectedObjects::ConstSharedPtr msg) { + output.header = msg->header; + output.objects = msg->objects; + }; + test_manager->set_subscriber(output_topic, callback); + + // prepare input + auto stamp = node->get_clock()->now(); + constexpr bool as_empty = true; + auto input = generate_feature_objects(stamp, as_empty); + test_manager->test_pub_msg(node, input_topic, input); + + // Check output + EXPECT_EQ(0, output.objects.size()); +} + +int main(int argc, char ** argv) +{ + testing::InitGoogleTest(&argc, argv); + rclcpp::init(argc, argv); + bool result = RUN_ALL_TESTS(); + rclcpp::shutdown(); + return result; +}