Skip to content

Commit b8e682a

Browse files
authored
Add tf prefix helper and test (#2803) (#2867)
1 parent f17fcef commit b8e682a

File tree

4 files changed

+139
-0
lines changed

4 files changed

+139
-0
lines changed

controller_interface/CMakeLists.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,11 @@ if(BUILD_TESTING)
117117
hardware_interface::hardware_interface
118118
${std_msgs_TARGETS}
119119
)
120+
121+
ament_add_gmock(test_controller_tf_prefix test/test_controller_tf_prefix.cpp)
122+
target_link_libraries(test_controller_tf_prefix
123+
controller_interface
124+
)
120125
endif()
121126

122127
install(
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
// Copyright (c) 2025, ros2_control developers
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+
#ifndef CONTROLLER_INTERFACE__TF_PREFIX_HPP_
16+
#define CONTROLLER_INTERFACE__TF_PREFIX_HPP_
17+
18+
#include <string>
19+
20+
namespace controller_interface
21+
{
22+
/**
23+
* @brief Resolve the TF prefix with normalized slashes
24+
* @param prefix The TF prefix
25+
* @param node_ns Node namespace to use as prefix if prefix is empty
26+
* @return Prefix to be prepended
27+
*/
28+
inline std::string resolve_tf_prefix(const std::string & prefix, const std::string & node_ns)
29+
{
30+
if (prefix.empty())
31+
{
32+
return "";
33+
}
34+
35+
std::string nprefix = prefix;
36+
std::size_t pos = nprefix.find("~");
37+
if (pos != std::string::npos)
38+
{
39+
nprefix.replace(pos, 1, node_ns);
40+
}
41+
42+
// ensure trailing '/'
43+
if (nprefix.back() != '/')
44+
{
45+
nprefix.push_back('/');
46+
}
47+
// remove leading '/'
48+
if (nprefix.front() == '/')
49+
{
50+
nprefix.erase(0, 1);
51+
}
52+
return nprefix;
53+
}
54+
} // namespace controller_interface
55+
56+
#endif // CONTROLLER_INTERFACE__TF_PREFIX_HPP_
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
// Copyright (c) 2025, ros2_control developers
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 <gmock/gmock.h>
16+
17+
#include "controller_interface/tf_prefix.hpp"
18+
#include "test_controller_tf_prefix.hpp"
19+
20+
TEST_F(TestControllerTFPrefix, EmptyPrefixReturnsEmpty)
21+
{
22+
EXPECT_EQ(controller_interface::resolve_tf_prefix("", "/ns"), "");
23+
}
24+
25+
TEST_F(TestControllerTFPrefix, ExplicitPrefixUsed)
26+
{
27+
EXPECT_EQ(controller_interface::resolve_tf_prefix("robot", "/ns"), "robot/");
28+
}
29+
30+
TEST_F(TestControllerTFPrefix, NormalizePrefixSlashes)
31+
{
32+
EXPECT_EQ(controller_interface::resolve_tf_prefix("/robot1", "/ns"), "robot1/");
33+
EXPECT_EQ(controller_interface::resolve_tf_prefix("robot2//", "/ns"), "robot2//");
34+
EXPECT_EQ(controller_interface::resolve_tf_prefix("/robot3/", "/ns"), "robot3/");
35+
EXPECT_EQ(controller_interface::resolve_tf_prefix("/", "/ns"), "");
36+
}
37+
38+
TEST_F(TestControllerTFPrefix, TildePrefixResolvesToNamespace)
39+
{
40+
EXPECT_EQ(controller_interface::resolve_tf_prefix("~", "/ns"), "ns/");
41+
EXPECT_EQ(controller_interface::resolve_tf_prefix("~/", "/ns"), "ns/");
42+
EXPECT_EQ(controller_interface::resolve_tf_prefix("~/robot", "/ns"), "ns/robot/");
43+
EXPECT_EQ(controller_interface::resolve_tf_prefix("/~/robot/", "ns"), "ns/robot/");
44+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// Copyright (c) 2025, ros2_control developers
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+
#ifndef TEST_CONTROLLER_TF_PREFIX_HPP_
16+
#define TEST_CONTROLLER_TF_PREFIX_HPP_
17+
18+
#include <gmock/gmock.h>
19+
#include <gtest/gtest.h>
20+
21+
class TestControllerTFPrefix : public ::testing::Test
22+
{
23+
public:
24+
void SetUp() override
25+
{
26+
// placeholder
27+
}
28+
void TearDown() override
29+
{
30+
// placeholder
31+
}
32+
};
33+
34+
#endif // TEST_CONTROLLER_TF_PREFIX_HPP_

0 commit comments

Comments
 (0)