From cd4e256d4ca19e6499e6e68a2bc600650ed12a85 Mon Sep 17 00:00:00 2001 From: brawner Date: Wed, 2 Sep 2020 12:39:46 -0700 Subject: [PATCH] Fix yaml parser error when meets .nan (refactor on #754) (#781) * Fix yaml parser error when meets .nan Signed-off-by: Ada-King Correct code style Signed-off-by: Ada-King Modify as suggested Signed-off-by: Ada-King Improve test Signed-off-by: Ada-King Fix minor flaw Signed-off-by: Ada-King Fix minor flaw again Signed-off-by: Ada-King Satisfy windows CI Signed-off-by: Ada-King Change the match rule for special float Signed-off-by: Ada-King Distinguish +.inf and -.inf Signed-off-by: Ada-King * Remove unnecessary #include change. Signed-off-by: Chris Lalancette * Add in two more necessary includes. Signed-off-by: Chris Lalancette Co-authored-by: Ada-King Co-authored-by: Chris Lalancette --- rcl_yaml_param_parser/src/parse.c | 28 ++++++++++- rcl_yaml_param_parser/test/special_float.yaml | 4 ++ .../test/test_parse_yaml.cpp | 50 ++++++++++++++++++- 3 files changed, 80 insertions(+), 2 deletions(-) create mode 100644 rcl_yaml_param_parser/test/special_float.yaml diff --git a/rcl_yaml_param_parser/src/parse.c b/rcl_yaml_param_parser/src/parse.c index 1632418e2..9db8ac6fa 100644 --- a/rcl_yaml_param_parser/src/parse.c +++ b/rcl_yaml_param_parser/src/parse.c @@ -12,7 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include #include +#include +#include #include "rcutils/allocator.h" #include "rcutils/strdup.h" @@ -116,7 +119,30 @@ void * get_value( { errno = 0; endptr = NULL; - dval = strtod(value, &endptr); + const char * iter_ptr = NULL; + if ((0 == strcmp(value, ".nan")) || + (0 == strcmp(value, ".NaN")) || + (0 == strcmp(value, ".NAN")) || + (0 == strcmp(value, ".inf")) || + (0 == strcmp(value, ".Inf")) || + (0 == strcmp(value, ".INF")) || + (0 == strcmp(value, "+.inf")) || + (0 == strcmp(value, "+.Inf")) || + (0 == strcmp(value, "+.INF")) || + (0 == strcmp(value, "-.inf")) || + (0 == strcmp(value, "-.Inf")) || + (0 == strcmp(value, "-.INF"))) + { + for (iter_ptr = value; !isalpha(*iter_ptr); ) { + iter_ptr += 1; + } + dval = strtod(iter_ptr, &endptr); + if (*value == '-') { + dval = -dval; + } + } else { + dval = strtod(value, &endptr); + } if ((0 == errno) && (NULL != endptr)) { if ((NULL != endptr) && (endptr != value)) { if (('\0' != *value) && ('\0' == *endptr)) { diff --git a/rcl_yaml_param_parser/test/special_float.yaml b/rcl_yaml_param_parser/test/special_float.yaml new file mode 100644 index 000000000..b3215e33d --- /dev/null +++ b/rcl_yaml_param_parser/test/special_float.yaml @@ -0,0 +1,4 @@ +test_node: + ros__parameters: + isstring: [string, .nananan, .nAN, .Nan, .infinf, .INf, .infinity] + nan_inf: [1.1, 2.2, .nan, .NAN, .inf, +.Inf, -.INF] diff --git a/rcl_yaml_param_parser/test/test_parse_yaml.cpp b/rcl_yaml_param_parser/test/test_parse_yaml.cpp index c69114ba5..e7a7f1f15 100644 --- a/rcl_yaml_param_parser/test/test_parse_yaml.cpp +++ b/rcl_yaml_param_parser/test/test_parse_yaml.cpp @@ -12,9 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include #include +#include + #include "osrf_testing_tools_cpp/scope_exit.hpp" #include "rcl_yaml_param_parser/parser.h" @@ -497,6 +498,53 @@ TEST(test_file_parser, maximum_number_parameters) { // No cleanup, rcl_parse_yaml_file takes care of that if it fails. } +// Test special float point(https://github.com/ros2/rcl/issues/555). +TEST(test_file_parser, special_float_point) { + rcutils_reset_error(); + EXPECT_TRUE(rcutils_get_cwd(cur_dir, 1024)) << rcutils_get_error_string().str; + rcutils_allocator_t allocator = rcutils_get_default_allocator(); + char * test_path = rcutils_join_path(cur_dir, "test", allocator); + ASSERT_TRUE(NULL != test_path) << rcutils_get_error_string().str; + OSRF_TESTING_TOOLS_CPP_SCOPE_EXIT( + { + allocator.deallocate(test_path, allocator.state); + }); + char * path = rcutils_join_path(test_path, "special_float.yaml", allocator); + ASSERT_TRUE(NULL != path) << rcutils_get_error_string().str; + OSRF_TESTING_TOOLS_CPP_SCOPE_EXIT( + { + allocator.deallocate(path, allocator.state); + }); + ASSERT_TRUE(rcutils_exists(path)) << "No test YAML file found at " << path; + rcl_params_t * params_hdl = rcl_yaml_node_struct_init(allocator); + ASSERT_TRUE(NULL != params_hdl) << rcutils_get_error_string().str; + OSRF_TESTING_TOOLS_CPP_SCOPE_EXIT( + { + rcl_yaml_node_struct_fini(params_hdl); + }); + + bool res = rcl_parse_yaml_file(path, params_hdl); + EXPECT_TRUE(res) << rcutils_get_error_string().str; + rcl_variant_t * param_value = rcl_yaml_node_struct_get("test_node", "isstring", params_hdl); + ASSERT_TRUE(NULL != param_value) << rcutils_get_error_string().str; + ASSERT_TRUE(NULL != param_value->string_array_value); + EXPECT_STREQ(".nananan", param_value->string_array_value->data[1]); + EXPECT_STREQ(".nAN", param_value->string_array_value->data[2]); + EXPECT_STREQ(".infinf", param_value->string_array_value->data[4]); + EXPECT_STREQ(".INf", param_value->string_array_value->data[5]); + param_value = rcl_yaml_node_struct_get( + "test_node", "nan_inf", params_hdl); + ASSERT_TRUE(NULL != param_value) << rcutils_get_error_string().str; + ASSERT_TRUE(NULL != param_value->double_array_value); + ASSERT_EQ(7U, param_value->double_array_value->size); + EXPECT_FALSE(std::isnan(param_value->double_array_value->values[1])); + EXPECT_TRUE(std::isnan(param_value->double_array_value->values[2])); + EXPECT_TRUE(std::isnan(param_value->double_array_value->values[3])); + EXPECT_TRUE(std::isinf(param_value->double_array_value->values[4])); + EXPECT_TRUE(std::isinf(param_value->double_array_value->values[5])); + EXPECT_TRUE(std::isinf(param_value->double_array_value->values[6])); +} + int32_t main(int32_t argc, char ** argv) { ::testing::InitGoogleTest(&argc, argv);