diff --git a/src/common/model/diagram_filter.cc b/src/common/model/diagram_filter.cc index 4357751f..f747dad0 100644 --- a/src/common/model/diagram_filter.cc +++ b/src/common/model/diagram_filter.cc @@ -430,7 +430,8 @@ tvl::value_t access_filter::match( [&a](const auto &access) { return a == access; }); } -context_filter::context_filter(filter_t type, std::vector context) +context_filter::context_filter( + filter_t type, std::vector context) : filter_visitor{type} , context_{std::move(context)} { @@ -447,48 +448,50 @@ tvl::value_t context_filter::match(const diagram &d, const element &e) const return {}; return tvl::any_of(context_.begin(), context_.end(), - [&e, &d](const auto &context_root_name) { - const auto &context_root = + [&e, &d](const auto &context_root_pattern) { + const auto &context_roots = static_cast(d) - .find(context_root_name); + .find(context_root_pattern); - if (context_root.has_value()) { - // This is a direct match to the context root - if (context_root.value().id() == e.id()) - return true; + for (auto &context_root : context_roots) { + if (context_root.has_value()) { + // This is a direct match to the context root + if (context_root.value().id() == e.id()) + return true; - // Return a positive match if the element e is in a direct - // relationship with any of the context_root's - for (const relationship &rel : - context_root.value().relationships()) { - if (d.should_include(rel.type()) && - rel.destination() == e.id()) - return true; - } - for (const relationship &rel : e.relationships()) { - if (d.should_include(rel.type()) && - rel.destination() == context_root.value().id()) - return true; - } - - // Return a positive match if the context_root is a parent - // of the element - for (const class_diagram::model::class_parent &p : - context_root.value().parents()) { - if (p.name() == e.full_name(false)) - return true; - } - if (dynamic_cast(&e) != - nullptr) { - for (const class_diagram::model::class_parent &p : - static_cast(e) - .parents()) { - if (p.name() == context_root.value().full_name(false)) + // Return a positive match if the element e is in a direct + // relationship with any of the context_root's + for (const relationship &rel : + context_root.value().relationships()) { + if (d.should_include(rel.type()) && + rel.destination() == e.id()) return true; } + for (const relationship &rel : e.relationships()) { + if (d.should_include(rel.type()) && + rel.destination() == context_root.value().id()) + return true; + } + + // Return a positive match if the context_root is a parent + // of the element + for (const class_diagram::model::class_parent &p : + context_root.value().parents()) { + if (p.name() == e.full_name(false)) + return true; + } + if (dynamic_cast( + &e) != nullptr) { + for (const class_diagram::model::class_parent &p : + static_cast(e) + .parents()) { + if (p.name() == + context_root.value().full_name(false)) + return true; + } + } } } - return false; }); } diff --git a/src/common/model/diagram_filter.h b/src/common/model/diagram_filter.h index fef070c1..67831ca6 100644 --- a/src/common/model/diagram_filter.h +++ b/src/common/model/diagram_filter.h @@ -363,14 +363,14 @@ private: }; struct context_filter : public filter_visitor { - context_filter(filter_t type, std::vector context); + context_filter(filter_t type, std::vector context); ~context_filter() override = default; tvl::value_t match(const diagram &d, const element &r) const override; private: - std::vector context_; + std::vector context_; }; struct paths_filter : public filter_visitor { diff --git a/src/common/types.h b/src/common/types.h index 4fdb1f15..23deba57 100644 --- a/src/common/types.h +++ b/src/common/types.h @@ -127,6 +127,18 @@ public: return *value_; } + T &operator*() + { + assert(value_ != nullptr); + return *value_; + } + + const T &operator*() const + { + assert(value_ != nullptr); + return *value_; + } + void reset() { value_ = nullptr; } T *get() const { return value_; } diff --git a/src/config/config.h b/src/config/config.h index e3a53149..f4829633 100644 --- a/src/config/config.h +++ b/src/config/config.h @@ -107,7 +107,7 @@ struct filter { std::vector dependencies; - std::vector context; + std::vector context; std::vector paths; diff --git a/tests/test_config_data/filters.yml b/tests/test_config_data/filters.yml index 8fb02e1d..118d48a9 100644 --- a/tests/test_config_data/filters.yml +++ b/tests/test_config_data/filters.yml @@ -63,4 +63,9 @@ diagrams: type: class include: specializations: - - r: 'A' \ No newline at end of file + - r: 'A' + regex_context_test: + type: class + include: + context: + - r: '[A|B]' \ No newline at end of file diff --git a/tests/test_filters.cc b/tests/test_filters.cc index bb47dfe6..ded1bcc7 100644 --- a/tests/test_filters.cc +++ b/tests/test_filters.cc @@ -293,23 +293,9 @@ TEST_CASE("Test subclasses regexp filter", "[unit-test]") diagram_filter filter(diagram, config); - c = std::make_unique(config.using_namespace()); - c->set_namespace(namespace_{"ns1::ns2"}); - c->set_name("A1"); - c->set_id(to_id("ns1::ns2::A1"s)); - CHECK(filter.should_include(*c)); - - c = std::make_unique(config.using_namespace()); - c->set_namespace(namespace_{"ns1::ns2"}); - c->set_name("B1"); - c->set_id(to_id("ns1::ns2::B1"s)); - CHECK(filter.should_include(*c)); - - c = std::make_unique(config.using_namespace()); - c->set_namespace(namespace_{"ns1::ns2"}); - c->set_name("C1"); - c->set_id(to_id("ns1::ns2::C1"s)); - CHECK(!filter.should_include(*c)); + CHECK(filter.should_include(*diagram.find("ns1::ns2::A1"))); + CHECK(filter.should_include(*diagram.find("ns1::ns2::B1"))); + CHECK(!filter.should_include(*diagram.find("ns1::ns2::C1"))); } TEST_CASE("Test parents regexp filter", "[unit-test]") @@ -397,23 +383,9 @@ TEST_CASE("Test parents regexp filter", "[unit-test]") diagram_filter filter(diagram, config); - c = std::make_unique(config.using_namespace()); - c->set_namespace(namespace_{"ns1::ns2"}); - c->set_name("BaseA"); - c->set_id(to_id("ns1::ns2::BaseA"s)); - CHECK(filter.should_include(*c)); - - c = std::make_unique(config.using_namespace()); - c->set_namespace(namespace_{"ns1::ns2"}); - c->set_name("BaseB"); - c->set_id(to_id("ns1::ns2::BaseB"s)); - CHECK(filter.should_include(*c)); - - c = std::make_unique(config.using_namespace()); - c->set_namespace(namespace_{"ns1::ns2"}); - c->set_name("Common"); - c->set_id(to_id("ns1::ns2::Common"s)); - CHECK(!filter.should_include(*c)); + CHECK(filter.should_include(*diagram.find("ns1::ns2::BaseA"))); + CHECK(filter.should_include(*diagram.find("ns1::ns2::BaseB"))); + CHECK(!filter.should_include(*diagram.find("ns1::ns2::Common"))); } TEST_CASE("Test specializations regexp filter", "[unit-test]") @@ -476,18 +448,97 @@ TEST_CASE("Test specializations regexp filter", "[unit-test]") diagram_filter filter(diagram, config); - c = std::make_unique(config.using_namespace()); + CHECK(filter.should_include(*diagram.find("A"))); + CHECK(!filter.should_include(*diagram.find("A"))); +} + +TEST_CASE("Test context regexp filter", "[unit-test]") +{ + using clanguml::class_diagram::model::class_; + using clanguml::class_diagram::model::class_method; + using clanguml::class_diagram::model::class_parent; + using clanguml::common::to_id; + using clanguml::common::model::access_t; + using clanguml::common::model::diagram_filter; + using clanguml::common::model::namespace_; + using clanguml::common::model::package; + using clanguml::common::model::relationship; + using clanguml::common::model::relationship_t; + using clanguml::common::model::source_file; + using clanguml::common::model::template_parameter; + using namespace std::string_literals; + + using clanguml::class_diagram::model::class_; + + auto cfg = clanguml::config::load("./test_config_data/filters.yml"); + + auto &config = *cfg.diagrams["regex_context_test"]; + clanguml::class_diagram::model::diagram diagram; + + auto c = std::make_unique(config.using_namespace()); c->set_name("A"); - c->add_template(template_parameter::make_argument("int")); - c->add_template(template_parameter::make_argument("std::string")); - c->set_id(to_id("A"s)); - CHECK(filter.should_include(*c)); + c->set_id(to_id("A"s)); + diagram.add(namespace_{}, std::move(c)); c = std::make_unique(config.using_namespace()); - c->set_name("A"); - c->add_template(template_parameter::make_argument("double")); - c->set_id(to_id("A"s)); - CHECK(!filter.should_include(*c)); + c->set_name("A1"); + c->set_id(to_id("A1"s)); + c->add_relationship( + relationship{relationship_t::kAssociation, to_id("A"s)}); + diagram.add(namespace_{}, std::move(c)); + + c = std::make_unique(config.using_namespace()); + c->set_name("A2"); + c->set_id(to_id("A2"s)); + c->add_relationship(relationship{relationship_t::kDependency, to_id("A"s)}); + diagram.add(namespace_{}, std::move(c)); + + c = std::make_unique(config.using_namespace()); + c->set_name("A21"); + c->set_id(to_id("A21"s)); + c->add_relationship( + relationship{relationship_t::kDependency, to_id("A2"s)}); + diagram.add(namespace_{}, std::move(c)); + + c = std::make_unique(config.using_namespace()); + c->set_name("B"); + c->set_id(to_id("B"s)); + diagram.add(namespace_{}, std::move(c)); + + c = std::make_unique(config.using_namespace()); + c->set_name("B1"); + c->set_id(to_id("B1"s)); + c->add_relationship( + relationship{relationship_t::kAssociation, to_id("B"s)}); + diagram.add(namespace_{}, std::move(c)); + + c = std::make_unique(config.using_namespace()); + c->set_name("C"); + c->set_id(to_id("C"s)); + diagram.add(namespace_{}, std::move(c)); + + c = std::make_unique(config.using_namespace()); + c->set_name("C1"); + c->set_id(to_id("C1"s)); + c->add_relationship( + relationship{relationship_t::kAssociation, to_id("C"s)}); + diagram.add(namespace_{}, std::move(c)); + + diagram.set_complete(true); + + diagram_filter filter(diagram, config); + + CHECK(filter.should_include(*diagram.find("A"))); + CHECK(filter.should_include(*diagram.find("A1"))); + CHECK(filter.should_include(*diagram.find("A2"))); + + CHECK(!filter.should_include(*diagram.find("A21"))); + + CHECK(filter.should_include(*diagram.find("B"))); + CHECK(filter.should_include(*diagram.find("B1"))); + + CHECK(!filter.should_include(*diagram.find("C"))); + CHECK(!filter.should_include(*diagram.find("C1"))); } ///