Skip to content

Commit 3a439bd

Browse files
Csaba Imre Zemplenipboettch
Csaba Imre Zempleni
authored andcommitted
Adding verbose error messages for logical combinations
1 parent e2f3586 commit 3a439bd

File tree

3 files changed

+384
-12
lines changed

3 files changed

+384
-12
lines changed

src/json-validator.cpp

+42-12
Original file line numberDiff line numberDiff line change
@@ -426,6 +426,32 @@ enum logical_combination_types {
426426
oneOf
427427
};
428428

429+
class logical_combination_error_handler : public error_handler
430+
{
431+
public:
432+
struct error_entry
433+
{
434+
json::json_pointer ptr_;
435+
json instance_;
436+
std::string message_;
437+
};
438+
439+
std::vector<error_entry> error_entry_list_;
440+
441+
void error(const json::json_pointer &ptr, const json &instance, const std::string &message) override
442+
{
443+
error_entry_list_.push_back(error_entry{ ptr, instance, message });
444+
}
445+
446+
void propagate(error_handler& e, const std::string& prefix) const
447+
{
448+
for (const error_entry& entry : error_entry_list_)
449+
e.error(entry.ptr_, entry.instance_, prefix + entry.message_);
450+
}
451+
452+
operator bool() const { return !error_entry_list_.empty(); }
453+
};
454+
429455
template <enum logical_combination_types combine_logic>
430456
class logical_combination : public schema
431457
{
@@ -434,29 +460,33 @@ class logical_combination : public schema
434460
void validate(const json::json_pointer &ptr, const json &instance, json_patch &patch, error_handler &e) const final
435461
{
436462
size_t count = 0;
463+
logical_combination_error_handler error_summary;
437464

438-
for (auto &s : subschemata_) {
439-
first_error_handler esub;
465+
for (std::size_t index = 0; index < subschemata_.size(); ++index) {
466+
const std::shared_ptr<schema>& s = subschemata_[index];
467+
logical_combination_error_handler esub;
440468
auto oldPatchSize = patch.get_json().size();
441469
s->validate(ptr, instance, patch, esub);
442470
if (!esub)
443471
count++;
444-
else
472+
else {
445473
patch.get_json().get_ref<nlohmann::json::array_t &>().resize(oldPatchSize);
474+
esub.propagate(error_summary, "case#" + std::to_string(index) + "] ");
475+
}
446476

447477
if (is_validate_complete(instance, ptr, e, esub, count))
448478
return;
449479
}
450480

451-
// could accumulate esub details for anyOf and oneOf, but not clear how to select which subschema failure to report
452-
// or how to report multiple such failures
453-
if (count == 0)
454-
e.error(ptr, instance, "no subschema has succeeded, but one of them is required to validate");
481+
if (count == 0) {
482+
e.error(ptr, instance, "no subschema has succeeded, but one of them is required to validate. Type: " + key + ", number of failed subschemas: " + std::to_string(subschemata_.size()));
483+
error_summary.propagate(e, "[combination: " + key + " / ");
484+
}
455485
}
456486

457487
// specialized for each of the logical_combination_types
458488
static const std::string key;
459-
static bool is_validate_complete(const json &, const json::json_pointer &, error_handler &, const first_error_handler &, size_t);
489+
static bool is_validate_complete(const json &, const json::json_pointer &, error_handler &, const logical_combination_error_handler &, size_t);
460490

461491
public:
462492
logical_combination(json &sch,
@@ -481,21 +511,21 @@ template <>
481511
const std::string logical_combination<oneOf>::key = "oneOf";
482512

483513
template <>
484-
bool logical_combination<allOf>::is_validate_complete(const json &, const json::json_pointer &, error_handler &e, const first_error_handler &esub, size_t)
514+
bool logical_combination<allOf>::is_validate_complete(const json &, const json::json_pointer &, error_handler &e, const logical_combination_error_handler &esub, size_t)
485515
{
486516
if (esub)
487-
e.error(esub.ptr_, esub.instance_, "at least one subschema has failed, but all of them are required to validate - " + esub.message_);
517+
e.error(esub.error_entry_list_.front().ptr_, esub.error_entry_list_.front().instance_, "at least one subschema has failed, but all of them are required to validate - " + esub.error_entry_list_.front().message_);
488518
return esub;
489519
}
490520

491521
template <>
492-
bool logical_combination<anyOf>::is_validate_complete(const json &, const json::json_pointer &, error_handler &, const first_error_handler &, size_t count)
522+
bool logical_combination<anyOf>::is_validate_complete(const json &, const json::json_pointer &, error_handler &, const logical_combination_error_handler &, size_t count)
493523
{
494524
return count == 1;
495525
}
496526

497527
template <>
498-
bool logical_combination<oneOf>::is_validate_complete(const json &instance, const json::json_pointer &ptr, error_handler &e, const first_error_handler &, size_t count)
528+
bool logical_combination<oneOf>::is_validate_complete(const json &instance, const json::json_pointer &ptr, error_handler &e, const logical_combination_error_handler &, size_t count)
499529
{
500530
if (count > 1)
501531
e.error(ptr, instance, "more than one subschema has succeeded, but exactly one of them is required to validate");

test/CMakeLists.txt

+4
Original file line numberDiff line numberDiff line change
@@ -89,3 +89,7 @@ add_test(NAME issue-243-root-default-values COMMAND issue-243-root-default-value
8989
add_executable(issue-255-error-message-limit-precision issue-255-error-message-limit-precision.cpp)
9090
target_link_libraries(issue-255-error-message-limit-precision nlohmann_json_schema_validator)
9191
add_test(NAME issue-255-error-message-limit-precision COMMAND issue-255-error-message-limit-precision)
92+
93+
add_executable(issue-105-verbose-combination-errors issue-105-verbose-combination-errors.cpp)
94+
target_link_libraries(issue-105-verbose-combination-errors nlohmann_json_schema_validator)
95+
add_test(NAME issue-105-verbose-combination-errors COMMAND issue-105-verbose-combination-errors)

0 commit comments

Comments
 (0)