diff --git a/rclcpp/src/rclcpp/node.cpp b/rclcpp/src/rclcpp/node.cpp index ba63ce6279..7cc352b019 100644 --- a/rclcpp/src/rclcpp/node.cpp +++ b/rclcpp/src/rclcpp/node.cpp @@ -54,6 +54,12 @@ extend_sub_namespace(const std::string & existing_sub_namespace, const std::stri extension.c_str(), "a sub-namespace should not have a leading /", 0); + } else if (existing_sub_namespace.empty() && extension.empty()) { + throw rclcpp::exceptions::NameValidationError( + "sub_namespace", + extension.c_str(), + "sub-nodes should not extend nodes by an empty sub-namespace", + 0); } std::string new_sub_namespace; @@ -79,7 +85,11 @@ create_effective_namespace(const std::string & node_namespace, const std::string // and do not need trimming of `/` and other things, as they were validated // in other functions already. - if (node_namespace.back() == '/') { + // A node may not have a sub_namespace if it is no sub_node. In this case, + // just return the original namespace + if (sub_namespace.empty()) { + return node_namespace; + } else if (node_namespace.back() == '/') { // this is the special case where node_namespace is just `/` return node_namespace + sub_namespace; } else { diff --git a/rclcpp/test/rclcpp/test_node.cpp b/rclcpp/test/rclcpp/test_node.cpp index 2c52b5264d..ae8b7e23f4 100644 --- a/rclcpp/test/rclcpp/test_node.cpp +++ b/rclcpp/test/rclcpp/test_node.cpp @@ -94,6 +94,7 @@ TEST_F(TestNode, get_name_and_namespace) { auto node = std::make_shared("my_node", "/ns"); EXPECT_STREQ("my_node", node->get_name()); EXPECT_STREQ("/ns", node->get_namespace()); + EXPECT_STREQ("/ns", node->get_effective_namespace().c_str()); EXPECT_STREQ("/ns/my_node", node->get_fully_qualified_name()); } { @@ -108,30 +109,35 @@ TEST_F(TestNode, get_name_and_namespace) { auto node = std::make_shared("my_node", "ns"); EXPECT_STREQ("my_node", node->get_name()); EXPECT_STREQ("/ns", node->get_namespace()); + EXPECT_STREQ("/ns", node->get_effective_namespace().c_str()); EXPECT_STREQ("/ns/my_node", node->get_fully_qualified_name()); } { auto node = std::make_shared("my_node"); EXPECT_STREQ("my_node", node->get_name()); EXPECT_STREQ("/", node->get_namespace()); + EXPECT_STREQ("/", node->get_effective_namespace().c_str()); EXPECT_STREQ("/my_node", node->get_fully_qualified_name()); } { auto node = std::make_shared("my_node", ""); EXPECT_STREQ("my_node", node->get_name()); EXPECT_STREQ("/", node->get_namespace()); + EXPECT_STREQ("/", node->get_effective_namespace().c_str()); EXPECT_STREQ("/my_node", node->get_fully_qualified_name()); } { auto node = std::make_shared("my_node", "/my/ns"); EXPECT_STREQ("my_node", node->get_name()); EXPECT_STREQ("/my/ns", node->get_namespace()); + EXPECT_STREQ("/my/ns", node->get_effective_namespace().c_str()); EXPECT_STREQ("/my/ns/my_node", node->get_fully_qualified_name()); } { auto node = std::make_shared("my_node", "my/ns"); EXPECT_STREQ("my_node", node->get_name()); EXPECT_STREQ("/my/ns", node->get_namespace()); + EXPECT_STREQ("/my/ns", node->get_effective_namespace().c_str()); EXPECT_STREQ("/my/ns/my_node", node->get_fully_qualified_name()); } { @@ -270,6 +276,13 @@ TEST_F(TestNode, subnode_construction_and_destruction) { auto subnode = node->create_sub_node("~sub_ns"); }, rclcpp::exceptions::InvalidNamespaceError); } + { + ASSERT_THROW( + { + auto node = std::make_shared("my_node", "/ns"); + auto subnode = node->create_sub_node(""); + }, rclcpp::exceptions::NameValidationError); + } } TEST_F(TestNode, get_logger) {