Skip to content

Commit 2c03d3c

Browse files
authored
Fix incorrect contains annotations reported by SimpleOutput (#420)
Signed-off-by: Juan Cruz Viotti <jv@jviotti.com>
1 parent 910bbea commit 2c03d3c

3 files changed

Lines changed: 141 additions & 9 deletions

File tree

src/compiler/compile_output_simple.cc

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -58,13 +58,28 @@ auto SimpleOutput::operator()(
5858
// To ease the output
5959
if (keyword == "anyOf" || keyword == "oneOf" || keyword == "not" ||
6060
keyword == "if") {
61-
this->mask.insert(evaluate_path);
61+
this->mask.emplace(evaluate_path, true);
62+
} else if (keyword == "contains") {
63+
this->mask.emplace(evaluate_path, false);
6264
}
6365
} else if (type == EvaluationType::Post &&
6466
this->mask.contains(evaluate_path)) {
6567
this->mask.erase(evaluate_path);
66-
} else if (type == EvaluationType::Post && !result &&
67-
!this->annotations_.empty()) {
68+
}
69+
70+
if (result) {
71+
return;
72+
}
73+
74+
if (std::any_of(this->mask.cbegin(), this->mask.cend(),
75+
[&evaluate_path](const auto &entry) {
76+
return evaluate_path.starts_with(entry.first) &&
77+
!entry.second;
78+
})) {
79+
return;
80+
}
81+
82+
if (type == EvaluationType::Post && !this->annotations_.empty()) {
6883
for (auto iterator = this->annotations_.begin();
6984
iterator != this->annotations_.end();) {
7085
if (iterator->first.evaluate_path.starts_with_initial(evaluate_path)) {
@@ -75,11 +90,10 @@ auto SimpleOutput::operator()(
7590
}
7691
}
7792

78-
// Ignore successful or masked steps
79-
if (result || std::any_of(this->mask.cbegin(), this->mask.cend(),
80-
[&evaluate_path](const auto &entry) {
81-
return evaluate_path.starts_with(entry);
82-
})) {
93+
if (std::any_of(this->mask.cbegin(), this->mask.cend(),
94+
[&evaluate_path](const auto &entry) {
95+
return evaluate_path.starts_with(entry.first);
96+
})) {
8397
return;
8498
}
8599

src/compiler/include/sourcemeta/blaze/compiler_output.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ class SOURCEMETA_BLAZE_COMPILER_EXPORT SimpleOutput {
122122
const sourcemeta::core::JSON &instance_;
123123
const sourcemeta::core::WeakPointer base_;
124124
container_type output;
125-
std::set<sourcemeta::core::WeakPointer> mask;
125+
std::map<sourcemeta::core::WeakPointer, bool> mask;
126126
std::map<Location, std::vector<sourcemeta::core::JSON>> annotations_;
127127
#if defined(_MSC_VER)
128128
#pragma warning(default : 4251)

test/compiler/compiler_output_simple_test.cc

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -620,6 +620,124 @@ TEST(Compiler_output_simple, annotations_success_3) {
620620
EXPECT_ANNOTATION_COUNT(output, 0);
621621
}
622622

623+
TEST(Compiler_output_simple, annotations_success_4) {
624+
const sourcemeta::core::JSON schema{sourcemeta::core::parse_json(R"JSON({
625+
"$schema": "https://json-schema.org/draft/2020-12/schema",
626+
"contains": { "type": "boolean" }
627+
})JSON")};
628+
629+
const auto schema_template{sourcemeta::blaze::compile(
630+
schema, sourcemeta::core::schema_official_walker,
631+
sourcemeta::core::schema_official_resolver,
632+
sourcemeta::blaze::default_schema_compiler,
633+
sourcemeta::blaze::Mode::Exhaustive)};
634+
635+
const sourcemeta::core::JSON instance{
636+
sourcemeta::core::parse_json("[ false, 1, true, 2 ]")};
637+
638+
sourcemeta::blaze::SimpleOutput output{instance};
639+
sourcemeta::blaze::Evaluator evaluator;
640+
const auto result{
641+
evaluator.validate(schema_template, instance, std::ref(output))};
642+
EXPECT_TRUE(result);
643+
644+
EXPECT_ANNOTATION_COUNT(output, 1);
645+
646+
EXPECT_ANNOTATION_ENTRY(output, "", "/contains", "#/contains", 2);
647+
EXPECT_ANNOTATION_VALUE(output, "", "/contains", "#/contains", 0,
648+
sourcemeta::core::JSON{0});
649+
EXPECT_ANNOTATION_VALUE(output, "", "/contains", "#/contains", 1,
650+
sourcemeta::core::JSON{2});
651+
}
652+
653+
TEST(Compiler_output_simple, annotations_success_5) {
654+
const sourcemeta::core::JSON schema{sourcemeta::core::parse_json(R"JSON({
655+
"$schema": "https://json-schema.org/draft/2020-12/schema",
656+
"contains": { "type": "boolean" }
657+
})JSON")};
658+
659+
const auto schema_template{sourcemeta::blaze::compile(
660+
schema, sourcemeta::core::schema_official_walker,
661+
sourcemeta::core::schema_official_resolver,
662+
sourcemeta::blaze::default_schema_compiler,
663+
sourcemeta::blaze::Mode::Exhaustive)};
664+
665+
const sourcemeta::core::JSON instance{
666+
sourcemeta::core::parse_json("[ false, 1, true ]")};
667+
668+
sourcemeta::blaze::SimpleOutput output{instance};
669+
sourcemeta::blaze::Evaluator evaluator;
670+
const auto result{
671+
evaluator.validate(schema_template, instance, std::ref(output))};
672+
EXPECT_TRUE(result);
673+
674+
EXPECT_ANNOTATION_COUNT(output, 1);
675+
676+
EXPECT_ANNOTATION_ENTRY(output, "", "/contains", "#/contains", 2);
677+
EXPECT_ANNOTATION_VALUE(output, "", "/contains", "#/contains", 0,
678+
sourcemeta::core::JSON{0});
679+
EXPECT_ANNOTATION_VALUE(output, "", "/contains", "#/contains", 1,
680+
sourcemeta::core::JSON{2});
681+
}
682+
683+
TEST(Compiler_output_simple, annotations_success_6) {
684+
const sourcemeta::core::JSON schema{sourcemeta::core::parse_json(R"JSON({
685+
"$schema": "https://json-schema.org/draft/2020-12/schema",
686+
"contains": { "type": "boolean" }
687+
})JSON")};
688+
689+
const auto schema_template{sourcemeta::blaze::compile(
690+
schema, sourcemeta::core::schema_official_walker,
691+
sourcemeta::core::schema_official_resolver,
692+
sourcemeta::blaze::default_schema_compiler,
693+
sourcemeta::blaze::Mode::Exhaustive)};
694+
695+
const sourcemeta::core::JSON instance{
696+
sourcemeta::core::parse_json("[ false, true ]")};
697+
698+
sourcemeta::blaze::SimpleOutput output{instance};
699+
sourcemeta::blaze::Evaluator evaluator;
700+
const auto result{
701+
evaluator.validate(schema_template, instance, std::ref(output))};
702+
EXPECT_TRUE(result);
703+
704+
EXPECT_ANNOTATION_COUNT(output, 1);
705+
706+
EXPECT_ANNOTATION_ENTRY(output, "", "/contains", "#/contains", 2);
707+
EXPECT_ANNOTATION_VALUE(output, "", "/contains", "#/contains", 0,
708+
sourcemeta::core::JSON{0});
709+
EXPECT_ANNOTATION_VALUE(output, "", "/contains", "#/contains", 1,
710+
sourcemeta::core::JSON{1});
711+
}
712+
713+
TEST(Compiler_output_simple, annotations_success_7) {
714+
const sourcemeta::core::JSON schema{sourcemeta::core::parse_json(R"JSON({
715+
"$schema": "https://json-schema.org/draft/2020-12/schema",
716+
"contains": { "type": "boolean" }
717+
})JSON")};
718+
719+
const auto schema_template{sourcemeta::blaze::compile(
720+
schema, sourcemeta::core::schema_official_walker,
721+
sourcemeta::core::schema_official_resolver,
722+
sourcemeta::blaze::default_schema_compiler,
723+
sourcemeta::blaze::Mode::Exhaustive)};
724+
725+
const sourcemeta::core::JSON instance{
726+
sourcemeta::core::parse_json("[ false ]")};
727+
728+
sourcemeta::blaze::SimpleOutput output{instance};
729+
sourcemeta::blaze::Evaluator evaluator;
730+
const auto result{
731+
evaluator.validate(schema_template, instance, std::ref(output))};
732+
EXPECT_TRUE(result);
733+
734+
EXPECT_ANNOTATION_COUNT(output, 1);
735+
736+
EXPECT_ANNOTATION_ENTRY(output, "", "/contains", "#/contains", 1);
737+
EXPECT_ANNOTATION_VALUE(output, "", "/contains", "#/contains", 0,
738+
sourcemeta::core::JSON{0});
739+
}
740+
623741
TEST(Compiler_output_simple, annotations_failure_1) {
624742
const sourcemeta::core::JSON schema{sourcemeta::core::parse_json(R"JSON({
625743
"$schema": "https://json-schema.org/draft/2020-12/schema",

0 commit comments

Comments
 (0)