Skip to content

Commit f569658

Browse files
Fix/collection defaults (#33)
* (wip) fix overriding vector defaults * revert default changes and fix map * fix printing issue with newer gtest
1 parent 5553441 commit f569658

File tree

3 files changed

+80
-9
lines changed

3 files changed

+80
-9
lines changed

config_utilities/include/config_utilities/internal/visitor_impl.hpp

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -231,10 +231,15 @@ void Visitor::visitField(std::vector<ConfigT>& config, const std::string& field_
231231
}
232232

233233
if (visitor.mode == Visitor::Mode::kSet) {
234+
const auto array_ns = visitor.name_space.empty() ? field_name : visitor.name_space + "/" + field_name;
235+
const auto subnode = lookupNamespace(visitor.data.data, array_ns);
236+
if (!subnode) {
237+
return; // don't override the field if not present
238+
}
239+
234240
// When setting the values first allocate the correct amount of configs.
235241
config.clear();
236-
const auto array_ns = visitor.name_space.empty() ? field_name : visitor.name_space + "/" + field_name;
237-
const std::vector<YAML::Node> nodes = getNodeArray(lookupNamespace(visitor.data.data, array_ns));
242+
const std::vector<YAML::Node> nodes = getNodeArray(subnode);
238243
size_t index = 0;
239244
for (const auto& node : nodes) {
240245
ConfigT& sub_config = config.emplace_back();
@@ -274,11 +279,8 @@ void Visitor::visitField(std::map<K, ConfigT>& config, const std::string& field_
274279
return;
275280
}
276281

277-
OrderedMap<K, ConfigT> intermediate;
278-
// copy current config state if doing something else other than settings the config
279-
if (visitor.mode != Visitor::Mode::kSet) {
280-
intermediate.insert(intermediate.begin(), config.begin(), config.end());
281-
}
282+
// copy current config state
283+
OrderedMap<K, ConfigT> intermediate(config.begin(), config.end());
282284

283285
// make use of more general named parsing
284286
visitField<K, ConfigT>(intermediate, field_name, unit);
@@ -301,10 +303,15 @@ void Visitor::visitField(OrderedMap<K, ConfigT>& config, const std::string& fiel
301303
}
302304

303305
if (visitor.mode == Visitor::Mode::kSet) {
306+
const auto map_ns = visitor.name_space.empty() ? field_name : visitor.name_space + "/" + field_name;
307+
const auto subnode = lookupNamespace(visitor.data.data, map_ns);
308+
if (!subnode) {
309+
return; // don't override the field if not present
310+
}
311+
304312
// When setting the values first allocate the correct amount of configs.
305313
config.clear();
306-
const auto map_ns = visitor.name_space.empty() ? field_name : visitor.name_space + "/" + field_name;
307-
const auto nodes = getNodeMap(lookupNamespace(visitor.data.data, map_ns));
314+
const auto nodes = getNodeMap(subnode);
308315
for (auto&& [key, node] : nodes) {
309316
auto& entry = config.emplace_back();
310317
entry.first = key.template as<K>();

config_utilities/test/tests/config_arrays.cpp

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,8 @@ class AddString : public ProcessorBase {
105105
config::RegistrationWithConfig<ProcessorBase, AddString, AddString::Config>("AddString");
106106
};
107107

108+
bool operator==(const AddString::Config& lhs, const AddString::Config& rhs) { return lhs.s == rhs.s; }
109+
108110
void declare_config(AddString::Config& config) {
109111
name("AddString");
110112
field(config.s, "s");
@@ -128,6 +130,21 @@ void declare_config(ConfigWithNestedArray& config) {
128130
field(config.nested, "nested");
129131
}
130132

133+
struct ConfigWithDefaultArray {
134+
std::vector<AddString::Config> configs{{"world!"}, {"hello"}};
135+
};
136+
137+
void declare_config(ConfigWithDefaultArray& config) {
138+
name("ConfigWithDefaultArray");
139+
field(config.configs, "configs");
140+
}
141+
142+
bool operator==(const ConfigWithDefaultArray& lhs, const ConfigWithDefaultArray& rhs) {
143+
return lhs.configs == rhs.configs;
144+
}
145+
146+
void PrintTo(const ConfigWithDefaultArray& config, std::ostream* os) { *os << toString(config); }
147+
131148
TEST(ConfigArrays, FromYamlSeq) {
132149
const std::string yaml_seq = R"(
133150
- s: "a"
@@ -407,4 +424,21 @@ config_array[2] [ArrConfig]:
407424
EXPECT_EQ(formatted, expected);
408425
}
409426

427+
TEST(ConfigArrays, ArrayWithDefaults) {
428+
{ // make sure not specifying anything results in default
429+
const auto node = YAML::Load("");
430+
auto config = fromYaml<ConfigWithDefaultArray>(node);
431+
EXPECT_EQ(config.configs.size(), 2);
432+
EXPECT_EQ(config, ConfigWithDefaultArray());
433+
}
434+
435+
{ // specifying empty list clears default
436+
const auto node = YAML::Load("configs: []");
437+
auto config = fromYaml<ConfigWithDefaultArray>(node);
438+
EXPECT_EQ(config.configs.size(), 0);
439+
ConfigWithDefaultArray expected{{}};
440+
EXPECT_EQ(config, expected);
441+
}
442+
}
443+
410444
} // namespace config::test

config_utilities/test/tests/config_maps.cpp

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,19 @@ void declare_config(ConfigWithNestedMaps& config) {
9999
field(config.nested, "nested");
100100
}
101101

102+
struct ConfigWithDefaultMap {
103+
std::map<std::string, MapConfig> configs{{"name1", {"world!", 1}}, {"name2", {"hello", 3}}};
104+
};
105+
106+
void declare_config(ConfigWithDefaultMap& config) {
107+
name("ConfigWithDefaultMap");
108+
field(config.configs, "configs");
109+
}
110+
111+
bool operator==(const ConfigWithDefaultMap& lhs, const ConfigWithDefaultMap& rhs) { return lhs.configs == rhs.configs; }
112+
113+
void PrintTo(const ConfigWithDefaultMap& config, std::ostream* os) { *os << toString(config); }
114+
102115
TEST(ConfigMaps, FromYamlMap) {
103116
const std::string yaml_map = R"(
104117
x:
@@ -278,4 +291,21 @@ config_map[4] [MapConfig]:
278291
EXPECT_EQ(formatted, expected);
279292
}
280293

294+
TEST(ConfigMaps, MapWithDefault) {
295+
{ // make sure not specifying anything results in default
296+
const auto node = YAML::Load("");
297+
auto config = fromYaml<ConfigWithDefaultMap>(node);
298+
EXPECT_EQ(config.configs.size(), 2);
299+
EXPECT_EQ(config, ConfigWithDefaultMap());
300+
}
301+
302+
{ // specifying empty list clears default
303+
const auto node = YAML::Load("configs: {}");
304+
auto config = fromYaml<ConfigWithDefaultMap>(node);
305+
EXPECT_EQ(config.configs.size(), 0);
306+
ConfigWithDefaultMap expected{{}};
307+
EXPECT_EQ(config, expected);
308+
}
309+
}
310+
281311
} // namespace config::test

0 commit comments

Comments
 (0)