Skip to content

Commit 8bbc39f

Browse files
authored
Support annotations on TraceOutput (#400)
Signed-off-by: Juan Cruz Viotti <jv@jviotti.com>
1 parent b67a045 commit 8bbc39f

3 files changed

Lines changed: 87 additions & 15 deletions

File tree

src/compiler/compile_output_trace.cc

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,23 +33,32 @@ auto TraceOutput::operator()(
3333
const EvaluationType type, const bool result, const Instruction &step,
3434
const sourcemeta::core::WeakPointer &evaluate_path,
3535
const sourcemeta::core::WeakPointer &instance_location,
36-
const sourcemeta::core::JSON &) -> void {
36+
const sourcemeta::core::JSON &annotation) -> void {
3737

3838
const auto short_step_name{step_name(step)};
3939
auto effective_evaluate_path{evaluate_path.resolve_from(this->base_)};
4040

41-
if (type == EvaluationType::Pre) {
41+
if (is_annotation(step.type)) {
42+
if (type == EvaluationType::Pre) {
43+
return;
44+
} else {
45+
this->output.push_back({EntryType::Annotation, short_step_name,
46+
instance_location,
47+
std::move(effective_evaluate_path),
48+
step.keyword_location, annotation});
49+
}
50+
} else if (type == EvaluationType::Pre) {
4251
this->output.push_back({EntryType::Push, short_step_name, instance_location,
4352
std::move(effective_evaluate_path),
44-
step.keyword_location});
53+
step.keyword_location, std::nullopt});
4554
} else if (result) {
4655
this->output.push_back({EntryType::Pass, short_step_name, instance_location,
4756
std::move(effective_evaluate_path),
48-
step.keyword_location});
57+
step.keyword_location, std::nullopt});
4958
} else {
5059
this->output.push_back({EntryType::Fail, short_step_name, instance_location,
5160
std::move(effective_evaluate_path),
52-
step.keyword_location});
61+
step.keyword_location, std::nullopt});
5362
}
5463
}
5564

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,7 @@ class SOURCEMETA_BLAZE_COMPILER_EXPORT TraceOutput {
177177
const sourcemeta::core::WeakPointer instance_location;
178178
const sourcemeta::core::WeakPointer evaluate_path;
179179
const std::string keyword_location;
180+
const std::optional<sourcemeta::core::JSON> annotation;
180181
};
181182

182183
auto operator()(const EvaluationType type, const bool result,

test/compiler/compiler_output_trace_test.cc

Lines changed: 72 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
#define EXPECT_OUTPUT(traces, index, expected_type, expected_name, \
1010
expected_instance_location, expected_evaluate_path, \
11-
expected_keyword_location) \
11+
expected_keyword_location, expected_annotation) \
1212
EXPECT_TRUE(traces.size() > index); \
1313
EXPECT_EQ(traces.at((index)).type, \
1414
sourcemeta::blaze::TraceOutput::EntryType::expected_type); \
@@ -17,7 +17,16 @@
1717
expected_instance_location); \
1818
EXPECT_EQ(sourcemeta::core::to_string(traces.at((index)).evaluate_path), \
1919
expected_evaluate_path); \
20-
EXPECT_EQ(traces.at((index)).keyword_location, (expected_keyword_location));
20+
EXPECT_EQ(traces.at((index)).keyword_location, (expected_keyword_location)); \
21+
if (std::optional<sourcemeta::core::JSON>{expected_annotation} \
22+
.has_value()) { \
23+
EXPECT_TRUE(traces.at((index)).annotation.has_value()); \
24+
EXPECT_EQ( \
25+
traces.at((index)).annotation.value(), \
26+
std::optional<sourcemeta::core::JSON>{expected_annotation}.value()); \
27+
} else { \
28+
EXPECT_FALSE(traces.at((index)).annotation.has_value()); \
29+
}
2130

