From 637112cea51df7614163e240140900304ea1ec87 Mon Sep 17 00:00:00 2001 From: Bartek Kryza Date: Sun, 24 Dec 2023 16:47:19 +0100 Subject: [PATCH] Added package diagram test case with C++20 module partitions dependencies --- .../json/class_diagram_generator.cc | 13 +- src/common/model/path.cc | 35 ++++ src/common/model/path.h | 6 +- src/config/config.cc | 2 + .../json/package_diagram_generator.cc | 8 +- src/package_diagram/model/diagram.h | 26 ++- .../visitor/translation_unit_visitor.cc | 2 +- tests/CMakeLists.txt | 3 +- tests/t30012/test_case.h | 6 + tests/t30013/t30013.cc | 1 + tests/t30013/test_case.h | 38 ++--- tests/t30014/test_case.h | 6 + tests/t30015/.clang-uml | 10 ++ tests/t30015/src/app.cppm | 72 ++++++++ tests/t30015/src/lib1.cppm | 24 +++ tests/t30015/src/mod1.cppm | 5 + tests/t30015/src/mod10.cppm | 5 + tests/t30015/src/mod11.cppm | 5 + tests/t30015/src/mod12.cppm | 5 + tests/t30015/src/mod13.cppm | 5 + tests/t30015/src/mod14.cppm | 5 + tests/t30015/src/mod15.cppm | 5 + tests/t30015/src/mod16.cppm | 5 + tests/t30015/src/mod17.cppm | 5 + tests/t30015/src/mod18.cppm | 5 + tests/t30015/src/mod2.cppm | 7 + tests/t30015/src/mod3.cppm | 5 + tests/t30015/src/mod4.cppm | 5 + tests/t30015/src/mod5.cppm | 5 + tests/t30015/src/mod6.cppm | 5 + tests/t30015/src/mod7.cppm | 5 + tests/t30015/src/mod8.cppm | 5 + tests/t30015/src/mod9.cppm | 5 + tests/t30015/t30015.cc | 6 + tests/t30015/test_case.h | 160 ++++++++++++++++++ tests/test_cases.cc | 3 +- tests/test_cases.h | 40 ++++- tests/test_cases.yaml | 3 + tests/test_model.cc | 51 ++++++ 39 files changed, 545 insertions(+), 62 deletions(-) create mode 100644 src/common/model/path.cc create mode 100644 tests/t30015/.clang-uml create mode 100644 tests/t30015/src/app.cppm create mode 100644 tests/t30015/src/lib1.cppm create mode 100644 tests/t30015/src/mod1.cppm create mode 100644 tests/t30015/src/mod10.cppm create mode 100644 tests/t30015/src/mod11.cppm create mode 100644 tests/t30015/src/mod12.cppm create mode 100644 tests/t30015/src/mod13.cppm create mode 100644 tests/t30015/src/mod14.cppm create mode 100644 tests/t30015/src/mod15.cppm create mode 100644 tests/t30015/src/mod16.cppm create mode 100644 tests/t30015/src/mod17.cppm create mode 100644 tests/t30015/src/mod18.cppm create mode 100644 tests/t30015/src/mod2.cppm create mode 100644 tests/t30015/src/mod3.cppm create mode 100644 tests/t30015/src/mod4.cppm create mode 100644 tests/t30015/src/mod5.cppm create mode 100644 tests/t30015/src/mod6.cppm create mode 100644 tests/t30015/src/mod7.cppm create mode 100644 tests/t30015/src/mod8.cppm create mode 100644 tests/t30015/src/mod9.cppm create mode 100644 tests/t30015/t30015.cc create mode 100644 tests/t30015/test_case.h diff --git a/src/class_diagram/generators/json/class_diagram_generator.cc b/src/class_diagram/generators/json/class_diagram_generator.cc index 9cfad127..14a67dde 100644 --- a/src/class_diagram/generators/json/class_diagram_generator.cc +++ b/src/class_diagram/generators/json/class_diagram_generator.cc @@ -184,18 +184,7 @@ void generator::generate(const package &p, nlohmann::json &parent) const if (!uns.starts_with({p.full_name(false)})) { LOG_DBG("Generating package {}", p.name()); - switch (config().package_type()) { - case config::package_type_t::kDirectory: - package_object["type"] = "directory"; - break; - case config::package_type_t::kModule: - package_object["type"] = "module"; - break; - case config::package_type_t::kNamespace: - package_object["type"] = "namespace"; - break; - } - + package_object["type"] = to_string(config().package_type()); package_object["name"] = p.name(); package_object["display_name"] = p.full_name(false); } diff --git a/src/common/model/path.cc b/src/common/model/path.cc new file mode 100644 index 00000000..fd642da0 --- /dev/null +++ b/src/common/model/path.cc @@ -0,0 +1,35 @@ +/** + * @file src/common/model/path.cc + * + * 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. + */ + +#include "path.h" + +namespace clanguml::common::model { + +std::string to_string(const path_type pt) +{ + switch (pt) { + case path_type::kModule: + return "module"; + case path_type::kNamespace: + return "namespace"; + case path_type::kFilesystem: + return "directory"; + } +} + +} // namespace clanguml::common::model \ No newline at end of file diff --git a/src/common/model/path.h b/src/common/model/path.h index afb20f82..090550cb 100644 --- a/src/common/model/path.h +++ b/src/common/model/path.h @@ -37,6 +37,8 @@ enum class path_type { kModule /*!< Module path */ }; +std::string to_string(path_type pt); + /** * @brief Diagram path * @@ -135,7 +137,8 @@ public: return *this; if (path_type_ != right.path_type_) - throw std::runtime_error(""); + throw std::runtime_error( + "Cannot assign a path to a path with another path type."); path_type_ = right.path_type_; path_ = right.path_; @@ -225,6 +228,7 @@ public: path operator|(const path &right) const { path res{*this}; + res.path_type_ = right.path_type_; res.append(right); return res; } diff --git a/src/config/config.cc b/src/config/config.cc index 8a9e1429..1a663a66 100644 --- a/src/config/config.cc +++ b/src/config/config.cc @@ -147,6 +147,8 @@ std::string to_string(package_type_t pt) return "namespace"; case package_type_t::kDirectory: return "directory"; + case package_type_t::kModule: + return "module"; default: assert(false); return ""; diff --git a/src/package_diagram/generators/json/package_diagram_generator.cc b/src/package_diagram/generators/json/package_diagram_generator.cc index 15656634..74f9f366 100644 --- a/src/package_diagram/generators/json/package_diagram_generator.cc +++ b/src/package_diagram/generators/json/package_diagram_generator.cc @@ -58,12 +58,12 @@ void generator::generate_relationships( void generator::generate(const package &p, nlohmann::json &parent) const { - LOG_DBG("Generating package {}", p.name()); + LOG_DBG("Generating package {}", p.full_name(false)); nlohmann::json j; j["id"] = std::to_string(p.id()); j["name"] = p.name(); - j["type"] = "namespace"; + j["type"] = to_string(config().package_type()); j["display_name"] = p.full_name(false); j["is_deprecated"] = p.is_deprecated(); if (!p.file().empty()) @@ -86,10 +86,12 @@ void generator::generate_diagram(nlohmann::json &parent) const { if (config().using_namespace) parent["using_namespace"] = config().using_namespace().to_string(); + if (config().using_module) + parent["using_module"] = config().using_module(); parent["name"] = model().name(); parent["diagram_type"] = "package"; - + parent["package_type"] = to_string(config().package_type()); parent["elements"] = std::vector{}; parent["relationships"] = std::vector{}; diff --git a/src/package_diagram/model/diagram.h b/src/package_diagram/model/diagram.h index f995d86b..0215ae56 100644 --- a/src/package_diagram/model/diagram.h +++ b/src/package_diagram/model/diagram.h @@ -260,35 +260,29 @@ bool diagram::add_with_module_path( // Make sure all parent modules are already packages in the // model - std::string module_path = p->using_namespace().to_string(); + auto module_relative_to = path{p->using_namespace()}; + for (auto it = parent_path.begin(); it != parent_path.end(); it++) { auto pkg = std::make_unique( p->using_namespace(), common::model::path_type::kModule); pkg->set_name(*it); - auto ns = common::model::path( + auto module_relative_part = common::model::path( parent_path.begin(), it, common::model::path_type::kModule); - pkg->set_module(module_path); - pkg->set_namespace(ns); - std::string package_id_path; - if (module_path.empty()) - package_id_path = pkg->name(); - else - package_id_path = module_path + "." + pkg->name(); + auto module_absolute_path = module_relative_to | module_relative_part; + pkg->set_module(module_absolute_path.to_string()); + pkg->set_namespace(module_absolute_path); - pkg->set_id(common::to_id(package_id_path)); + auto package_absolute_path = module_absolute_path | pkg->name(); + + pkg->set_id(common::to_id(package_absolute_path.to_string())); auto p_ref = std::ref(*pkg); - auto res = add_element(ns, std::move(pkg)); + auto res = add_element(module_relative_part, std::move(pkg)); if (res) element_view::add(p_ref); - - if (module_path.empty()) - module_path = *it; - else - module_path += fmt::format(".{}", *it); } auto p_ref = std::ref(*p); diff --git a/src/package_diagram/visitor/translation_unit_visitor.cc b/src/package_diagram/visitor/translation_unit_visitor.cc index e2fd4f7a..9d00d7ca 100644 --- a/src/package_diagram/visitor/translation_unit_visitor.cc +++ b/src/package_diagram/visitor/translation_unit_visitor.cc @@ -270,7 +270,7 @@ void translation_unit_visitor::add_relationships( // This is for diagram filters pkg->set_module(module_path.to_string()); // This is for rendering nested package structure - pkg->set_namespace(parent_path); + pkg->set_namespace(module_path); set_source_location(*cls, *pkg); if (diagram().should_include(*pkg)) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 2d105273..1ac5a3ed 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -7,7 +7,8 @@ file(GLOB_RECURSE TEST_CONFIG_YMLS test_config_data/*.yml test_compilation_database_data/*.json) set(TEST_CASES_REQUIRING_CXX20 t00056 t00058 t00059 t00065 t00069) -set(TEST_CASES_REQUIRING_CXX20_MODULES t00070 t00071 t30012 t30013) +set(TEST_CASES_REQUIRING_CXX20_MODULES t00070 t00071 + t30012 t30013 t30014 t30015) if(ENABLE_CXX_MODULES_TEST_CASES) foreach(CXX20_MOD_TC ${TEST_CASES_REQUIRING_CXX20_MODULES}) diff --git a/tests/t30012/test_case.h b/tests/t30012/test_case.h index de394bda..d5e51c03 100644 --- a/tests/t30012/test_case.h +++ b/tests/t30012/test_case.h @@ -50,6 +50,12 @@ TEST_CASE("t30012", "[test-case][package]") using namespace json; + REQUIRE(IsPackage(j, "app", "module")); + REQUIRE(IsPackage(j, "app.lib1", "module")); + REQUIRE(IsPackage(j, "app.lib2", "module")); + REQUIRE(IsPackage(j, "app.lib1.mod1", "module")); + REQUIRE(IsPackage(j, "app.lib1.mod2", "module")); + save_json(config.output_directory(), diagram->name + ".json", j); } diff --git a/tests/t30013/t30013.cc b/tests/t30013/t30013.cc index 8bba7195..75dcd332 100644 --- a/tests/t30013/t30013.cc +++ b/tests/t30013/t30013.cc @@ -1,4 +1,5 @@ import t30013.app; +import t30013.mod1; import t30013.mod2; import t30013.mod3; import t30013.mod4; diff --git a/tests/t30013/test_case.h b/tests/t30013/test_case.h index 96589efe..c87b21cd 100644 --- a/tests/t30013/test_case.h +++ b/tests/t30013/test_case.h @@ -83,25 +83,25 @@ TEST_CASE("t30013", "[test-case][package]") using namespace json; - REQUIRE(IsPackage(j, "app")); - REQUIRE(IsPackage(j, "mod1")); - REQUIRE(IsPackage(j, "mod2")); - REQUIRE(IsPackage(j, "mod3")); - REQUIRE(IsPackage(j, "mod4")); - REQUIRE(IsPackage(j, "mod5")); - REQUIRE(IsPackage(j, "mod6")); - REQUIRE(IsPackage(j, "mod7")); - REQUIRE(IsPackage(j, "mod8")); - REQUIRE(IsPackage(j, "mod9")); - REQUIRE(IsPackage(j, "mod10")); - REQUIRE(IsPackage(j, "mod11")); - REQUIRE(IsPackage(j, "mod12")); - REQUIRE(IsPackage(j, "mod13")); - REQUIRE(IsPackage(j, "mod14")); - REQUIRE(IsPackage(j, "mod15")); - REQUIRE(IsPackage(j, "mod16")); - REQUIRE(IsPackage(j, "mod17")); - REQUIRE(IsPackage(j, "mod18")); + REQUIRE(IsPackage(j, "app", "module")); + REQUIRE(IsPackage(j, "mod1", "module")); + REQUIRE(IsPackage(j, "mod2", "module")); + REQUIRE(IsPackage(j, "mod3", "module")); + REQUIRE(IsPackage(j, "mod4", "module")); + REQUIRE(IsPackage(j, "mod5", "module")); + REQUIRE(IsPackage(j, "mod6", "module")); + REQUIRE(IsPackage(j, "mod7", "module")); + REQUIRE(IsPackage(j, "mod8", "module")); + REQUIRE(IsPackage(j, "mod9", "module")); + REQUIRE(IsPackage(j, "mod10", "module")); + REQUIRE(IsPackage(j, "mod11", "module")); + REQUIRE(IsPackage(j, "mod12", "module")); + REQUIRE(IsPackage(j, "mod13", "module")); + REQUIRE(IsPackage(j, "mod14", "module")); + REQUIRE(IsPackage(j, "mod15", "module")); + REQUIRE(IsPackage(j, "mod16", "module")); + REQUIRE(IsPackage(j, "mod17", "module")); + REQUIRE(IsPackage(j, "mod18", "module")); save_json(config.output_directory(), diagram->name + ".json", j); } diff --git a/tests/t30014/test_case.h b/tests/t30014/test_case.h index 24db12d4..898ca2ba 100644 --- a/tests/t30014/test_case.h +++ b/tests/t30014/test_case.h @@ -50,6 +50,12 @@ TEST_CASE("t30014", "[test-case][package]") using namespace json; + REQUIRE(IsPackage(j, "app", "module")); + REQUIRE(IsPackage(j, "app:lib1", "module")); + REQUIRE(IsPackage(j, "app:lib2", "module")); + REQUIRE(IsPackage(j, "app:lib1.mod1", "module")); + REQUIRE(!IsPackage(j, "app:lib1.mod2", "module")); + save_json(config.output_directory(), diagram->name + ".json", j); } diff --git a/tests/t30015/.clang-uml b/tests/t30015/.clang-uml new file mode 100644 index 00000000..1be20718 --- /dev/null +++ b/tests/t30015/.clang-uml @@ -0,0 +1,10 @@ +diagrams: + t30015_package: + type: package + glob: + - t30015.cc + package_type: module + include: + modules: + - t30015 + using_module: t30015 \ No newline at end of file diff --git a/tests/t30015/src/app.cppm b/tests/t30015/src/app.cppm new file mode 100644 index 00000000..22da8d4e --- /dev/null +++ b/tests/t30015/src/app.cppm @@ -0,0 +1,72 @@ +module; + +#include +#include +#include +#include +#include + +export module t30015.app; +import t30015.lib1; + +// import t30015.app; +// import t30015.mod2; +// import t30015.mod3; +// import t30015.mod4; +// import t30015.mod5; +// import t30015.mod6; +// import t30015.mod7; +// import t30015.mod8; +// import t30015.mod9; +// import t30015.mod10; +// import t30015.mod11; +// import t30015.mod12; +// import t30015.mod13; +// import t30015.mod14; +// import t30015.mod15; +// import t30015.mod16; +// import t30015.mod17; +// import t30015.mod18; + +export namespace clanguml::t30015 { + +class CBA : public CF { +public: + CA *ca_; + CB cb_; + std::shared_ptr cc_; + std::map> *cd_; + std::array co_; + static CP *cp_; + + CBA() = default; + + CBA(CN *cn) { } + + friend CR; + + template CBA(std::tuple &items) { } + + void ce(const std::vector /*ce_*/) { } + + std::shared_ptr cg() { return {}; } + + template void ch(std::map> &ch_) { } + + template std::map> ci(T * /*t*/) + { + return {}; + } + + S s; +}; + +void cj(std::unique_ptr /*cj_*/) { } + +std::unique_ptr ck() { return {}; } + +template void cl(std::map> & /*ch_*/) { } + +template std::map> cm() { return {}; } + +} // namespace clanguml::t30013 \ No newline at end of file diff --git a/tests/t30015/src/lib1.cppm b/tests/t30015/src/lib1.cppm new file mode 100644 index 00000000..3877d626 --- /dev/null +++ b/tests/t30015/src/lib1.cppm @@ -0,0 +1,24 @@ +export module t30015.lib1; + +export import :mod1; +export import :mod2; +export import :mod3; +export import :mod4; +export import :mod5; +export import :mod6; +export import :mod7; +export import :mod8; +export import :mod9; +export import :mod10; +export import :mod11; +export import :mod12; +export import :mod13; +export import :mod14; +export import :mod15; +export import :mod16; +export import :mod17; +export import :mod18; + +export namespace clanguml::t30015 { + +} \ No newline at end of file diff --git a/tests/t30015/src/mod1.cppm b/tests/t30015/src/mod1.cppm new file mode 100644 index 00000000..5b561d48 --- /dev/null +++ b/tests/t30015/src/mod1.cppm @@ -0,0 +1,5 @@ +export module t30015.lib1:mod1; + +export namespace clanguml::t30015 { +struct CA { }; +} \ No newline at end of file diff --git a/tests/t30015/src/mod10.cppm b/tests/t30015/src/mod10.cppm new file mode 100644 index 00000000..c52c9f28 --- /dev/null +++ b/tests/t30015/src/mod10.cppm @@ -0,0 +1,5 @@ +export module t30015.lib1:mod10; + +export namespace clanguml::t30015 { +struct CJ { }; +} \ No newline at end of file diff --git a/tests/t30015/src/mod11.cppm b/tests/t30015/src/mod11.cppm new file mode 100644 index 00000000..756088b6 --- /dev/null +++ b/tests/t30015/src/mod11.cppm @@ -0,0 +1,5 @@ +export module t30015.lib1:mod11; + +export namespace clanguml::t30015 { +struct CK { }; +} \ No newline at end of file diff --git a/tests/t30015/src/mod12.cppm b/tests/t30015/src/mod12.cppm new file mode 100644 index 00000000..33513171 --- /dev/null +++ b/tests/t30015/src/mod12.cppm @@ -0,0 +1,5 @@ +export module t30015.lib1:mod12; + +export namespace clanguml::t30015 { +struct CL { }; +} \ No newline at end of file diff --git a/tests/t30015/src/mod13.cppm b/tests/t30015/src/mod13.cppm new file mode 100644 index 00000000..fcac26ef --- /dev/null +++ b/tests/t30015/src/mod13.cppm @@ -0,0 +1,5 @@ +export module t30015.lib1:mod13; + +export namespace clanguml::t30015 { +struct CM { }; +} \ No newline at end of file diff --git a/tests/t30015/src/mod14.cppm b/tests/t30015/src/mod14.cppm new file mode 100644 index 00000000..89d748d9 --- /dev/null +++ b/tests/t30015/src/mod14.cppm @@ -0,0 +1,5 @@ +export module t30015.lib1:mod14; + +export namespace clanguml::t30015 { +struct CN { }; +} \ No newline at end of file diff --git a/tests/t30015/src/mod15.cppm b/tests/t30015/src/mod15.cppm new file mode 100644 index 00000000..49d8c63a --- /dev/null +++ b/tests/t30015/src/mod15.cppm @@ -0,0 +1,5 @@ +export module t30015.lib1:mod15; + +export namespace clanguml::t30015 { +struct CO { }; +} \ No newline at end of file diff --git a/tests/t30015/src/mod16.cppm b/tests/t30015/src/mod16.cppm new file mode 100644 index 00000000..6ea292f3 --- /dev/null +++ b/tests/t30015/src/mod16.cppm @@ -0,0 +1,5 @@ +export module t30015.lib1:mod16; + +export namespace clanguml::t30015 { +struct CP { }; +} \ No newline at end of file diff --git a/tests/t30015/src/mod17.cppm b/tests/t30015/src/mod17.cppm new file mode 100644 index 00000000..b2e6979b --- /dev/null +++ b/tests/t30015/src/mod17.cppm @@ -0,0 +1,5 @@ +export module t30015.lib1:mod17; + +export namespace clanguml::t30015 { +struct CR { }; +} \ No newline at end of file diff --git a/tests/t30015/src/mod18.cppm b/tests/t30015/src/mod18.cppm new file mode 100644 index 00000000..8b452b1d --- /dev/null +++ b/tests/t30015/src/mod18.cppm @@ -0,0 +1,5 @@ +export module t30015.lib1:mod18; + +export namespace clanguml::t30015 { +enum class S { s1, s2, s3 }; +} \ No newline at end of file diff --git a/tests/t30015/src/mod2.cppm b/tests/t30015/src/mod2.cppm new file mode 100644 index 00000000..5ddfa19d --- /dev/null +++ b/tests/t30015/src/mod2.cppm @@ -0,0 +1,7 @@ +export module t30015.lib1:mod2; + +export namespace clanguml::t30015 { +template struct CB { + T cb; +}; +} \ No newline at end of file diff --git a/tests/t30015/src/mod3.cppm b/tests/t30015/src/mod3.cppm new file mode 100644 index 00000000..7711abd6 --- /dev/null +++ b/tests/t30015/src/mod3.cppm @@ -0,0 +1,5 @@ +export module t30015.lib1:mod3; + +export namespace clanguml::t30015 { +struct CC { }; +} \ No newline at end of file diff --git a/tests/t30015/src/mod4.cppm b/tests/t30015/src/mod4.cppm new file mode 100644 index 00000000..4d07765b --- /dev/null +++ b/tests/t30015/src/mod4.cppm @@ -0,0 +1,5 @@ +export module t30015.lib1:mod4; + +export namespace clanguml::t30015 { +struct CD { }; +} \ No newline at end of file diff --git a/tests/t30015/src/mod5.cppm b/tests/t30015/src/mod5.cppm new file mode 100644 index 00000000..31ab043c --- /dev/null +++ b/tests/t30015/src/mod5.cppm @@ -0,0 +1,5 @@ +export module t30015.lib1:mod5; + +export namespace clanguml::t30015 { +struct CE { }; +} \ No newline at end of file diff --git a/tests/t30015/src/mod6.cppm b/tests/t30015/src/mod6.cppm new file mode 100644 index 00000000..6c9de47d --- /dev/null +++ b/tests/t30015/src/mod6.cppm @@ -0,0 +1,5 @@ +export module t30015.lib1:mod6; + +export namespace clanguml::t30015 { +struct CF { }; +} \ No newline at end of file diff --git a/tests/t30015/src/mod7.cppm b/tests/t30015/src/mod7.cppm new file mode 100644 index 00000000..9e8bda51 --- /dev/null +++ b/tests/t30015/src/mod7.cppm @@ -0,0 +1,5 @@ +export module t30015.lib1:mod7; + +export namespace clanguml::t30015 { +struct CG { }; +} \ No newline at end of file diff --git a/tests/t30015/src/mod8.cppm b/tests/t30015/src/mod8.cppm new file mode 100644 index 00000000..ca717b6f --- /dev/null +++ b/tests/t30015/src/mod8.cppm @@ -0,0 +1,5 @@ +export module t30015.lib1:mod8; + +export namespace clanguml::t30015 { +struct CH { }; +} \ No newline at end of file diff --git a/tests/t30015/src/mod9.cppm b/tests/t30015/src/mod9.cppm new file mode 100644 index 00000000..f9a139b9 --- /dev/null +++ b/tests/t30015/src/mod9.cppm @@ -0,0 +1,5 @@ +export module t30015.lib1:mod9; + +export namespace clanguml::t30015 { +struct CI { }; +} \ No newline at end of file diff --git a/tests/t30015/t30015.cc b/tests/t30015/t30015.cc new file mode 100644 index 00000000..edc3de2d --- /dev/null +++ b/tests/t30015/t30015.cc @@ -0,0 +1,6 @@ +import t30015.app; + +namespace clanguml { +namespace t30015 { +} +} \ No newline at end of file diff --git a/tests/t30015/test_case.h b/tests/t30015/test_case.h new file mode 100644 index 00000000..8aab68fb --- /dev/null +++ b/tests/t30015/test_case.h @@ -0,0 +1,160 @@ +/** + * tests/t30015/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("t30015", "[test-case][package]") +{ + auto [config, db] = load_config("t30015"); + + auto diagram = config.diagrams["t30015_package"]; + + REQUIRE(diagram->name == "t30015_package"); + + auto model = generate_package_diagram(*db, diagram); + + REQUIRE(model->name() == "t30015_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(":mod1")); + REQUIRE_THAT(src, IsPackage(":mod2")); + REQUIRE_THAT(src, IsPackage(":mod3")); + REQUIRE_THAT(src, IsPackage(":mod4")); + REQUIRE_THAT(src, IsPackage(":mod5")); + REQUIRE_THAT(src, IsPackage(":mod6")); + REQUIRE_THAT(src, IsPackage(":mod7")); + REQUIRE_THAT(src, IsPackage(":mod8")); + REQUIRE_THAT(src, IsPackage(":mod9")); + REQUIRE_THAT(src, IsPackage(":mod10")); + REQUIRE_THAT(src, IsPackage(":mod11")); + REQUIRE_THAT(src, IsPackage(":mod12")); + REQUIRE_THAT(src, IsPackage(":mod13")); + REQUIRE_THAT(src, IsPackage(":mod14")); + REQUIRE_THAT(src, IsPackage(":mod15")); + REQUIRE_THAT(src, IsPackage(":mod16")); + REQUIRE_THAT(src, IsPackage(":mod17")); + REQUIRE_THAT(src, IsPackage(":mod18")); + + REQUIRE_THAT(src, IsDependency(_A("app"), _A(":mod1"))); + REQUIRE_THAT(src, IsDependency(_A("app"), _A(":mod2"))); + REQUIRE_THAT(src, IsDependency(_A("app"), _A(":mod3"))); + REQUIRE_THAT(src, IsDependency(_A("app"), _A(":mod4"))); + REQUIRE_THAT(src, IsDependency(_A("app"), _A(":mod5"))); + REQUIRE_THAT(src, IsDependency(_A("app"), _A(":mod6"))); + REQUIRE_THAT(src, IsDependency(_A("app"), _A(":mod7"))); + REQUIRE_THAT(src, IsDependency(_A("app"), _A(":mod8"))); + REQUIRE_THAT(src, IsDependency(_A("app"), _A(":mod9"))); + REQUIRE_THAT(src, IsDependency(_A("app"), _A(":mod10"))); + REQUIRE_THAT(src, IsDependency(_A("app"), _A(":mod11"))); + REQUIRE_THAT(src, IsDependency(_A("app"), _A(":mod12"))); + REQUIRE_THAT(src, IsDependency(_A("app"), _A(":mod13"))); + REQUIRE_THAT(src, IsDependency(_A("app"), _A(":mod14"))); + REQUIRE_THAT(src, IsDependency(_A("app"), _A(":mod15"))); + REQUIRE_THAT(src, IsDependency(_A("app"), _A(":mod16"))); + REQUIRE_THAT(src, IsDependency(_A("app"), _A(":mod17"))); + REQUIRE_THAT(src, IsDependency(_A("app"), _A(":mod18"))); + + save_puml(config.output_directory(), diagram->name + ".puml", src); + } + + { + auto j = generate_package_json(diagram, *model); + + using namespace json; + + REQUIRE(IsPackage(j, "app", "module")); + REQUIRE(IsPackage(j, "lib1", "module")); + REQUIRE(IsPackage(j, "lib1:mod1", "module")); + REQUIRE(IsPackage(j, "lib1:mod2", "module")); + REQUIRE(IsPackage(j, "lib1:mod3", "module")); + REQUIRE(IsPackage(j, "lib1:mod4", "module")); + REQUIRE(IsPackage(j, "lib1:mod5", "module")); + REQUIRE(IsPackage(j, "lib1:mod6", "module")); + REQUIRE(IsPackage(j, "lib1:mod7", "module")); + REQUIRE(IsPackage(j, "lib1:mod8", "module")); + REQUIRE(IsPackage(j, "lib1:mod9", "module")); + REQUIRE(IsPackage(j, "lib1:mod10", "module")); + REQUIRE(IsPackage(j, "lib1:mod11", "module")); + REQUIRE(IsPackage(j, "lib1:mod12", "module")); + REQUIRE(IsPackage(j, "lib1:mod13", "module")); + REQUIRE(IsPackage(j, "lib1:mod14", "module")); + REQUIRE(IsPackage(j, "lib1:mod15", "module")); + REQUIRE(IsPackage(j, "lib1:mod16", "module")); + REQUIRE(IsPackage(j, "lib1:mod17", "module")); + REQUIRE(IsPackage(j, "lib1:mod18", "module")); + + save_json(config.output_directory(), diagram->name + ".json", j); + } + + { + auto src = generate_package_mermaid(diagram, *model); + + mermaid::AliasMatcher _A(src); + using mermaid::IsPackage; + using mermaid::IsPackageDependency; + + REQUIRE_THAT(src, IsPackage(_A("app"))); + REQUIRE_THAT(src, IsPackage(_A("lib1"))); + REQUIRE_THAT(src, IsPackage(_A(":mod1"))); + REQUIRE_THAT(src, IsPackage(_A(":mod2"))); + REQUIRE_THAT(src, IsPackage(_A(":mod3"))); + REQUIRE_THAT(src, IsPackage(_A(":mod4"))); + REQUIRE_THAT(src, IsPackage(_A(":mod5"))); + REQUIRE_THAT(src, IsPackage(_A(":mod6"))); + REQUIRE_THAT(src, IsPackage(_A(":mod7"))); + REQUIRE_THAT(src, IsPackage(_A(":mod8"))); + REQUIRE_THAT(src, IsPackage(_A(":mod9"))); + REQUIRE_THAT(src, IsPackage(_A(":mod10"))); + REQUIRE_THAT(src, IsPackage(_A(":mod11"))); + REQUIRE_THAT(src, IsPackage(_A(":mod12"))); + REQUIRE_THAT(src, IsPackage(_A(":mod13"))); + REQUIRE_THAT(src, IsPackage(_A(":mod14"))); + REQUIRE_THAT(src, IsPackage(_A(":mod15"))); + REQUIRE_THAT(src, IsPackage(_A(":mod16"))); + REQUIRE_THAT(src, IsPackage(_A(":mod17"))); + REQUIRE_THAT(src, IsPackage(_A(":mod18"))); + + REQUIRE_THAT(src, IsPackageDependency(_A("app"), _A(":mod1"))); + REQUIRE_THAT(src, IsPackageDependency(_A("app"), _A(":mod2"))); + REQUIRE_THAT(src, IsPackageDependency(_A("app"), _A(":mod3"))); + REQUIRE_THAT(src, IsPackageDependency(_A("app"), _A(":mod4"))); + REQUIRE_THAT(src, IsPackageDependency(_A("app"), _A(":mod5"))); + REQUIRE_THAT(src, IsPackageDependency(_A("app"), _A(":mod6"))); + REQUIRE_THAT(src, IsPackageDependency(_A("app"), _A(":mod7"))); + REQUIRE_THAT(src, IsPackageDependency(_A("app"), _A(":mod8"))); + REQUIRE_THAT(src, IsPackageDependency(_A("app"), _A(":mod9"))); + REQUIRE_THAT(src, IsPackageDependency(_A("app"), _A(":mod10"))); + REQUIRE_THAT(src, IsPackageDependency(_A("app"), _A(":mod11"))); + REQUIRE_THAT(src, IsPackageDependency(_A("app"), _A(":mod12"))); + REQUIRE_THAT(src, IsPackageDependency(_A("app"), _A(":mod13"))); + REQUIRE_THAT(src, IsPackageDependency(_A("app"), _A(":mod14"))); + REQUIRE_THAT(src, IsPackageDependency(_A("app"), _A(":mod15"))); + REQUIRE_THAT(src, IsPackageDependency(_A("app"), _A(":mod16"))); + REQUIRE_THAT(src, IsPackageDependency(_A("app"), _A(":mod17"))); + REQUIRE_THAT(src, IsPackageDependency(_A("app"), _A(":mod18"))); + + 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 8906bbb0..c53a9840 100644 --- a/tests/test_cases.cc +++ b/tests/test_cases.cc @@ -476,6 +476,7 @@ using namespace clanguml::test::matchers; #include "t30012/test_case.h" #include "t30013/test_case.h" #include "t30014/test_case.h" +#include "t30015/test_case.h" #endif /// /// Include diagram tests @@ -520,4 +521,4 @@ int main(int argc, char *argv[]) clih.handle_options(argvv.size(), argvv.data()); return session.run(); -} +} \ No newline at end of file diff --git a/tests/test_cases.h b/tests/test_cases.h index 0c9860ee..ede7b074 100644 --- a/tests/test_cases.h +++ b/tests/test_cases.h @@ -1210,7 +1210,8 @@ std::optional get_element( if (e["display_name"] == name) return {e}; - if (e["type"] == "namespace" || e["type"] == "folder") { + if (e["type"] == "namespace" || e["type"] == "folder" || + e["type"] == "module") { auto maybe_e = get_element(e, name); if (maybe_e) return maybe_e; @@ -1258,13 +1259,35 @@ auto get_relationship(const nlohmann::json &j, const std::string &from, std::string expand_name(const nlohmann::json &j, const std::string &name) { - if (!j.contains("using_namespace")) - return name; + using clanguml::class_diagram::model::path_type; + using clanguml::common::model::path; + using config::package_type_t; - if (name.find("::") == 0) - return name; + if (!j.contains("package_type") || + j["package_type"] == to_string(package_type_t::kNamespace)) { + if (!j.contains("using_namespace")) + return name; - return fmt::format("{}::{}", j["using_namespace"].get(), name); + auto full_path = path{j["using_namespace"].get()}; + full_path |= path{name}; + + return full_path.to_string(); + } + + if (j["package_type"] == to_string(package_type_t::kModule)) { + if (!j.contains("using_module")) + return name; + + auto full_path = + path{j["using_module"].get(), path_type::kModule}; + full_path |= path{name, path_type::kModule}; + + auto res = full_path.to_string(); + + return res; + } + + return name; } bool HasTitle(const nlohmann::json &j, const std::string &title) @@ -1318,10 +1341,11 @@ bool IsEnum(const nlohmann::json &j, const std::string &name) return e && e->at("type") == "enum"; } -bool IsPackage(const nlohmann::json &j, const std::string &name) +bool IsPackage(const nlohmann::json &j, const std::string &name, + const std::string &type = "namespace") { auto e = get_element(j, expand_name(j, name)); - return e && e->at("type") == "namespace"; + return e && e->at("type") == type; } bool IsFolder(const nlohmann::json &j, const std::string &name) diff --git a/tests/test_cases.yaml b/tests/test_cases.yaml index 5b92936b..3f208020 100644 --- a/tests/test_cases.yaml +++ b/tests/test_cases.yaml @@ -368,6 +368,9 @@ test_cases: - name: t30014 title: C++20 modules package diagram test with partitions description: + - name: t30015 + title: C++20 modules package diagram test with partition dependencies + description: Include diagrams: - name: t40001 title: Basic include graph diagram test case diff --git a/tests/test_model.cc b/tests/test_model.cc index d61c45d5..680d7cc8 100644 --- a/tests/test_model.cc +++ b/tests/test_model.cc @@ -21,6 +21,7 @@ #include "class_diagram/model/class.h" #include "common/model/namespace.h" +#include "common/model/package.h" #include "common/model/template_parameter.h" TEST_CASE("Test namespace_", "[unit-test]") @@ -407,3 +408,53 @@ TEST_CASE( CHECK(tp1.calculate_specialization_match(tp2) == 0); } } + +TEST_CASE("Test common::model::package full_name", "[unit-test]") +{ + using clanguml::common::model::package; + using clanguml::common::model::path; + using clanguml::common::model::path_type; + + { + auto using_namespace = path{"A::B::C"}; + auto pkg = package(using_namespace); + pkg.set_name("G"); + pkg.set_namespace(path{"A::B::C::D::E::F"}); + + CHECK(pkg.full_name(false) == "A::B::C::D::E::F::G"); + CHECK(pkg.full_name(true) == "D::E::F::G"); + + CHECK(pkg.doxygen_link().value() == + "namespaceA_1_1B_1_1C_1_1D_1_1E_1_1F_1_1G.html"); + } + + { + auto using_namespace = path{"/A/B/C", path_type::kFilesystem}; + auto pkg = package(using_namespace, path_type::kFilesystem); + pkg.set_name("G"); + pkg.set_namespace(path{"/A/B/C/D/E/F", path_type::kFilesystem}); + + CHECK(pkg.full_name(false) == "A/B/C/D/E/F/G"); + CHECK(pkg.full_name(true) == "D/E/F/G"); + } + + { + auto using_namespace = path{"A.B.C", path_type::kModule}; + auto pkg = package(using_namespace, path_type::kModule); + pkg.set_name("G"); + pkg.set_namespace(path{"A.B.C.D:E.F", path_type::kModule}); + + CHECK(pkg.full_name(false) == "A.B.C.D:E.F.G"); + CHECK(pkg.full_name(true) == "D:E.F.G"); + } + + { + auto using_namespace = path{"A.B.C", path_type::kModule}; + auto pkg = package(using_namespace, path_type::kModule); + pkg.set_name(":D"); + pkg.set_namespace(path{"A.B.C", path_type::kModule}); + + CHECK(pkg.full_name(false) == "A.B.C:D"); + CHECK(pkg.full_name(true) == ":D"); + } +} \ No newline at end of file