From 453f265feb393b6330c355dc593b1c5fd956a46d Mon Sep 17 00:00:00 2001 From: Bartek Kryza Date: Sat, 23 Dec 2023 19:23:40 +0100 Subject: [PATCH] Added package diagram test case with C++20 module partitions --- src/common/model/diagram_filter.cc | 6 ++- src/common/model/element.h | 2 - src/common/model/path.h | 44 +++++++++++++++++-- src/config/config.cc | 8 +++- tests/t30014/.clang-uml | 13 ++++++ tests/t30014/src/lib1.cppm | 13 ++++++ tests/t30014/src/lib1mod1.cppm | 5 +++ tests/t30014/src/lib1mod2.cppm | 5 +++ tests/t30014/src/lib2.cppm | 13 ++++++ tests/t30014/src/t30014_mod.cppm | 13 ++++++ tests/t30014/t30014.cc | 6 +++ tests/t30014/test_case.h | 69 ++++++++++++++++++++++++++++++ tests/test_cases.cc | 1 + tests/test_cases.yaml | 3 ++ 14 files changed, 191 insertions(+), 10 deletions(-) create mode 100644 tests/t30014/.clang-uml create mode 100644 tests/t30014/src/lib1.cppm create mode 100644 tests/t30014/src/lib1mod1.cppm create mode 100644 tests/t30014/src/lib1mod2.cppm create mode 100644 tests/t30014/src/lib2.cppm create mode 100644 tests/t30014/src/t30014_mod.cppm create mode 100644 tests/t30014/t30014.cc create mode 100644 tests/t30014/test_case.h diff --git a/src/common/model/diagram_filter.cc b/src/common/model/diagram_filter.cc index 49b3ac0f..3c0c9fd8 100644 --- a/src/common/model/diagram_filter.cc +++ b/src/common/model/diagram_filter.cc @@ -301,7 +301,8 @@ tvl::value_t modules_filter::match( if (!e.module().has_value()) return {false}; - auto module_toks = util::split(e.module().value(), ".", true); // NOLINT + auto module_toks = + path::split(e.module().value(), path_type::kModule); // NOLINT if (dynamic_cast(&e) != nullptr && e.get_namespace().type() == path_type::kModule) { @@ -312,7 +313,8 @@ tvl::value_t modules_filter::match( [&e, &module_toks](const auto &modit) { if (std::holds_alternative(modit.value())) { const auto &modit_str = std::get(modit.value()); - const auto modit_toks = util::split(modit_str, ".", true); + const auto modit_toks = + path::split(modit_str, path_type::kModule); return e.module() == modit_str || util::starts_with(module_toks, modit_toks); diff --git a/src/common/model/element.h b/src/common/model/element.h index 2d94d393..38849d13 100644 --- a/src/common/model/element.h +++ b/src/common/model/element.h @@ -39,8 +39,6 @@ class element : public diagram_element { public: element(namespace_ using_namespace, path_type pt = path_type::kNamespace); - element(path_type pt); - ~element() override = default; /** diff --git a/src/common/model/path.h b/src/common/model/path.h index 3cb030eb..afb20f82 100644 --- a/src/common/model/path.h +++ b/src/common/model/path.h @@ -50,9 +50,9 @@ class path { * * @return Path separator */ - const char *separator() const + static const char *separator(path_type pt) { - switch (path_type_) { + switch (pt) { case path_type::kNamespace: return "::"; case path_type::kModule: @@ -68,9 +68,38 @@ class path { return "::"; } + /** + * Returns the path separator based on the type of the instance path. + * + * @return Path separator + */ + const char *separator() const { return separator(path_type_); } + public: using container_type = std::vector; + static container_type split( + const std::string &ns, path_type pt = path_type::kNamespace) + { + container_type result; + if (pt == path_type::kModule) { + auto path_toks = util::split(ns, separator(pt)); + for (const auto &pt : path_toks) { + const auto subtoks = util::split(pt, ":"); + if (subtoks.size() == 2) { + result.push_back(subtoks.at(0)); + result.push_back(fmt::format(":{}", subtoks.at(1))); + } + else + result.push_back(subtoks.at(0)); + } + } + else + result = util::split(ns, separator(pt)); + + return result; + } + path(path_type pt = path_type::kNamespace) : path_type_{pt} { @@ -82,7 +111,7 @@ public: if (ns.empty()) return; - path_ = util::split(ns, separator()); + path_ = split(ns, pt); } virtual ~path() = default; @@ -163,7 +192,14 @@ public: */ std::string to_string() const { - return fmt::format("{}", fmt::join(path_, std::string{separator()})); + auto result = + fmt::format("{}", fmt::join(path_, std::string{separator()})); + + if (path_type_ == path_type::kModule) { + util::replace_all(result, ".:", ":"); + } + + return result; } /** diff --git a/src/config/config.cc b/src/config/config.cc index 11207f86..8a9e1429 100644 --- a/src/config/config.cc +++ b/src/config/config.cc @@ -277,10 +277,14 @@ std::vector diagram::make_module_relative( if (!maybe_module) return {}; - auto module_path = util::split(maybe_module.value(), "."); + auto module_path = common::model::path( + maybe_module.value(), common::model::path_type::kModule) + .tokens(); if (using_module.has_value) { - auto using_module_path = util::split(using_module(), "."); + auto using_module_path = common::model::path( + using_module(), common::model::path_type::kModule) + .tokens(); if (util::starts_with(module_path, using_module_path)) { util::remove_prefix(module_path, using_module_path); diff --git a/tests/t30014/.clang-uml b/tests/t30014/.clang-uml new file mode 100644 index 00000000..9eed5c76 --- /dev/null +++ b/tests/t30014/.clang-uml @@ -0,0 +1,13 @@ +diagrams: + t30014_package: + type: package + glob: + - t30014.cc + package_type: module + include: + modules: + - t30014 + exclude: + modules: + - t30014.app:lib1.mod2 + using_module: t30014 \ No newline at end of file diff --git a/tests/t30014/src/lib1.cppm b/tests/t30014/src/lib1.cppm new file mode 100644 index 00000000..8df1bab0 --- /dev/null +++ b/tests/t30014/src/lib1.cppm @@ -0,0 +1,13 @@ +export module t30014.app:lib1; + +export namespace clanguml::t30014 { +class B { }; + +template class BB { + T t; +}; + +namespace detail { +enum class BBB { bbb1, bbb2 }; +} // namespace detail +} // namespace clanguml::t30014 \ No newline at end of file diff --git a/tests/t30014/src/lib1mod1.cppm b/tests/t30014/src/lib1mod1.cppm new file mode 100644 index 00000000..e0449519 --- /dev/null +++ b/tests/t30014/src/lib1mod1.cppm @@ -0,0 +1,5 @@ +export module t30014.app:lib1.mod1; + +export namespace clanguml::t30014 { +class D { }; +} // namespace clanguml::t30014 \ No newline at end of file diff --git a/tests/t30014/src/lib1mod2.cppm b/tests/t30014/src/lib1mod2.cppm new file mode 100644 index 00000000..51d3f5a0 --- /dev/null +++ b/tests/t30014/src/lib1mod2.cppm @@ -0,0 +1,5 @@ +export module t30014.app:lib1.mod2; + +export namespace clanguml::t30014 { +class E { }; +} // namespace clanguml::t30014 \ No newline at end of file diff --git a/tests/t30014/src/lib2.cppm b/tests/t30014/src/lib2.cppm new file mode 100644 index 00000000..d213f45b --- /dev/null +++ b/tests/t30014/src/lib2.cppm @@ -0,0 +1,13 @@ +export module t30014.app:lib2; + +export namespace clanguml::t30014 { +class C { }; + +template class CC { + T t; +}; + +namespace detail { +enum class CCC { ccc1, ccc2 }; +} // namespace detail +} // namespace clanguml::t30014 \ No newline at end of file diff --git a/tests/t30014/src/t30014_mod.cppm b/tests/t30014/src/t30014_mod.cppm new file mode 100644 index 00000000..1c2f1390 --- /dev/null +++ b/tests/t30014/src/t30014_mod.cppm @@ -0,0 +1,13 @@ +export module t30014.app; +import :lib1; +import :lib1.mod1; +import :lib1.mod2; +import :lib2; + +export namespace clanguml::t30014 { +class A { + int get() { return a; } + + int a; +}; +} // namespace clanguml::t30014 \ No newline at end of file diff --git a/tests/t30014/t30014.cc b/tests/t30014/t30014.cc new file mode 100644 index 00000000..67822f28 --- /dev/null +++ b/tests/t30014/t30014.cc @@ -0,0 +1,6 @@ +import t30014.app; + +namespace clanguml { +namespace t30014 { +} +} \ No newline at end of file diff --git a/tests/t30014/test_case.h b/tests/t30014/test_case.h new file mode 100644 index 00000000..24db12d4 --- /dev/null +++ b/tests/t30014/test_case.h @@ -0,0 +1,69 @@ +/** + * tests/t30014/test_case.h + * + * Copyright (c) 2021-2023 Bartek Kryza + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +TEST_CASE("t30014", "[test-case][package]") +{ + auto [config, db] = load_config("t30014"); + + auto diagram = config.diagrams["t30014_package"]; + + REQUIRE(diagram->name == "t30014_package"); + + auto model = generate_package_diagram(*db, diagram); + + REQUIRE(model->name() == "t30014_package"); + + { + auto src = generate_package_puml(diagram, *model); + AliasMatcher _A(src); + + REQUIRE_THAT(src, StartsWith("@startuml")); + REQUIRE_THAT(src, EndsWith("@enduml\n")); + + // Check if all packages exist + REQUIRE_THAT(src, IsPackage("app")); + REQUIRE_THAT(src, IsPackage(":lib1")); + REQUIRE_THAT(src, IsPackage(":lib2")); + REQUIRE_THAT(src, IsPackage("mod1")); + REQUIRE_THAT(src, !IsPackage("mod2")); + + save_puml(config.output_directory(), diagram->name + ".puml", src); + } + + { + auto j = generate_package_json(diagram, *model); + + using namespace json; + + save_json(config.output_directory(), diagram->name + ".json", j); + } + + { + auto src = generate_package_mermaid(diagram, *model); + + mermaid::AliasMatcher _A(src); + using mermaid::IsPackage; + + REQUIRE_THAT(src, IsPackage(_A("app"))); + REQUIRE_THAT(src, IsPackage(_A(":lib1"))); + REQUIRE_THAT(src, IsPackage(_A(":lib2"))); + REQUIRE_THAT(src, IsPackage(_A("mod1"))); + + save_mermaid(config.output_directory(), diagram->name + ".mmd", src); + } +} \ No newline at end of file diff --git a/tests/test_cases.cc b/tests/test_cases.cc index bb5eb37f..8906bbb0 100644 --- a/tests/test_cases.cc +++ b/tests/test_cases.cc @@ -475,6 +475,7 @@ using namespace clanguml::test::matchers; #if defined(ENABLE_CXX_MODULES_TEST_CASES) #include "t30012/test_case.h" #include "t30013/test_case.h" +#include "t30014/test_case.h" #endif /// /// Include diagram tests diff --git a/tests/test_cases.yaml b/tests/test_cases.yaml index 2500c49c..5b92936b 100644 --- a/tests/test_cases.yaml +++ b/tests/test_cases.yaml @@ -365,6 +365,9 @@ test_cases: - name: t30013 title: C++20 modules package dependencies diagram test description: + - name: t30014 + title: C++20 modules package diagram test with partitions + description: Include diagrams: - name: t40001 title: Basic include graph diagram test case