2231
TEST(Compiler_output_trace, pass_1) {
2332
const sourcemeta::core::JSON schema{sourcemeta::core::parse_json(R"JSON({
@@ -51,13 +60,64 @@ TEST(Compiler_output_trace, pass_1) {
5160
EXPECT_EQ(traces.size(), 4);
5261

5362
EXPECT_OUTPUT(traces, 0, Push, "LoopPropertiesMatchClosed", "", "/properties",
54-
"#/properties");
63+
"#/properties", std::nullopt);
5564
EXPECT_OUTPUT(traces, 1, Push, "AssertionTypeStrict", "/foo",
56-
"/properties/foo/type", "#/properties/foo/type");
65+
"/properties/foo/type", "#/properties/foo/type", std::nullopt);
5766
EXPECT_OUTPUT(traces, 2, Pass, "AssertionTypeStrict", "/foo",
58-
"/properties/foo/type", "#/properties/foo/type");
67+
"/properties/foo/type", "#/properties/foo/type", std::nullopt);
5968
EXPECT_OUTPUT(traces, 3, Pass, "LoopPropertiesMatchClosed", "", "/properties",
60-
"#/properties");
69+
"#/properties", std::nullopt);
70+
}
71+
72+
TEST(Compiler_output_trace, pass_annotations) {
73+
const sourcemeta::core::JSON schema{sourcemeta::core::parse_json(R"JSON({
74+
"$schema": "https://json-schema.org/draft/2020-12/schema",
75+
"title": "Foo Bar",
76+
"additionalProperties": false,
77+
"properties": {
78+
"foo": true,
79+
"bar": true
80+
}
81+
})JSON")};
82+
83+
const auto schema_template{sourcemeta::blaze::compile(
84+
schema, sourcemeta::core::schema_official_walker,
85+
sourcemeta::core::schema_official_resolver,
86+
sourcemeta::blaze::default_schema_compiler,
87+
sourcemeta::blaze::Mode::Exhaustive)};
88+
89+
const sourcemeta::core::JSON instance{sourcemeta::core::parse_json(R"JSON({
90+
"foo": "bar",
91+
"bar": "baz"
92+
})JSON")};
93+
94+
sourcemeta::blaze::TraceOutput output;
95+
sourcemeta::blaze::Evaluator evaluator;
96+
const auto result{
97+
evaluator.validate(schema_template, instance, std::ref(output))};
98+
99+
EXPECT_TRUE(result);
100+
std::vector<sourcemeta::blaze::TraceOutput::Entry> traces{output.cbegin(),
101+
output.cend()};
102+
103+
EXPECT_EQ(traces.size(), 7);
104+
105+
EXPECT_OUTPUT(traces, 0, Annotation, "AnnotationEmit", "", "/title",
106+
"#/title", sourcemeta::core::JSON{"Foo Bar"});
107+
EXPECT_OUTPUT(traces, 1, Push, "LoopPropertiesMatch", "", "/properties",
108+
"#/properties", std::nullopt);
109+
EXPECT_OUTPUT(traces, 2, Annotation, "AnnotationEmit", "", "/properties",
110+
"#/properties", sourcemeta::core::JSON{"foo"});
111+
EXPECT_OUTPUT(traces, 3, Annotation, "AnnotationEmit", "", "/properties",
112+
"#/properties", sourcemeta::core::JSON{"bar"});
113+
EXPECT_OUTPUT(traces, 4, Pass, "LoopPropertiesMatch", "", "/properties",
114+
"#/properties", std::nullopt);
115+
EXPECT_OUTPUT(traces, 5, Push, "LoopPropertiesExcept", "",
116+
"/additionalProperties", "#/additionalProperties",
117+
std::nullopt);
118+
EXPECT_OUTPUT(traces, 6, Pass, "LoopPropertiesExcept", "",
119+
"/additionalProperties", "#/additionalProperties",
120+
std::nullopt);
61121
}
62122

63123
TEST(Compiler_output_trace, pass_with_matching_prefix_1) {
@@ -98,11 +158,13 @@ TEST(Compiler_output_trace, pass_with_matching_prefix_1) {
98158
EXPECT_EQ(traces.size(), 4);
99159

100160
EXPECT_OUTPUT(traces, 0, Push, "LoopPropertiesMatchClosed", "", "/properties",
101-
"#/$defs/helper/properties");
161+
"#/$defs/helper/properties", std::nullopt);
102162
EXPECT_OUTPUT(traces, 1, Push, "AssertionTypeStrict", "/foo",
103-
"/properties/foo/type", "#/$defs/helper/properties/foo/type");
163+
"/properties/foo/type", "#/$defs/helper/properties/foo/type",
164+
std::nullopt);
104165
EXPECT_OUTPUT(traces, 2, Pass, "AssertionTypeStrict", "/foo",
105-
"/properties/foo/type", "#/$defs/helper/properties/foo/type");
166+
"/properties/foo/type", "#/$defs/helper/properties/foo/type",
167+
std::nullopt);
106168
EXPECT_OUTPUT(traces, 3, Pass, "LoopPropertiesMatchClosed", "", "/properties",
107-
"#/$defs/helper/properties");
169+
"#/$defs/helper/properties", std::nullopt);
108170
}

0 commit comments

Comments
 (0)