Skip to content

Commit

Permalink
Address comments and parsing tests
Browse files Browse the repository at this point in the history
  • Loading branch information
Anilm3 committed Aug 16, 2023
1 parent c9e5486 commit 2e01180
Show file tree
Hide file tree
Showing 2 changed files with 327 additions and 14 deletions.
25 changes: 12 additions & 13 deletions src/generator/extract_schema.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ enum class scalar_type : uint8_t { null = 1, boolean = 2, integer = 4, string =

struct node_scalar {
scalar_type type{scalar_type::null};
std::map<std::string_view, std::string_view> tags{};
std::unordered_map<std::string_view, std::string_view> tags{};
};

using base_node = std::variant<std::monostate, node_scalar, node_array_ptr, node_record_ptr>;
Expand Down Expand Up @@ -63,7 +63,7 @@ struct node_equal {

struct node_record {
bool truncated{false};
std::map<std::string_view, base_node> children{};
std::unordered_map<std::string_view, base_node> children{};
};

struct node_array {
Expand Down Expand Up @@ -130,21 +130,16 @@ bool node_equal::operator()(const node_record_ptr &lhs, const node_record_ptr &r
return false;
}

auto lhs_it = lhs->children.begin();
auto lhs_end = lhs->children.end();

auto rhs_it = rhs->children.begin();
auto rhs_end = rhs->children.end();

for (; lhs_it != lhs_end && rhs_it != rhs_end; ++lhs_it, ++rhs_it) {
if (rhs_it->first != lhs_it->first) {
for (const auto &[k, v] : lhs->children) {
auto it = rhs->children.find(k);
if (it == rhs->children.end()) {
return false;
}
if (!std::visit(node_equal{}, lhs_it->second, rhs_it->second)) {

if (!std::visit(node_equal{}, v, it->second)) {
return false;
}
}

return true;
}

Expand All @@ -162,10 +157,12 @@ struct node_serialize {

ddwaf_object node_serialize::operator()(const std::monostate & /*node*/) const noexcept
{
static constexpr unsigned unknown_type = 0;

ddwaf_object tmp;
ddwaf_object array;
ddwaf_object_array(&array);
ddwaf_object_array_add(&array, ddwaf_object_unsigned(&tmp, 0));
ddwaf_object_array_add(&array, ddwaf_object_unsigned(&tmp, unknown_type));
return array;
}

Expand Down Expand Up @@ -270,6 +267,7 @@ base_node generate_helper(const ddwaf_object *object, std::size_t depth)
record->truncated = true;
length = extract_schema::max_record_nodes;
}
record->children.reserve(length);
for (std::size_t i = 0; i < length && depth > 1; i++) {
const auto *child = &object->array[i];
if (child->parameterName == nullptr) {
Expand All @@ -291,6 +289,7 @@ base_node generate_helper(const ddwaf_object *object, std::size_t depth)
array->truncated = true;
length = extract_schema::max_array_nodes;
}
array->children.reserve(length);
for (std::size_t i = 0; i < length && depth > 1; i++) {
const auto *child = &object->array[i];
auto schema = generate_helper(child, depth - 1);
Expand Down
316 changes: 315 additions & 1 deletion tests/parser_v2_preprocessors_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,320 @@ using namespace ddwaf;

namespace {

TEST(TestParserV2Preprocessors, ParseEmpty) {}
TEST(TestParserV2Preprocessors, ParseNoGenerator)
{
ddwaf::object_limits limits;

auto object = yaml_to_object(R"([{id: 1}])");

ddwaf::ruleset_info::section_info section;
auto array = static_cast<parameter::vector>(parameter(object));
auto preprocessors = parser::v2::parse_preprocessors(array, section, limits);
ddwaf_object_free(&object);

{
ddwaf::parameter root;
section.to_object(root);

auto root_map = static_cast<parameter::map>(root);

auto loaded = ddwaf::parser::at<parameter::string_set>(root_map, "loaded");
EXPECT_EQ(loaded.size(), 0);

auto failed = ddwaf::parser::at<parameter::string_set>(root_map, "failed");
EXPECT_EQ(failed.size(), 1);
EXPECT_NE(failed.find("1"), failed.end());

auto errors = ddwaf::parser::at<parameter::map>(root_map, "errors");
EXPECT_EQ(errors.size(), 1);
auto it = errors.find("missing key 'generator'");
EXPECT_NE(it, errors.end());

auto error_rules = static_cast<ddwaf::parameter::string_set>(it->second);
EXPECT_EQ(error_rules.size(), 1);
EXPECT_NE(error_rules.find("1"), error_rules.end());

ddwaf_object_free(&root);
}

EXPECT_EQ(preprocessors.size(), 0);
}

TEST(TestParserV2Preprocessors, ParseNoID)
{
ddwaf::object_limits limits;

auto object = yaml_to_object(R"([{}])");

ddwaf::ruleset_info::section_info section;
auto array = static_cast<parameter::vector>(parameter(object));
auto preprocessors = parser::v2::parse_preprocessors(array, section, limits);
ddwaf_object_free(&object);

{
ddwaf::parameter root;
section.to_object(root);

auto root_map = static_cast<parameter::map>(root);

auto loaded = ddwaf::parser::at<parameter::string_set>(root_map, "loaded");
EXPECT_EQ(loaded.size(), 0);

auto failed = ddwaf::parser::at<parameter::string_set>(root_map, "failed");
EXPECT_EQ(failed.size(), 1);
EXPECT_NE(failed.find("index:0"), failed.end());

auto errors = ddwaf::parser::at<parameter::map>(root_map, "errors");
EXPECT_EQ(errors.size(), 1);
auto it = errors.find("missing key 'id'");
EXPECT_NE(it, errors.end());

auto error_rules = static_cast<ddwaf::parameter::string_set>(it->second);
EXPECT_EQ(error_rules.size(), 1);
EXPECT_NE(error_rules.find("index:0"), error_rules.end());

ddwaf_object_free(&root);
}

EXPECT_EQ(preprocessors.size(), 0);
}

TEST(TestParserV2Preprocessors, ParseNoParameters)
{
ddwaf::object_limits limits;

auto object = yaml_to_object(R"([{id: 1, generator: extract_schema}])");

ddwaf::ruleset_info::section_info section;
auto array = static_cast<parameter::vector>(parameter(object));
auto preprocessors = parser::v2::parse_preprocessors(array, section, limits);
ddwaf_object_free(&object);

{
ddwaf::parameter root;
section.to_object(root);

auto root_map = static_cast<parameter::map>(root);

auto loaded = ddwaf::parser::at<parameter::string_set>(root_map, "loaded");
EXPECT_EQ(loaded.size(), 0);

auto failed = ddwaf::parser::at<parameter::string_set>(root_map, "failed");
EXPECT_EQ(failed.size(), 1);
EXPECT_NE(failed.find("1"), failed.end());

auto errors = ddwaf::parser::at<parameter::map>(root_map, "errors");
EXPECT_EQ(errors.size(), 1);
auto it = errors.find("missing key 'parameters'");
EXPECT_NE(it, errors.end());

auto error_rules = static_cast<ddwaf::parameter::string_set>(it->second);
EXPECT_EQ(error_rules.size(), 1);
EXPECT_NE(error_rules.find("1"), error_rules.end());

ddwaf_object_free(&root);
}

EXPECT_EQ(preprocessors.size(), 0);
}

TEST(TestParserV2Preprocessors, ParseNoMappings)
{
ddwaf::object_limits limits;

auto object = yaml_to_object(R"([{id: 1, generator: extract_schema, parameters: {}}])");

ddwaf::ruleset_info::section_info section;
auto array = static_cast<parameter::vector>(parameter(object));
auto preprocessors = parser::v2::parse_preprocessors(array, section, limits);
ddwaf_object_free(&object);

{
ddwaf::parameter root;
section.to_object(root);

auto root_map = static_cast<parameter::map>(root);

auto loaded = ddwaf::parser::at<parameter::string_set>(root_map, "loaded");
EXPECT_EQ(loaded.size(), 0);

auto failed = ddwaf::parser::at<parameter::string_set>(root_map, "failed");
EXPECT_EQ(failed.size(), 1);
EXPECT_NE(failed.find("1"), failed.end());

auto errors = ddwaf::parser::at<parameter::map>(root_map, "errors");
EXPECT_EQ(errors.size(), 1);
auto it = errors.find("missing key 'mappings'");
EXPECT_NE(it, errors.end());

auto error_rules = static_cast<ddwaf::parameter::string_set>(it->second);
EXPECT_EQ(error_rules.size(), 1);
EXPECT_NE(error_rules.find("1"), error_rules.end());

ddwaf_object_free(&root);
}

EXPECT_EQ(preprocessors.size(), 0);
}

TEST(TestParserV2Preprocessors, ParseEmptyMappings)
{
ddwaf::object_limits limits;

auto object =
yaml_to_object(R"([{id: 1, generator: extract_schema, parameters: {mappings: []}}])");

ddwaf::ruleset_info::section_info section;
auto array = static_cast<parameter::vector>(parameter(object));
auto preprocessors = parser::v2::parse_preprocessors(array, section, limits);
ddwaf_object_free(&object);

{
ddwaf::parameter root;
section.to_object(root);

auto root_map = static_cast<parameter::map>(root);

auto loaded = ddwaf::parser::at<parameter::string_set>(root_map, "loaded");
EXPECT_EQ(loaded.size(), 0);

auto failed = ddwaf::parser::at<parameter::string_set>(root_map, "failed");
EXPECT_EQ(failed.size(), 1);
EXPECT_NE(failed.find("1"), failed.end());

auto errors = ddwaf::parser::at<parameter::map>(root_map, "errors");
EXPECT_EQ(errors.size(), 1);
auto it = errors.find("empty mappings");
EXPECT_NE(it, errors.end());

auto error_rules = static_cast<ddwaf::parameter::string_set>(it->second);
EXPECT_EQ(error_rules.size(), 1);
EXPECT_NE(error_rules.find("1"), error_rules.end());

ddwaf_object_free(&root);
}

EXPECT_EQ(preprocessors.size(), 0);
}

TEST(TestParserV2Preprocessors, ParseNoInput)
{
ddwaf::object_limits limits;

auto object =
yaml_to_object(R"([{id: 1, generator: extract_schema, parameters: {mappings: [{}]}}])");

ddwaf::ruleset_info::section_info section;
auto array = static_cast<parameter::vector>(parameter(object));
auto preprocessors = parser::v2::parse_preprocessors(array, section, limits);
ddwaf_object_free(&object);

{
ddwaf::parameter root;
section.to_object(root);

auto root_map = static_cast<parameter::map>(root);

auto loaded = ddwaf::parser::at<parameter::string_set>(root_map, "loaded");
EXPECT_EQ(loaded.size(), 0);

auto failed = ddwaf::parser::at<parameter::string_set>(root_map, "failed");
EXPECT_EQ(failed.size(), 1);
EXPECT_NE(failed.find("1"), failed.end());

auto errors = ddwaf::parser::at<parameter::map>(root_map, "errors");
EXPECT_EQ(errors.size(), 1);
auto it = errors.find("missing key 'inputs'");
EXPECT_NE(it, errors.end());

auto error_rules = static_cast<ddwaf::parameter::string_set>(it->second);
EXPECT_EQ(error_rules.size(), 1);
EXPECT_NE(error_rules.find("1"), error_rules.end());

ddwaf_object_free(&root);
}

EXPECT_EQ(preprocessors.size(), 0);
}

TEST(TestParserV2Preprocessors, ParseEmptyInput)
{
ddwaf::object_limits limits;

auto object = yaml_to_object(
R"([{id: 1, generator: extract_schema, parameters: {mappings: [{inputs: [], output: out}]}}])");

ddwaf::ruleset_info::section_info section;
auto array = static_cast<parameter::vector>(parameter(object));
auto preprocessors = parser::v2::parse_preprocessors(array, section, limits);
ddwaf_object_free(&object);

{
ddwaf::parameter root;
section.to_object(root);

auto root_map = static_cast<parameter::map>(root);

auto loaded = ddwaf::parser::at<parameter::string_set>(root_map, "loaded");
EXPECT_EQ(loaded.size(), 0);

auto failed = ddwaf::parser::at<parameter::string_set>(root_map, "failed");
EXPECT_EQ(failed.size(), 1);
EXPECT_NE(failed.find("1"), failed.end());

auto errors = ddwaf::parser::at<parameter::map>(root_map, "errors");
EXPECT_EQ(errors.size(), 1);
auto it = errors.find("empty preprocessor input mapping");
EXPECT_NE(it, errors.end());

auto error_rules = static_cast<ddwaf::parameter::string_set>(it->second);
EXPECT_EQ(error_rules.size(), 1);
EXPECT_NE(error_rules.find("1"), error_rules.end());

ddwaf_object_free(&root);
}

EXPECT_EQ(preprocessors.size(), 0);
}

TEST(TestParserV2Preprocessors, ParseNoOutput)
{
ddwaf::object_limits limits;

auto object = yaml_to_object(
R"([{id: 1, generator: extract_schema, parameters: {mappings: [{inputs: [{address: in}]}]}}])");

ddwaf::ruleset_info::section_info section;
auto array = static_cast<parameter::vector>(parameter(object));
auto preprocessors = parser::v2::parse_preprocessors(array, section, limits);
ddwaf_object_free(&object);

{
ddwaf::parameter root;
section.to_object(root);

auto root_map = static_cast<parameter::map>(root);

auto loaded = ddwaf::parser::at<parameter::string_set>(root_map, "loaded");
EXPECT_EQ(loaded.size(), 0);

auto failed = ddwaf::parser::at<parameter::string_set>(root_map, "failed");
EXPECT_EQ(failed.size(), 1);
EXPECT_NE(failed.find("1"), failed.end());

auto errors = ddwaf::parser::at<parameter::map>(root_map, "errors");
EXPECT_EQ(errors.size(), 1);
auto it = errors.find("missing key 'output'");
EXPECT_NE(it, errors.end());

auto error_rules = static_cast<ddwaf::parameter::string_set>(it->second);
EXPECT_EQ(error_rules.size(), 1);
EXPECT_NE(error_rules.find("1"), error_rules.end());

ddwaf_object_free(&root);
}

EXPECT_EQ(preprocessors.size(), 0);
}

} // namespace

0 comments on commit 2e01180

Please sign in to comment.