From 79e2e044d32ab3ad011fe9aecf656d260bbaf7c8 Mon Sep 17 00:00:00 2001 From: brawner Date: Wed, 2 Sep 2020 14:25:45 -0700 Subject: [PATCH] Add basic unit tests for refactored functions in rcl_yaml_param_parser (coverage part 1/3) (#771) * Add basic unit tests for refactored functions Signed-off-by: Stephen Brawner * PR Fixup Signed-off-by: Stephen Brawner * Fix memory errors Signed-off-by: Stephen Brawner * headers moved Signed-off-by: Stephen Brawner * Addressing feedback Signed-off-by: Stephen Brawner * Switch to decltype Signed-off-by: Stephen Brawner --- rcl_yaml_param_parser/CMakeLists.txt | 47 ++ rcl_yaml_param_parser/test/test_namespace.cpp | 106 +++++ .../test/test_node_params.cpp | 42 ++ rcl_yaml_param_parser/test/test_parse.cpp | 448 ++++++++++++++++++ .../test/test_yaml_variant.cpp | 184 +++++++ 5 files changed, 827 insertions(+) create mode 100644 rcl_yaml_param_parser/test/test_namespace.cpp create mode 100644 rcl_yaml_param_parser/test/test_node_params.cpp create mode 100644 rcl_yaml_param_parser/test/test_parse.cpp create mode 100644 rcl_yaml_param_parser/test/test_yaml_variant.cpp diff --git a/rcl_yaml_param_parser/CMakeLists.txt b/rcl_yaml_param_parser/CMakeLists.txt index 343b2ef..5ce4a75 100644 --- a/rcl_yaml_param_parser/CMakeLists.txt +++ b/rcl_yaml_param_parser/CMakeLists.txt @@ -63,6 +63,30 @@ if(BUILD_TESTING) performance_test_fixture::performance_test_fixture INTERFACE_INCLUDE_DIRECTORIES) # Gtests + ament_add_gtest(test_namespace + test/test_namespace.cpp + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" + ) + if(TARGET test_namespace) + ament_target_dependencies(test_namespace + "rcutils" + "osrf_testing_tools_cpp" + ) + target_link_libraries(test_namespace ${PROJECT_NAME}) + endif() + + ament_add_gtest(test_node_params + test/test_node_params.cpp + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" + ) + if(TARGET test_node_params) + ament_target_dependencies(test_node_params + "rcutils" + "osrf_testing_tools_cpp" + ) + target_link_libraries(test_node_params ${PROJECT_NAME}) + endif() + ament_add_gtest(test_parse_yaml test/test_parse_yaml.cpp WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" @@ -73,6 +97,18 @@ if(BUILD_TESTING) PRIVATE ${osrf_testing_tools_cpp_INCLUDE_DIRS}) endif() + ament_add_gtest(test_parse + test/test_parse.cpp + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" + ) + if(TARGET test_parse) + ament_target_dependencies(test_parse + "rcutils" + "osrf_testing_tools_cpp" + ) + target_link_libraries(test_parse ${PROJECT_NAME}) + endif() + ament_add_gtest(test_parser test/test_parser.cpp WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" @@ -94,6 +130,17 @@ if(BUILD_TESTING) "rcutils" ) endif() + ament_add_gtest(test_yaml_variant + test/test_yaml_variant.cpp + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" + ) + if(TARGET test_yaml_variant) + ament_target_dependencies(test_yaml_variant + "rcutils" + "osrf_testing_tools_cpp" + ) + target_link_libraries(test_yaml_variant ${PROJECT_NAME}) + endif() endif() ament_export_dependencies(ament_cmake libyaml_vendor) diff --git a/rcl_yaml_param_parser/test/test_namespace.cpp b/rcl_yaml_param_parser/test/test_namespace.cpp new file mode 100644 index 0000000..8c685a7 --- /dev/null +++ b/rcl_yaml_param_parser/test/test_namespace.cpp @@ -0,0 +1,106 @@ +// Copyright 2020 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. + +#include + +#include + +#include +#include + +#include "osrf_testing_tools_cpp/scope_exit.hpp" +#include "rcl_yaml_param_parser/parser.h" +#include "../src/impl/namespace.h" +#include "rcutils/allocator.h" +#include "rcutils/strdup.h" + +TEST(TestNamespace, add_name_to_ns) { + rcutils_allocator_t allocator = rcutils_get_default_allocator(); + namespace_tracker_t ns_tracker; + ns_tracker.node_ns = nullptr; + ns_tracker.parameter_ns = nullptr; + ns_tracker.num_node_ns = 0; + ns_tracker.num_parameter_ns = 0; + + rcutils_ret_t ret = add_name_to_ns(&ns_tracker, nullptr, NS_TYPE_NODE, allocator); + EXPECT_EQ(RCUTILS_RET_INVALID_ARGUMENT, ret) << rcutils_get_error_string().str; + EXPECT_EQ(nullptr, ns_tracker.node_ns); + + ret = add_name_to_ns(&ns_tracker, "node1", NS_TYPE_NODE, allocator); + EXPECT_EQ(RCUTILS_RET_OK, ret) << rcutils_get_error_string().str; + EXPECT_STREQ("node1", ns_tracker.node_ns); + EXPECT_EQ(1u, ns_tracker.num_node_ns); + OSRF_TESTING_TOOLS_CPP_SCOPE_EXIT( + { + allocator.deallocate(ns_tracker.node_ns, allocator.state); + }); + + ret = add_name_to_ns(&ns_tracker, "node2", NS_TYPE_NODE, allocator); + EXPECT_EQ(RCUTILS_RET_OK, ret) << rcutils_get_error_string().str; + EXPECT_STREQ("node1/node2", ns_tracker.node_ns); + EXPECT_EQ(2u, ns_tracker.num_node_ns); + + ret = add_name_to_ns(&ns_tracker, "param1", NS_TYPE_PARAM, allocator); + EXPECT_EQ(RCUTILS_RET_OK, ret) << rcutils_get_error_string().str; + EXPECT_STREQ("param1", ns_tracker.parameter_ns); + EXPECT_EQ(1u, ns_tracker.num_parameter_ns); + OSRF_TESTING_TOOLS_CPP_SCOPE_EXIT( + { + allocator.deallocate(ns_tracker.parameter_ns, allocator.state); + }); + + ret = add_name_to_ns(&ns_tracker, "param2", NS_TYPE_PARAM, allocator); + EXPECT_EQ(RCUTILS_RET_OK, ret) << rcutils_get_error_string().str; + EXPECT_STREQ("param1.param2", ns_tracker.parameter_ns); + EXPECT_EQ(2u, ns_tracker.num_parameter_ns); +} + +TEST(TestNamespace, replace_ns) { + rcutils_allocator_t allocator = rcutils_get_default_allocator(); + namespace_tracker_t ns_tracker; + ns_tracker.node_ns = rcutils_strdup("initial_node1/initial_node2", allocator); + ASSERT_STREQ("initial_node1/initial_node2", ns_tracker.node_ns); + ns_tracker.parameter_ns = rcutils_strdup("initial_param1.initial_param2", allocator); + ASSERT_STREQ("initial_param1.initial_param2", ns_tracker.parameter_ns); + ns_tracker.num_node_ns = 2; + ns_tracker.num_parameter_ns = 2; + + char * expected_ns = rcutils_strdup("new_ns1/new_ns2/new_ns3", allocator); + ASSERT_STREQ("new_ns1/new_ns2/new_ns3", expected_ns); + OSRF_TESTING_TOOLS_CPP_SCOPE_EXIT( + { + allocator.deallocate(ns_tracker.node_ns, allocator.state); + allocator.deallocate(ns_tracker.parameter_ns, allocator.state); + allocator.deallocate(expected_ns, allocator.state); + }); + + rcutils_ret_t ret = + replace_ns(&ns_tracker, expected_ns, 3, NS_TYPE_NODE, allocator); + EXPECT_EQ(RCUTILS_RET_OK, ret) << rcutils_get_error_string().str; + EXPECT_STREQ(expected_ns, ns_tracker.node_ns); + EXPECT_EQ(3u, ns_tracker.num_node_ns); + + char * expected_param_ns = + rcutils_strdup("new_param1.new_param2.new_param3", allocator); + ASSERT_STREQ("new_param1.new_param2.new_param3", expected_param_ns); + OSRF_TESTING_TOOLS_CPP_SCOPE_EXIT( + { + allocator.deallocate(expected_param_ns, allocator.state); + }); + + ret = replace_ns(&ns_tracker, expected_param_ns, 3, NS_TYPE_PARAM, allocator); + EXPECT_EQ(RCUTILS_RET_OK, ret) << rcutils_get_error_string().str; + EXPECT_STREQ(expected_param_ns, ns_tracker.parameter_ns); + EXPECT_EQ(3u, ns_tracker.num_parameter_ns); +} diff --git a/rcl_yaml_param_parser/test/test_node_params.cpp b/rcl_yaml_param_parser/test/test_node_params.cpp new file mode 100644 index 0000000..d1b6729 --- /dev/null +++ b/rcl_yaml_param_parser/test/test_node_params.cpp @@ -0,0 +1,42 @@ +// Copyright 2020 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. + +#include + +#include + +#include +#include + +#include "osrf_testing_tools_cpp/scope_exit.hpp" +#include "rcl_yaml_param_parser/parser.h" +#include "../src/impl/node_params.h" +#include "rcutils/allocator.h" + +TEST(TestNodeParams, init_fini) { + rcutils_allocator_t allocator = rcutils_get_default_allocator(); + rcl_node_params_t node_params = {NULL, NULL, 0u}; + EXPECT_EQ(RCUTILS_RET_OK, node_params_init(&node_params, allocator)); + EXPECT_NE(nullptr, node_params.parameter_names); + EXPECT_NE(nullptr, node_params.parameter_values); + EXPECT_EQ(0u, node_params.num_params); + rcl_yaml_node_params_fini(&node_params, allocator); + EXPECT_EQ(nullptr, node_params.parameter_names); + EXPECT_EQ(nullptr, node_params.parameter_values); + EXPECT_EQ(0u, node_params.num_params); + + // This function doesn't return anything, so just check it doesn't segfault on the second try + rcl_yaml_node_params_fini(&node_params, allocator); + rcl_yaml_node_params_fini(nullptr, allocator); +} diff --git a/rcl_yaml_param_parser/test/test_parse.cpp b/rcl_yaml_param_parser/test/test_parse.cpp new file mode 100644 index 0000000..428fa0f --- /dev/null +++ b/rcl_yaml_param_parser/test/test_parse.cpp @@ -0,0 +1,448 @@ +// Copyright 2020 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. + +#include + +#include + +#include +#include + +#include "osrf_testing_tools_cpp/scope_exit.hpp" +#include "rcl_yaml_param_parser/parser.h" +#include "../src/impl/parse.h" +#include "../src/impl/node_params.h" +#include "rcutils/filesystem.h" + +TEST(TestParse, parse_value) { + rcutils_allocator_t allocator = rcutils_get_default_allocator(); + yaml_event_t event; + event.type = YAML_NO_EVENT; + event.start_mark = {0u, 0u, 0u}; + event.data.scalar = {NULL, NULL, NULL, 1u, 0, 0, YAML_ANY_SCALAR_STYLE}; + + bool is_seq = false; + size_t node_idx = 0u; + size_t parameter_idx = 0u; + data_types_t seq_data_type = DATA_TYPE_UNKNOWN; + rcl_params_t * params_st = rcl_yaml_node_struct_init(allocator); + ASSERT_NE(nullptr, params_st); + OSRF_TESTING_TOOLS_CPP_SCOPE_EXIT( + { + rcl_yaml_node_struct_fini(params_st); + }); + + ASSERT_EQ(RCUTILS_RET_OK, node_params_init(¶ms_st->params[0], allocator)); + params_st->num_nodes = 1u; + + // bool value + yaml_char_t bool_value[] = "true"; + const size_t bool_value_length = sizeof(bool_value) / sizeof(bool_value[0]); + event.data.scalar.value = bool_value; + event.data.scalar.length = bool_value_length; + + EXPECT_EQ( + RCUTILS_RET_OK, + parse_value(event, is_seq, node_idx, parameter_idx, &seq_data_type, params_st)) << + rcutils_get_error_string().str; + ASSERT_NE(nullptr, params_st->params[node_idx].parameter_values[parameter_idx].bool_value); + EXPECT_TRUE(*params_st->params[node_idx].parameter_values[parameter_idx].bool_value); + allocator.deallocate( + params_st->params[node_idx].parameter_values[parameter_idx].bool_value, allocator.state); + params_st->params[node_idx].parameter_values[parameter_idx].bool_value = nullptr; + + // integer value + yaml_char_t integer_value[] = "42"; + const size_t integer_value_length = sizeof(integer_value) / sizeof(integer_value[0]); + event.data.scalar.value = integer_value; + event.data.scalar.length = integer_value_length; + + EXPECT_EQ( + RCUTILS_RET_OK, + parse_value(event, is_seq, node_idx, parameter_idx, &seq_data_type, params_st)) << + rcutils_get_error_string().str; + ASSERT_NE(nullptr, params_st->params[node_idx].parameter_values[parameter_idx].integer_value); + EXPECT_EQ(42, *params_st->params[node_idx].parameter_values[parameter_idx].integer_value); + allocator.deallocate( + params_st->params[node_idx].parameter_values[parameter_idx].integer_value, allocator.state); + params_st->params[node_idx].parameter_values[parameter_idx].integer_value = nullptr; + + // double value + yaml_char_t double_value[] = "3.14159"; + const size_t double_value_length = sizeof(double_value) / sizeof(double_value[0]); + event.data.scalar.value = double_value; + event.data.scalar.length = double_value_length; + + EXPECT_EQ( + RCUTILS_RET_OK, + parse_value(event, is_seq, node_idx, parameter_idx, &seq_data_type, params_st)) << + rcutils_get_error_string().str; + ASSERT_NE(nullptr, params_st->params[node_idx].parameter_values[parameter_idx].double_value); + EXPECT_EQ(3.14159, *params_st->params[node_idx].parameter_values[parameter_idx].double_value); + allocator.deallocate( + params_st->params[node_idx].parameter_values[parameter_idx].double_value, allocator.state); + params_st->params[node_idx].parameter_values[parameter_idx].double_value = nullptr; + + // double value + yaml_char_t string_value[] = "hello, I am a string"; + const size_t string_value_length = sizeof(string_value) / sizeof(string_value[0]); + event.data.scalar.value = string_value; + event.data.scalar.length = string_value_length; + + EXPECT_EQ( + RCUTILS_RET_OK, + parse_value(event, is_seq, node_idx, parameter_idx, &seq_data_type, params_st)) << + rcutils_get_error_string().str; + ASSERT_NE(nullptr, params_st->params[node_idx].parameter_values[parameter_idx].string_value); + EXPECT_STREQ( + "hello, I am a string", + params_st->params[node_idx].parameter_values[parameter_idx].string_value); + allocator.deallocate( + params_st->params[node_idx].parameter_values[parameter_idx].string_value, allocator.state); + params_st->params[node_idx].parameter_values[parameter_idx].string_value = nullptr; +} + +TEST(TestParse, parse_value_sequence) { + rcutils_allocator_t allocator = rcutils_get_default_allocator(); + yaml_event_t event; + event.type = YAML_NO_EVENT; + event.start_mark = {0u, 0u, 0u}; + event.data.scalar = {NULL, NULL, NULL, 1u, 0, 0, YAML_ANY_SCALAR_STYLE}; + + bool is_seq = true; + size_t node_idx = 0u; + size_t parameter_idx = 0u; + data_types_t seq_data_type = DATA_TYPE_UNKNOWN; + rcl_params_t * params_st = rcl_yaml_node_struct_init(allocator); + ASSERT_NE(nullptr, params_st); + OSRF_TESTING_TOOLS_CPP_SCOPE_EXIT( + { + rcl_yaml_node_struct_fini(params_st); + }); + + ASSERT_EQ(RCUTILS_RET_OK, node_params_init(¶ms_st->params[0], allocator)); + params_st->num_nodes = 1u; + + // bool array value + yaml_char_t bool_value[] = "true"; + const size_t bool_value_length = sizeof(bool_value) / sizeof(bool_value[0]); + event.data.scalar.value = bool_value; + event.data.scalar.length = bool_value_length; + + // Check bad sequence type for bool + seq_data_type = DATA_TYPE_STRING; + EXPECT_EQ( + RCUTILS_RET_ERROR, + parse_value(event, is_seq, node_idx, parameter_idx, &seq_data_type, params_st)) << + rcutils_get_error_string().str; + EXPECT_EQ( + nullptr, + params_st->params[node_idx].parameter_values[parameter_idx].integer_array_value); + + // Check proper sequence type + seq_data_type = DATA_TYPE_UNKNOWN; + EXPECT_EQ( + RCUTILS_RET_OK, + parse_value(event, is_seq, node_idx, parameter_idx, &seq_data_type, params_st)) << + rcutils_get_error_string().str; + ASSERT_NE( + nullptr, params_st->params[node_idx].parameter_values[parameter_idx].bool_array_value); + EXPECT_TRUE( + params_st->params[node_idx].parameter_values[parameter_idx].bool_array_value->values[0]); + allocator.deallocate( + params_st->params[node_idx].parameter_values[parameter_idx].bool_array_value->values, + allocator.state); + allocator.deallocate( + params_st->params[node_idx].parameter_values[parameter_idx].bool_array_value, allocator.state); + params_st->params[node_idx].parameter_values[parameter_idx].bool_array_value = nullptr; + + // integer array value + yaml_char_t integer_value[] = "42"; + const size_t integer_value_length = sizeof(integer_value) / sizeof(integer_value[0]); + event.data.scalar.value = integer_value; + event.data.scalar.length = integer_value_length; + + // Check bad sequence type for int + seq_data_type = DATA_TYPE_STRING; + EXPECT_EQ( + RCUTILS_RET_ERROR, + parse_value(event, is_seq, node_idx, parameter_idx, &seq_data_type, params_st)) << + rcutils_get_error_string().str; + EXPECT_EQ( + nullptr, params_st->params[node_idx].parameter_values[parameter_idx].integer_array_value); + + // Check proper sequence type + seq_data_type = DATA_TYPE_UNKNOWN; + EXPECT_EQ( + RCUTILS_RET_OK, + parse_value(event, is_seq, node_idx, parameter_idx, &seq_data_type, params_st)) << + rcutils_get_error_string().str; + ASSERT_NE( + nullptr, + params_st->params[node_idx].parameter_values[parameter_idx].integer_array_value); + EXPECT_EQ( + 42, + params_st->params[node_idx].parameter_values[parameter_idx].integer_array_value->values[0]); + allocator.deallocate( + params_st->params[node_idx].parameter_values[parameter_idx].integer_array_value->values, + allocator.state); + allocator.deallocate( + params_st->params[node_idx].parameter_values[parameter_idx].integer_array_value, + allocator.state); + params_st->params[node_idx].parameter_values[parameter_idx].integer_array_value = nullptr; + + // double value + yaml_char_t double_value[] = "3.14159"; + const size_t double_value_length = sizeof(double_value) / sizeof(double_value[0]); + event.data.scalar.value = double_value; + event.data.scalar.length = double_value_length; + + // Check bad sequence type for double + seq_data_type = DATA_TYPE_STRING; + EXPECT_EQ( + RCUTILS_RET_ERROR, + parse_value(event, is_seq, node_idx, parameter_idx, &seq_data_type, params_st)) << + rcutils_get_error_string().str; + EXPECT_EQ( + nullptr, params_st->params[node_idx].parameter_values[parameter_idx].integer_array_value); + + // Check proper sequence type + seq_data_type = DATA_TYPE_UNKNOWN; + EXPECT_EQ( + RCUTILS_RET_OK, + parse_value(event, is_seq, node_idx, parameter_idx, &seq_data_type, params_st)) << + rcutils_get_error_string().str; + ASSERT_NE( + nullptr, params_st->params[node_idx].parameter_values[parameter_idx].double_array_value); + EXPECT_EQ( + 3.14159, + params_st->params[node_idx].parameter_values[parameter_idx].double_array_value->values[0]); + allocator.deallocate( + params_st->params[node_idx].parameter_values[parameter_idx].double_array_value->values, + allocator.state); + allocator.deallocate( + params_st->params[node_idx].parameter_values[parameter_idx].double_array_value, + allocator.state); + params_st->params[node_idx].parameter_values[parameter_idx].double_array_value = nullptr; + + // double value + yaml_char_t string_value[] = "hello, I am a string"; + const size_t string_value_length = sizeof(string_value) / sizeof(string_value[0]); + event.data.scalar.value = string_value; + event.data.scalar.length = string_value_length; + + // Check bad sequence type for string + seq_data_type = DATA_TYPE_BOOL; + EXPECT_EQ( + RCUTILS_RET_ERROR, + parse_value(event, is_seq, node_idx, parameter_idx, &seq_data_type, params_st)) << + rcutils_get_error_string().str; + EXPECT_EQ( + nullptr, params_st->params[node_idx].parameter_values[parameter_idx].integer_array_value); + + // Check proper sequence type + seq_data_type = DATA_TYPE_UNKNOWN; + EXPECT_EQ( + RCUTILS_RET_OK, + parse_value(event, is_seq, node_idx, parameter_idx, &seq_data_type, params_st)) << + rcutils_get_error_string().str; + ASSERT_NE( + nullptr, params_st->params[node_idx].parameter_values[parameter_idx].string_array_value); + EXPECT_STREQ( + "hello, I am a string", + params_st->params[node_idx].parameter_values[parameter_idx].string_array_value->data[0]); + EXPECT_EQ( + RCUTILS_RET_OK, + rcutils_string_array_fini( + params_st->params[node_idx].parameter_values[parameter_idx].string_array_value)) << + rcutils_get_error_string().str; + allocator.deallocate( + params_st->params[node_idx].parameter_values[parameter_idx].string_array_value, + allocator.state); + params_st->params[node_idx].parameter_values[parameter_idx].string_array_value = nullptr; +} + +TEST(TestParse, parse_value_bad_args) { + rcutils_allocator_t allocator = rcutils_get_default_allocator(); + yaml_event_t event; + event.type = YAML_NO_EVENT; + event.start_mark = {0u, 0u, 0u}; + event.data.scalar = {NULL, NULL, NULL, 1u, 0, 0, YAML_ANY_SCALAR_STYLE}; + + bool is_seq = false; + size_t node_idx = 0u; + size_t parameter_idx = 0u; + data_types_t seq_data_type = DATA_TYPE_UNKNOWN; + rcl_params_t * params_st = rcl_yaml_node_struct_init(allocator); + ASSERT_NE(nullptr, params_st); + OSRF_TESTING_TOOLS_CPP_SCOPE_EXIT( + { + rcl_yaml_node_struct_fini(params_st); + }); + + EXPECT_EQ( + RCUTILS_RET_INVALID_ARGUMENT, + parse_value(event, is_seq, node_idx, parameter_idx, nullptr, params_st)); + EXPECT_TRUE(rcutils_error_is_set()); + rcutils_reset_error(); + + EXPECT_EQ( + RCUTILS_RET_INVALID_ARGUMENT, + parse_value(event, is_seq, node_idx, parameter_idx, &seq_data_type, nullptr)); + EXPECT_TRUE(rcutils_error_is_set()); + rcutils_reset_error(); + + // No node to update + const size_t num_nodes = params_st->num_nodes; + params_st->num_nodes = 0u; + EXPECT_EQ( + RCUTILS_RET_INVALID_ARGUMENT, + parse_value(event, is_seq, node_idx, parameter_idx, &seq_data_type, params_st)); + EXPECT_TRUE(rcutils_error_is_set()); + rcutils_reset_error(); + params_st->num_nodes = num_nodes; + + ASSERT_EQ(RCUTILS_RET_OK, node_params_init(¶ms_st->params[0], allocator)); + params_st->num_nodes = 1u; + + // event.data.scalar.value is NULL, but event.data.scalar.length > 0 + event.data.scalar.value = NULL; + EXPECT_EQ( + RCUTILS_RET_INVALID_ARGUMENT, + parse_value(event, is_seq, node_idx, parameter_idx, &seq_data_type, params_st)); + EXPECT_TRUE(rcutils_error_is_set()); + rcutils_reset_error(); + + // event.data.scalar.length is 0 and style is not a QUOTED_SCALAR_STYLE + event.data.scalar.length = 0u; + yaml_char_t event_value[] = "non_empty_string"; + const size_t event_value_length = sizeof(event_value) / sizeof(event_value[0]); + event.data.scalar.value = event_value; + EXPECT_EQ( + RCUTILS_RET_ERROR, + parse_value(event, is_seq, node_idx, parameter_idx, &seq_data_type, params_st)) << + rcutils_get_error_string().str; + EXPECT_TRUE(rcutils_error_is_set()); + rcutils_reset_error(); + + // parameter_values is NULL + event.data.scalar.length = event_value_length; + rcl_variant_t * tmp_variant_array = params_st->params[0].parameter_values; + params_st->params[0].parameter_values = NULL; + EXPECT_EQ( + RCUTILS_RET_BAD_ALLOC, + parse_value(event, is_seq, node_idx, parameter_idx, &seq_data_type, params_st)) << + rcutils_get_error_string().str; + EXPECT_TRUE(rcutils_error_is_set()); + rcutils_reset_error(); + params_st->params[0].parameter_values = tmp_variant_array; +} + +TEST(TestParse, parse_key_bad_args) +{ + yaml_event_t event; + event.type = YAML_NO_EVENT; + event.start_mark = {0u, 0u, 0u}; + + rcutils_allocator_t allocator = rcutils_get_default_allocator(); + uint32_t map_level = MAP_NODE_NAME_LVL; + bool is_new_map = false; + size_t node_idx = 0; + size_t parameter_idx = 0; + namespace_tracker_t ns_tracker; + + rcl_params_t * params_st = rcl_yaml_node_struct_init(allocator); + ASSERT_NE(nullptr, params_st); + OSRF_TESTING_TOOLS_CPP_SCOPE_EXIT( + { + rcl_yaml_node_struct_fini(params_st); + }); + + ASSERT_EQ(RCUTILS_RET_OK, node_params_init(¶ms_st->params[0], allocator)); + params_st->num_nodes = 1u; + + // map_level is nullptr + EXPECT_EQ( + RCUTILS_RET_INVALID_ARGUMENT, + parse_key(event, nullptr, &is_new_map, &node_idx, ¶meter_idx, &ns_tracker, params_st)) << + rcutils_get_error_string().str; + EXPECT_TRUE(rcutils_error_is_set()); + rcutils_reset_error(); + + // params_st is nullptr + EXPECT_EQ( + RCUTILS_RET_INVALID_ARGUMENT, + parse_key(event, &map_level, &is_new_map, &node_idx, ¶meter_idx, &ns_tracker, nullptr)) << + rcutils_get_error_string().str; + EXPECT_TRUE(rcutils_error_is_set()); + rcutils_reset_error(); + + // event.data.scalar.value is nullptr + event.data.scalar.value = nullptr; + event.data.scalar.length = 1u; + EXPECT_EQ( + RCUTILS_RET_INVALID_ARGUMENT, + parse_key( + event, &map_level, &is_new_map, &node_idx, ¶meter_idx, &ns_tracker, params_st)) << + rcutils_get_error_string().str; + EXPECT_TRUE(rcutils_error_is_set()); + rcutils_reset_error(); + + yaml_char_t string_value[] = "key_name"; + const size_t string_value_length = sizeof(string_value) / sizeof(string_value[0]); + + // event.data.scalar.length is 0 + event.data.scalar.value = string_value; + event.data.scalar.length = 0u; + EXPECT_EQ( + RCUTILS_RET_ERROR, + parse_key( + event, &map_level, &is_new_map, &node_idx, ¶meter_idx, &ns_tracker, params_st)) << + rcutils_get_error_string().str; + EXPECT_TRUE(rcutils_error_is_set()); + rcutils_reset_error(); + event.data.scalar.length = string_value_length; + + // map_level is MAP_UNINIT_LVL + map_level = MAP_UNINIT_LVL; + EXPECT_EQ( + RCUTILS_RET_ERROR, + parse_key( + event, &map_level, &is_new_map, &node_idx, ¶meter_idx, &ns_tracker, params_st)) << + rcutils_get_error_string().str; + EXPECT_TRUE(rcutils_error_is_set()); + rcutils_reset_error(); + + // map_level is not a valid value + map_level = 42; + EXPECT_EQ( + RCUTILS_RET_ERROR, + parse_key( + event, &map_level, &is_new_map, &node_idx, ¶meter_idx, &ns_tracker, params_st)) << + rcutils_get_error_string().str; + EXPECT_TRUE(rcutils_error_is_set()); + rcutils_reset_error(); + + // previous parameter names required for parameter namespace + map_level = MAP_PARAMS_LVL; + is_new_map = true; + params_st->params[0].parameter_names[0] = nullptr; + EXPECT_EQ( + RCUTILS_RET_ERROR, + parse_key( + event, &map_level, &is_new_map, &node_idx, ¶meter_idx, &ns_tracker, params_st)) << + rcutils_get_error_string().str; + EXPECT_TRUE(rcutils_error_is_set()); + rcutils_reset_error(); +} diff --git a/rcl_yaml_param_parser/test/test_yaml_variant.cpp b/rcl_yaml_param_parser/test/test_yaml_variant.cpp new file mode 100644 index 0000000..67ea7b6 --- /dev/null +++ b/rcl_yaml_param_parser/test/test_yaml_variant.cpp @@ -0,0 +1,184 @@ +// Copyright 2020 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. + +#include + +#include + +#include +#include + +#include "osrf_testing_tools_cpp/scope_exit.hpp" +#include "rcl_yaml_param_parser/parser.h" +#include "../src/impl/yaml_variant.h" +#include "rcutils/allocator.h" +#include "rcutils/strdup.h" +#include "rcutils/testing/fault_injection.h" + +#define TEST_VARIANT_COPY(field, tmp_var) \ + do { \ + SCOPED_TRACE("TEST_VARIANT_COPY " #field); \ + rcl_variant_t src_variant{}; \ + rcl_variant_t dest_variant{}; \ + rcutils_allocator_t allocator = rcutils_get_default_allocator(); \ + src_variant.field = &tmp_var; \ + EXPECT_TRUE(rcl_yaml_variant_copy(&dest_variant, &src_variant, allocator)); \ + ASSERT_NE(nullptr, dest_variant.field); \ + EXPECT_EQ(*src_variant.field, *dest_variant.field); \ + rcl_yaml_variant_fini(&dest_variant, allocator); \ + src_variant.field = nullptr; \ + } while (0) + +#define TEST_VARIANT_ARRAY_COPY(field, tmp_array) \ + do { \ + SCOPED_TRACE("TEST_VARIANT_ARRAY_COPY " #field); \ + constexpr size_t array_size = sizeof(tmp_array) / sizeof(tmp_array[0]); \ + rcl_variant_t src_variant{}; \ + rcl_variant_t dest_variant{}; \ + rcutils_allocator_t allocator = rcutils_get_default_allocator(); \ + using ArrayT = std::remove_pointer::type; \ + src_variant.field = \ + static_cast(allocator.allocate(sizeof(ArrayT), allocator.state)); \ + ASSERT_NE(nullptr, src_variant.field); \ + using ValueT = std::remove_pointervalues)>::type; \ + src_variant.field->values = \ + static_cast( \ + allocator.zero_allocate(array_size, sizeof(ValueT), allocator.state)); \ + ASSERT_NE(nullptr, src_variant.field->values); \ + OSRF_TESTING_TOOLS_CPP_SCOPE_EXIT( \ + { \ + rcl_yaml_variant_fini(&src_variant, allocator); \ + rcl_yaml_variant_fini(&dest_variant, allocator); \ + src_variant.field = nullptr; \ + dest_variant.field = nullptr; \ + }); \ + src_variant.field->size = array_size; \ + for (size_t i = 0; i < array_size; ++i) { \ + src_variant.field->values[i] = tmp_array[i]; \ + } \ + EXPECT_TRUE(rcl_yaml_variant_copy(&dest_variant, &src_variant, allocator)); \ + ASSERT_NE(nullptr, dest_variant.field); \ + ASSERT_NE(nullptr, dest_variant.field->values); \ + for (size_t i = 0; i < array_size; ++i) { \ + SCOPED_TRACE(i); \ + EXPECT_EQ(src_variant.field->values[i], dest_variant.field->values[i]); \ + } \ + } while (0) + +TEST(TestYamlVariant, copy_fini) { + rcl_variant_t variant{}; + rcl_variant_t copy{}; + rcutils_allocator_t allocator = rcutils_get_default_allocator(); + + EXPECT_FALSE(rcl_yaml_variant_copy(nullptr, &variant, allocator)); + EXPECT_FALSE(rcl_yaml_variant_copy(©, nullptr, allocator)); + + ASSERT_TRUE(rcl_yaml_variant_copy(©, &variant, allocator)); + + rcl_yaml_variant_fini(©, allocator); + + // Check second fini works fine + rcl_yaml_variant_fini(©, allocator); + + // Check fini with a nullptr doesn't crash. + rcl_yaml_variant_fini(nullptr, allocator); +} + +TEST(TestYamlVariant, copy_bool_value) { + bool tmp_bool = true; + TEST_VARIANT_COPY(bool_value, tmp_bool); +} + +TEST(TestYamlVariant, copy_integer_value) { + int64_t tmp_int = 42; + TEST_VARIANT_COPY(integer_value, tmp_int); +} + +TEST(TestYamlVariant, copy_double_value) { + double tmp_double = 3.14159; + TEST_VARIANT_COPY(double_value, tmp_double); +} + +TEST(TestYamlVariant, copy_string_value) { + // String version is slightly different and can't use the above macro + rcl_variant_t src_variant{}; + rcl_variant_t dest_variant{}; + rcutils_allocator_t allocator = rcutils_get_default_allocator(); + + char * tmp_string = rcutils_strdup("hello there", allocator); + ASSERT_STREQ("hello there", tmp_string); + OSRF_TESTING_TOOLS_CPP_SCOPE_EXIT( + { + allocator.deallocate(tmp_string, allocator.state); + }); + src_variant.string_value = tmp_string; + EXPECT_TRUE(rcl_yaml_variant_copy(&dest_variant, &src_variant, allocator)); + ASSERT_NE(nullptr, dest_variant.string_value); + OSRF_TESTING_TOOLS_CPP_SCOPE_EXIT( + { + rcl_yaml_variant_fini(&dest_variant, allocator); + }); + EXPECT_STREQ(tmp_string, dest_variant.string_value); +} + +TEST(TestYamlVariant, copy_bool_array_values) { + constexpr bool bool_arry[] = {true, false, true}; + TEST_VARIANT_ARRAY_COPY(bool_array_value, bool_arry); +} + +TEST(TestYamlVariant, copy_integer_array_values) { + constexpr int64_t int_arry[] = {1, 2, 3}; + TEST_VARIANT_ARRAY_COPY(integer_array_value, int_arry); +} + +TEST(TestYamlVariant, copy_double_array_values) { + constexpr double double_arry[] = {10.0, 11.0, 12.0}; + TEST_VARIANT_ARRAY_COPY(double_array_value, double_arry); +} + +TEST(TestYamlVariant, copy_string_array_values) { + // Strings just have to be different + rcl_variant_t src_variant{}; + rcl_variant_t dest_variant{}; + rcutils_allocator_t allocator = rcutils_get_default_allocator(); + + constexpr size_t size = 3u; + src_variant.string_array_value = + static_cast( + allocator.allocate(sizeof(rcutils_string_array_t), allocator.state)); + ASSERT_NE(nullptr, src_variant.string_array_value); + OSRF_TESTING_TOOLS_CPP_SCOPE_EXIT( + { + rcl_yaml_variant_fini(&src_variant, allocator); + rcl_yaml_variant_fini(&dest_variant, allocator); + }); + *src_variant.string_array_value = rcutils_get_zero_initialized_string_array(); + ASSERT_EQ( + RCUTILS_RET_OK, rcutils_string_array_init(src_variant.string_array_value, size, &allocator)); + src_variant.string_array_value->size = size; + src_variant.string_array_value->data[0] = rcutils_strdup("string1", allocator); + src_variant.string_array_value->data[1] = rcutils_strdup("string2", allocator); + src_variant.string_array_value->data[2] = rcutils_strdup("string3", allocator); + for (size_t i = 0; i < size; ++i) { + ASSERT_NE(nullptr, src_variant.string_array_value->data[i]); + } + EXPECT_TRUE(rcl_yaml_variant_copy(&dest_variant, &src_variant, allocator)); + ASSERT_NE(nullptr, dest_variant.string_array_value); + ASSERT_NE(nullptr, dest_variant.string_array_value->data); + for (size_t i = 0; i < size; ++i) { + SCOPED_TRACE(i); + EXPECT_STREQ( + src_variant.string_array_value->data[i], dest_variant.string_array_value->data[i]); + } +}