Skip to content

Commit 55c1c2e

Browse files
Update property tree to leverage nested exceptions during validation
1 parent ee53e44 commit 55c1c2e

File tree

3 files changed

+50
-37
lines changed

3 files changed

+50
-37
lines changed

tesseract_common/include/tesseract_common/property_tree.h

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,13 @@ constexpr std::string_view MAXIMUM{ "maximum" };
2929
class PropertyTree
3030
{
3131
public:
32-
using ValidatorFn = std::function<bool(const PropertyTree&, std::vector<std::string>&, const std::string&)>;
32+
using ValidatorFn = std::function<void(const PropertyTree&)>;
3333

3434
PropertyTree() = default;
3535

3636
void mergeSchema(const PropertyTree& schema);
3737

38-
bool validate(std::vector<std::string>& errors, const std::string& path = "") const;
38+
void validate() const;
3939

4040
void addValidator(ValidatorFn fn);
4141

@@ -69,11 +69,11 @@ class PropertyTree
6969
std::vector<ValidatorFn> validators_;
7070
};
7171

72-
bool validateRequired(const PropertyTree& node, std::vector<std::string>& errors, const std::string& path);
72+
void validateRequired(const PropertyTree& node);
7373

74-
bool validateRange(const PropertyTree& node, std::vector<std::string>& errors, const std::string& path);
74+
void validateRange(const PropertyTree& node);
7575

76-
bool validateEnum(const PropertyTree& node, std::vector<std::string>& errors, const std::string& path);
76+
void validateEnum(const PropertyTree& node);
7777

7878
} // namespace tesseract_common
7979

tesseract_common/src/property_tree.cpp

Lines changed: 19 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -42,23 +42,24 @@ void PropertyTree::mergeSchema(const PropertyTree& schema)
4242
}
4343
}
4444

45-
bool PropertyTree::validate(std::vector<std::string>& errors, const std::string& path) const
45+
void PropertyTree::validate() const
4646
{
47-
bool ok = true;
4847
// run custom validators
4948
for (const auto& vfn : validators_)
50-
{
51-
if (!vfn(*this, errors, path))
52-
ok = false;
53-
}
49+
vfn(*this);
50+
5451
// recurse children
5552
for (const auto& kv : children_)
5653
{
57-
const std::string nextPath = path.empty() ? kv.first : path + "." + kv.first;
58-
if (!kv.second.validate(errors, nextPath))
59-
ok = false;
54+
try
55+
{
56+
kv.second.validate();
57+
}
58+
catch (...)
59+
{
60+
std::throw_with_nested(std::runtime_error("Validation failed for property: " + kv.first));
61+
}
6062
}
61-
return ok;
6263
}
6364

6465
/// Add a custom validator for this node
@@ -184,22 +185,18 @@ YAML::Node PropertyTree::toYAML() const
184185
return value_;
185186
}
186187

187-
bool validateRequired(const PropertyTree& node, std::vector<std::string>& errors, const std::string& path)
188+
void validateRequired(const PropertyTree& node)
188189
{
189190
auto req_attr = node.getAttribute(property_attribute::REQUIRED);
190191
if (req_attr && req_attr->as<bool>())
191192
{
192193
// if leaf node with no value or null
193194
if (!node.getValue() || node.getValue().IsNull())
194-
{
195-
errors.push_back(path + ": required property missing or null");
196-
return false;
197-
}
195+
std::throw_with_nested(std::runtime_error("Required property missing or null"));
198196
}
199-
return true;
200197
}
201198

202-
bool validateRange(const PropertyTree& node, std::vector<std::string>& errors, const std::string& path)
199+
void validateRange(const PropertyTree& node)
203200
{
204201
auto min_attr = node.getAttribute(property_attribute::MINIMUM);
205202
auto max_attr = node.getAttribute(property_attribute::MAXIMUM);
@@ -210,15 +207,13 @@ bool validateRange(const PropertyTree& node, std::vector<std::string>& errors, c
210207
const auto val = node.getValue().as<double>();
211208
if (val < minv || val > maxv)
212209
{
213-
errors.push_back(path + ": value " + std::to_string(val) + " out of range [" + std::to_string(minv) + "," +
214-
std::to_string(maxv) + "]");
215-
return false;
210+
std::throw_with_nested(std::runtime_error("Property value " + std::to_string(val) + " out of range [" +
211+
std::to_string(minv) + "," + std::to_string(maxv) + "]"));
216212
}
217213
}
218-
return true;
219214
}
220215

221-
bool validateEnum(const PropertyTree& node, std::vector<std::string>& errors, const std::string& path)
216+
void validateEnum(const PropertyTree& node)
222217
{
223218
auto enum_attr = node.getAttribute(property_attribute::ENUM);
224219
if (enum_attr.has_value() && enum_attr->IsSequence())
@@ -227,12 +222,10 @@ bool validateEnum(const PropertyTree& node, std::vector<std::string>& errors, co
227222
for (const auto& v : enum_attr.value())
228223
{
229224
if (v.as<std::string>() == val)
230-
return true;
225+
return;
231226
}
232-
errors.push_back(path + ": value '" + val + "' not in enum list");
233-
return false;
227+
std::throw_with_nested(std::runtime_error("Property value '" + val + "' not in enum list"));
234228
}
235-
return true;
236229
}
237230

238231
} // namespace tesseract_common

tesseract_common/src/property_tree_demo.cpp

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#include <iostream>
22
#include <yaml-cpp/yaml.h>
33
#include <tesseract_common/property_tree.h>
4+
#include <tesseract_common/utils.h>
45

56
using namespace tesseract_common;
67

@@ -68,6 +69,7 @@ PropertyTree buildConfigSchema()
6869
auto& prop = outs.get("program");
6970
prop.setAttribute("type", property_type::STRING);
7071
prop.setAttribute("required", true);
72+
prop.addValidator(validateRequired);
7173
}
7274
// format_result_as_input
7375
{
@@ -97,10 +99,19 @@ std::string str2 = R"(config:
9799
outputs:
98100
program: output_data)";
99101

102+
std::string str3 = R"(config:
103+
conditional: true
104+
inputs:
105+
program: input_data
106+
environment: environment
107+
profiles: profiles
108+
outputs:
109+
programs: output_data)";
110+
100111
int main()
101112
{
102113
// Load configuration from YAML
103-
PropertyTree prop = PropertyTree::fromYAML(YAML::Load(str2));
114+
PropertyTree prop = PropertyTree::fromYAML(YAML::Load(str3));
104115

105116
// Parse schema from external file (config_schema.yaml)
106117
PropertyTree schema = buildConfigSchema();
@@ -109,14 +120,23 @@ int main()
109120
prop.mergeSchema(schema);
110121
std::cout << prop.toYAML() << "\n";
111122

112-
std::vector<std::string> errors;
113-
if (!prop.validate(errors, "config"))
123+
try
114124
{
115-
std::cerr << "Validation errors:\n";
116-
for (auto const& e : errors)
117-
std::cerr << " - " << e << "\n";
125+
prop.validate();
126+
}
127+
catch (const std::exception& e)
128+
{
129+
tesseract_common::printNestedException(e);
118130
return 1;
119131
}
132+
133+
// if (!prop.validate(errors, "config"))
134+
// {
135+
// std::cerr << "Validation errors:\n";
136+
// for (auto const& e : errors)
137+
// std::cerr << " - " << e << "\n";
138+
// return 1;
139+
// }
120140
bool cond = prop.get("config").get("conditional").getValue().as<bool>();
121141
std::cout << "conditional = " << std::boolalpha << cond << "\n";
122142
return 0;

0 commit comments

Comments
 (0)