Skip to content

Commit cb3284f

Browse files
committed
Return error on invalid YAML fields
1 parent 50277e3 commit cb3284f

File tree

4 files changed

+41
-0
lines changed

4 files changed

+41
-0
lines changed

dynmsg/include/dynmsg/msg_parser.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ namespace c
3434
* representation for the given ROS message.
3535
*
3636
* It is an error for the YAML representation to contain a field that is not in the ROS message.
37+
* An std::runtime_error exception will be thrown in this case.
38+
*
3739
* It is not an error for a field of the ROS message to not be specified in the YAML
3840
* representation; that field will be left uninitialised.
3941
*/

dynmsg/src/msg_parser_c.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include <yaml-cpp/yaml.h>
1616

1717
#include <string>
18+
#include <unordered_set>
1819

1920
#include "rosidl_runtime_c/string.h"
2021
#include "rosidl_runtime_c/string_functions.h"
@@ -413,12 +414,23 @@ void yaml_to_rosmsg_impl(
413414
const TypeInfo * typeinfo,
414415
uint8_t * buffer)
415416
{
417+
// Put all the YAML node keys into a set. We'll be removing the keys from the set as they are parsed. If at the end
418+
// there are some keys left in the set, it means the YAML has extra fields that don't belong to the message, and an
419+
// exception will be thrown.
420+
std::unordered_set<std::string> yaml_keys;
421+
for (const auto& elem : root)
422+
{
423+
yaml_keys.insert(elem.first.as<std::string>());
424+
}
425+
426+
416427
for (uint32_t i = 0; i < typeinfo->member_count_; i++) {
417428
const auto & member = typeinfo->members_[i];
418429

419430
if (!root[member.name_]) {
420431
continue;
421432
}
433+
yaml_keys.erase(member.name_);
422434

423435
switch (member.type_id_) {
424436
case rosidl_typesupport_introspection_c__ROS_TYPE_FLOAT:
@@ -480,6 +492,9 @@ void yaml_to_rosmsg_impl(
480492
throw std::runtime_error("unknown type");
481493
}
482494
}
495+
if (!yaml_keys.empty()) {
496+
throw std::runtime_error("Found unknown fields in the YAML not corresponding to the given message.");
497+
}
483498
}
484499

485500
} // namespace impl

dynmsg/src/msg_parser_cpp.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include <iostream>
1919
#include <string>
2020
#include <vector>
21+
#include <unordered_set>
2122

2223
#include "rosidl_runtime_c/string.h"
2324
#include "rosidl_runtime_c/string_functions.h"
@@ -502,6 +503,15 @@ void yaml_to_rosmsg_impl(
502503
const TypeInfo_Cpp * typeinfo,
503504
uint8_t * buffer)
504505
{
506+
// Put all the YAML node keys into a set. We'll be removing the keys from the set as they are
507+
// parsed. If at the end there are some keys left in the set, it means the YAML has extra fields
508+
// that don't belong to the message, and an exception will be thrown.
509+
std::unordered_set<std::string> yaml_keys;
510+
for (const auto& elem : root)
511+
{
512+
yaml_keys.insert(elem.first.as<std::string>());
513+
}
514+
505515
DYNMSG_DEBUG(std::cout << "DEBUG: yaml_to_rosmsg_impl" << std::endl);
506516
DYNMSG_DEBUG(
507517
std::cout << "DEBUG: type_info message_namespace_: " <<
@@ -514,6 +524,7 @@ void yaml_to_rosmsg_impl(
514524
if (!root[member.name_]) {
515525
continue;
516526
}
527+
yaml_keys.erase(member.name_);
517528

518529
switch (member.type_id_) {
519530
case rosidl_typesupport_introspection_cpp::ROS_TYPE_FLOAT:
@@ -575,6 +586,9 @@ void yaml_to_rosmsg_impl(
575586
throw std::runtime_error("unknown type");
576587
}
577588
}
589+
if (!yaml_keys.empty()) {
590+
throw std::runtime_error("Found unknown fields in the YAML not corresponding to the given message.");
591+
}
578592
}
579593

580594
} // namespace impl

dynmsg_demo/test/msg_parser_test.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,16 @@ TEST(MsgParser, String) {
126126
dynmsg::c::ros_message_destroy(&generic_msg);
127127
}
128128

129+
TEST(MsgParser, StringInvalidFieldCpp) {
130+
EXPECT_ANY_THROW(dynmsg::cpp::yaml_to_rosmsg(
131+
InterfaceTypeName{"std_msgs", "String"}, "{ invalid_field: hello }"));
132+
}
133+
134+
TEST(MsgParser, StringInvalidFieldC) {
135+
EXPECT_ANY_THROW(dynmsg::c::yaml_to_rosmsg(
136+
InterfaceTypeName{"std_msgs", "String"}, "{ invalid_field: hello }"));
137+
}
138+
129139
TEST(MsgParser, WideString) {
130140
auto generic_msg = dynmsg::c::yaml_to_rosmsg(
131141
InterfaceTypeName{"dynmsg_msgs", "WideString"},

0 commit comments

Comments
 (0)