Skip to content

Commit 1c21a98

Browse files
Add string array to lexical casts (#2333) (#2335)
(cherry picked from commit 4d3362d) Co-authored-by: Jordan Palacios <[email protected]>
1 parent 43714af commit 1c21a98

File tree

4 files changed

+133
-0
lines changed

4 files changed

+133
-0
lines changed

hardware_interface/CMakeLists.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,10 @@ if(BUILD_TESTING)
9090
ament_add_gmock(test_helpers test/test_helpers.cpp)
9191
target_link_libraries(test_helpers hardware_interface)
9292

93+
# Test lexical casts methods
94+
ament_add_gtest(test_lexical_casts test/test_lexical_casts.cpp)
95+
target_link_libraries(test_lexical_casts hardware_interface)
96+
9397
ament_add_gmock(test_component_interfaces test/test_component_interfaces.cpp)
9498
target_link_libraries(test_component_interfaces hardware_interface ros2_control_test_assets::ros2_control_test_assets)
9599

hardware_interface/include/hardware_interface/lexical_casts.hpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#define HARDWARE_INTERFACE__LEXICAL_CASTS_HPP_
1717

1818
#include <string>
19+
#include <vector>
1920

2021
namespace hardware_interface
2122
{
@@ -29,6 +30,8 @@ double stod(const std::string & s);
2930

3031
bool parse_bool(const std::string & bool_string);
3132

33+
std::vector<std::string> parse_string_array(const std::string & string_array_string);
34+
3235
} // namespace hardware_interface
3336

3437
#endif // HARDWARE_INTERFACE__LEXICAL_CASTS_HPP_

hardware_interface/src/lexical_casts.cpp

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
#include <locale>
1616
#include <optional>
1717
#include <sstream>
18+
#include <string>
19+
#include <vector>
1820

1921
#include "hardware_interface/lexical_casts.hpp"
2022

@@ -48,6 +50,7 @@ std::optional<double> stod(const std::string & s)
4850
#endif
4951
}
5052
} // namespace impl
53+
5154
double stod(const std::string & s)
5255
{
5356
if (const auto result = impl::stod(s))
@@ -56,8 +59,63 @@ double stod(const std::string & s)
5659
}
5760
throw std::invalid_argument("Failed converting string to real number");
5861
}
62+
5963
bool parse_bool(const std::string & bool_string)
6064
{
6165
return bool_string == "true" || bool_string == "True";
6266
}
67+
68+
std::vector<std::string> parse_string_array(const std::string & string_array_string)
69+
{
70+
// Check string starts with '[' and ends with ']'
71+
if (
72+
string_array_string.empty() || string_array_string.front() != '[' ||
73+
string_array_string.back() != ']')
74+
{
75+
throw std::invalid_argument("String must start with '[' and end with ']'");
76+
}
77+
78+
// Check there are no "sub arrays"
79+
if (
80+
string_array_string.find("[") != 0u ||
81+
string_array_string.find("]") != string_array_string.size() - 1u)
82+
{
83+
throw std::invalid_argument("String contains nested arrays");
84+
}
85+
86+
// Check for empty array
87+
if (string_array_string == "[]")
88+
{
89+
return {};
90+
}
91+
92+
std::vector<std::string> result;
93+
std::string current_string;
94+
for (char c : string_array_string)
95+
{
96+
if (c == ',' || c == ']')
97+
{
98+
if (!current_string.empty())
99+
{
100+
result.push_back(current_string);
101+
current_string.clear();
102+
}
103+
else
104+
{
105+
throw std::invalid_argument("Empty string found in array");
106+
}
107+
}
108+
else if (c == '[' || c == ' ')
109+
{
110+
// Ignore opening brackets and spaces
111+
}
112+
else
113+
{
114+
current_string += c; // Add character to current string
115+
}
116+
}
117+
118+
return result;
119+
}
120+
63121
} // namespace hardware_interface
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
// Copyright 2025 PAL Robotics S.L.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
#include <stdexcept>
16+
17+
#include "gtest/gtest.h"
18+
19+
#include "hardware_interface/lexical_casts.hpp"
20+
21+
TEST(TestLexicalCasts, test_stod)
22+
{
23+
using hardware_interface::stod;
24+
25+
ASSERT_THROW(stod(""), std::invalid_argument);
26+
ASSERT_THROW(stod("abc"), std::invalid_argument);
27+
ASSERT_THROW(stod("1.2.3"), std::invalid_argument);
28+
ASSERT_EQ(stod("1.2"), 1.2);
29+
ASSERT_EQ(stod("-1.2"), -1.2);
30+
ASSERT_EQ(stod("1.0"), 1.0);
31+
}
32+
33+
TEST(TestLexicalCasts, test_parse_bool)
34+
{
35+
using hardware_interface::parse_bool;
36+
37+
ASSERT_TRUE(parse_bool("true"));
38+
ASSERT_TRUE(parse_bool("True"));
39+
40+
// Any other value should return false
41+
ASSERT_FALSE(parse_bool("false"));
42+
ASSERT_FALSE(parse_bool("False"));
43+
ASSERT_FALSE(parse_bool(""));
44+
ASSERT_FALSE(parse_bool("abc"));
45+
ASSERT_FALSE(parse_bool("1"));
46+
}
47+
48+
TEST(TestLexicalCasts, test_parse_string_array)
49+
{
50+
using hardware_interface::parse_string_array;
51+
52+
ASSERT_THROW(parse_string_array(""), std::invalid_argument);
53+
ASSERT_THROW(parse_string_array("abc"), std::invalid_argument);
54+
ASSERT_THROW(parse_string_array("[abc"), std::invalid_argument);
55+
ASSERT_THROW(parse_string_array("abc]"), std::invalid_argument);
56+
ASSERT_THROW(parse_string_array("[[abc, def], hij]"), std::invalid_argument);
57+
ASSERT_THROW(parse_string_array("[ ]"), std::invalid_argument);
58+
ASSERT_THROW(parse_string_array("[,]"), std::invalid_argument);
59+
ASSERT_THROW(parse_string_array("[abc,]"), std::invalid_argument);
60+
ASSERT_THROW(parse_string_array("[,abc]"), std::invalid_argument);
61+
ASSERT_THROW(parse_string_array("[abc,,def]"), std::invalid_argument);
62+
63+
ASSERT_EQ(parse_string_array("[]"), std::vector<std::string>());
64+
ASSERT_EQ(parse_string_array("[abc]"), std::vector<std::string>({"abc"}));
65+
ASSERT_EQ(parse_string_array("[abc,def]"), std::vector<std::string>({"abc", "def"}));
66+
ASSERT_EQ(parse_string_array("[abc, def]"), std::vector<std::string>({"abc", "def"}));
67+
ASSERT_EQ(parse_string_array("[ abc, def ]"), std::vector<std::string>({"abc", "def"}));
68+
}

0 commit comments

Comments
 (0)