diff --git a/src/common/model/diagram_filter.cc b/src/common/model/diagram_filter.cc index 2e9b81fe..49b3ac0f 100644 --- a/src/common/model/diagram_filter.cc +++ b/src/common/model/diagram_filter.cc @@ -301,13 +301,18 @@ tvl::value_t modules_filter::match( if (!e.module().has_value()) return {false}; - const auto module_toks = util::split(e.module().value(), "."); // NOLINT + auto module_toks = util::split(e.module().value(), ".", true); // NOLINT + + if (dynamic_cast(&e) != nullptr && + e.get_namespace().type() == path_type::kModule) { + module_toks.push_back(e.name()); + } auto result = tvl::any_of(modules_.begin(), modules_.end(), [&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, "."); + const auto modit_toks = util::split(modit_str, ".", true); return e.module() == modit_str || util::starts_with(module_toks, modit_toks); diff --git a/src/util/util.cc b/src/util/util.cc index 4fa36a65..21b4f41c 100644 --- a/src/util/util.cc +++ b/src/util/util.cc @@ -216,20 +216,29 @@ std::vector split( { std::vector result; - if (!contains(str, delimiter)) - result.push_back(str); + if (!contains(str, delimiter)) { + if (!str.empty()) + result.push_back(std::move(str)); + else if (!skip_empty) + result.push_back(std::move(str)); + } else while (static_cast(!str.empty()) != 0U) { auto index = str.find(delimiter); if (index != std::string::npos) { auto tok = str.substr(0, index); - if (!tok.empty() || !skip_empty) + if (!tok.empty()) result.push_back(std::move(tok)); + else if (!skip_empty) + result.push_back(std::move(tok)); + str = str.substr(index + delimiter.size()); } else { - if (!str.empty() || !skip_empty) - result.push_back(str); + if (!str.empty()) + result.push_back(std::move(str)); + else if (!skip_empty) + result.push_back(std::move(str)); str = ""; } } diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 85e627ad..2d105273 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -7,7 +7,7 @@ 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) +set(TEST_CASES_REQUIRING_CXX20_MODULES t00070 t00071 t30012 t30013) if(ENABLE_CXX_MODULES_TEST_CASES) foreach(CXX20_MOD_TC ${TEST_CASES_REQUIRING_CXX20_MODULES}) diff --git a/tests/t30013/.clang-uml b/tests/t30013/.clang-uml new file mode 100644 index 00000000..9eb52e03 --- /dev/null +++ b/tests/t30013/.clang-uml @@ -0,0 +1,10 @@ +diagrams: + t30013_package: + type: package + glob: + - t30013.cc + package_type: module + include: + modules: + - t30013 + using_module: t30013 \ No newline at end of file diff --git a/tests/t30013/src/app.cppm b/tests/t30013/src/app.cppm new file mode 100644 index 00000000..fc41ab3c --- /dev/null +++ b/tests/t30013/src/app.cppm @@ -0,0 +1,81 @@ +module; + +#include +#include +#include +#include +#include + +export module t30013.app; + +import t30013.mod1; +import t30013.mod2; +import t30013.mod3; +import t30013.mod4; +import t30013.mod5; +import t30013.mod6; +import t30013.mod7; +import t30013.mod8; +import t30013.mod9; +import t30013.mod10; +import t30013.mod11; +import t30013.mod12; +import t30013.mod13; +import t30013.mod14; +import t30013.mod15; +import t30013.mod16; +import t30013.mod17; +import t30013.mod18; + +export namespace clanguml::t30013 { + +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/t30013/src/mod1.cppm b/tests/t30013/src/mod1.cppm new file mode 100644 index 00000000..b8f44f18 --- /dev/null +++ b/tests/t30013/src/mod1.cppm @@ -0,0 +1,5 @@ +export module t30013.mod1; + +export namespace clanguml::t30013 { +struct CA { }; +} \ No newline at end of file diff --git a/tests/t30013/src/mod10.cppm b/tests/t30013/src/mod10.cppm new file mode 100644 index 00000000..4d3618e2 --- /dev/null +++ b/tests/t30013/src/mod10.cppm @@ -0,0 +1,5 @@ +export module t30013.mod10; + +export namespace clanguml::t30013 { +struct CJ { }; +} \ No newline at end of file diff --git a/tests/t30013/src/mod11.cppm b/tests/t30013/src/mod11.cppm new file mode 100644 index 00000000..d3fe42e2 --- /dev/null +++ b/tests/t30013/src/mod11.cppm @@ -0,0 +1,5 @@ +export module t30013.mod11; + +export namespace clanguml::t30013 { +struct CK { }; +} \ No newline at end of file diff --git a/tests/t30013/src/mod12.cppm b/tests/t30013/src/mod12.cppm new file mode 100644 index 00000000..0075f864 --- /dev/null +++ b/tests/t30013/src/mod12.cppm @@ -0,0 +1,5 @@ +export module t30013.mod12; + +export namespace clanguml::t30013 { +struct CL { }; +} \ No newline at end of file diff --git a/tests/t30013/src/mod13.cppm b/tests/t30013/src/mod13.cppm new file mode 100644 index 00000000..ffff01c3 --- /dev/null +++ b/tests/t30013/src/mod13.cppm @@ -0,0 +1,5 @@ +export module t30013.mod13; + +export namespace clanguml::t30013 { +struct CM { }; +} \ No newline at end of file diff --git a/tests/t30013/src/mod14.cppm b/tests/t30013/src/mod14.cppm new file mode 100644 index 00000000..aaeac2bc --- /dev/null +++ b/tests/t30013/src/mod14.cppm @@ -0,0 +1,5 @@ +export module t30013.mod14; + +export namespace clanguml::t30013 { +struct CN { }; +} \ No newline at end of file diff --git a/tests/t30013/src/mod15.cppm b/tests/t30013/src/mod15.cppm new file mode 100644 index 00000000..8c0bf8d0 --- /dev/null +++ b/tests/t30013/src/mod15.cppm @@ -0,0 +1,5 @@ +export module t30013.mod15; + +export namespace clanguml::t30013 { +struct CO { }; +} \ No newline at end of file diff --git a/tests/t30013/src/mod16.cppm b/tests/t30013/src/mod16.cppm new file mode 100644 index 00000000..2dfb91c1 --- /dev/null +++ b/tests/t30013/src/mod16.cppm @@ -0,0 +1,5 @@ +export module t30013.mod16; + +export namespace clanguml::t30013 { +struct CP { }; +} \ No newline at end of file diff --git a/tests/t30013/src/mod17.cppm b/tests/t30013/src/mod17.cppm new file mode 100644 index 00000000..89d291b2 --- /dev/null +++ b/tests/t30013/src/mod17.cppm @@ -0,0 +1,5 @@ +export module t30013.mod17; + +export namespace clanguml::t30013 { +struct CR { }; +} \ No newline at end of file diff --git a/tests/t30013/src/mod18.cppm b/tests/t30013/src/mod18.cppm new file mode 100644 index 00000000..9897e8c0 --- /dev/null +++ b/tests/t30013/src/mod18.cppm @@ -0,0 +1,5 @@ +export module t30013.mod18; + +export namespace clanguml::t30013 { +enum class S { s1, s2, s3 }; +} \ No newline at end of file diff --git a/tests/t30013/src/mod2.cppm b/tests/t30013/src/mod2.cppm new file mode 100644 index 00000000..d8beca54 --- /dev/null +++ b/tests/t30013/src/mod2.cppm @@ -0,0 +1,7 @@ +export module t30013.mod2; + +export namespace clanguml::t30013 { +template struct CB { + T cb; +}; +} \ No newline at end of file diff --git a/tests/t30013/src/mod3.cppm b/tests/t30013/src/mod3.cppm new file mode 100644 index 00000000..0260cd39 --- /dev/null +++ b/tests/t30013/src/mod3.cppm @@ -0,0 +1,5 @@ +export module t30013.mod3; + +export namespace clanguml::t30013 { +struct CC { }; +} \ No newline at end of file diff --git a/tests/t30013/src/mod4.cppm b/tests/t30013/src/mod4.cppm new file mode 100644 index 00000000..a15f917a --- /dev/null +++ b/tests/t30013/src/mod4.cppm @@ -0,0 +1,5 @@ +export module t30013.mod4; + +export namespace clanguml::t30013 { +struct CD { }; +} \ No newline at end of file diff --git a/tests/t30013/src/mod5.cppm b/tests/t30013/src/mod5.cppm new file mode 100644 index 00000000..09abf480 --- /dev/null +++ b/tests/t30013/src/mod5.cppm @@ -0,0 +1,5 @@ +export module t30013.mod5; + +export namespace clanguml::t30013 { +struct CE { }; +} \ No newline at end of file diff --git a/tests/t30013/src/mod6.cppm b/tests/t30013/src/mod6.cppm new file mode 100644 index 00000000..3d39d392 --- /dev/null +++ b/tests/t30013/src/mod6.cppm @@ -0,0 +1,5 @@ +export module t30013.mod6; + +export namespace clanguml::t30013 { +struct CF { }; +} \ No newline at end of file diff --git a/tests/t30013/src/mod7.cppm b/tests/t30013/src/mod7.cppm new file mode 100644 index 00000000..5a2eb8a4 --- /dev/null +++ b/tests/t30013/src/mod7.cppm @@ -0,0 +1,5 @@ +export module t30013.mod7; + +export namespace clanguml::t30013 { +struct CG { }; +} \ No newline at end of file diff --git a/tests/t30013/src/mod8.cppm b/tests/t30013/src/mod8.cppm new file mode 100644 index 00000000..870cb975 --- /dev/null +++ b/tests/t30013/src/mod8.cppm @@ -0,0 +1,5 @@ +export module t30013.mod8; + +export namespace clanguml::t30013 { +struct CH { }; +} \ No newline at end of file diff --git a/tests/t30013/src/mod9.cppm b/tests/t30013/src/mod9.cppm new file mode 100644 index 00000000..9cce4809 --- /dev/null +++ b/tests/t30013/src/mod9.cppm @@ -0,0 +1,5 @@ +export module t30013.mod9; + +export namespace clanguml::t30013 { +struct CI { }; +} \ No newline at end of file diff --git a/tests/t30013/t30013.cc b/tests/t30013/t30013.cc new file mode 100644 index 00000000..8bba7195 --- /dev/null +++ b/tests/t30013/t30013.cc @@ -0,0 +1,24 @@ +import t30013.app; +import t30013.mod2; +import t30013.mod3; +import t30013.mod4; +import t30013.mod5; +import t30013.mod6; +import t30013.mod7; +import t30013.mod8; +import t30013.mod9; +import t30013.mod10; +import t30013.mod11; +import t30013.mod12; +import t30013.mod13; +import t30013.mod14; +import t30013.mod15; +import t30013.mod16; +import t30013.mod17; +import t30013.mod18; + +namespace clanguml::t30013 { +class R { + CBA cba; +}; +} // namespace clanguml::t30013 \ No newline at end of file diff --git a/tests/t30013/test_case.h b/tests/t30013/test_case.h new file mode 100644 index 00000000..96589efe --- /dev/null +++ b/tests/t30013/test_case.h @@ -0,0 +1,157 @@ +/** + * tests/t30013/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("t30013", "[test-case][package]") +{ + auto [config, db] = load_config("t30013"); + + auto diagram = config.diagrams["t30013_package"]; + + REQUIRE(diagram->name == "t30013_package"); + + auto model = generate_package_diagram(*db, diagram); + + REQUIRE(model->name() == "t30013_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("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")); + 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")); + + 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("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 a8bf55b9..bb5eb37f 100644 --- a/tests/test_cases.cc +++ b/tests/test_cases.cc @@ -474,6 +474,7 @@ using namespace clanguml::test::matchers; #include "t30011/test_case.h" #if defined(ENABLE_CXX_MODULES_TEST_CASES) #include "t30012/test_case.h" +#include "t30013/test_case.h" #endif /// /// Include diagram tests diff --git a/tests/test_cases.yaml b/tests/test_cases.yaml index 6ec49260..2500c49c 100644 --- a/tests/test_cases.yaml +++ b/tests/test_cases.yaml @@ -359,6 +359,12 @@ test_cases: - name: t30011 title: Package diagram with packages from directory structure for plain C description: + - name: t30012 + title: C++20 modules package diagram test + description: + - name: t30013 + title: C++20 modules package dependencies diagram test + description: Include diagrams: - name: t40001 title: Basic include graph diagram test case diff --git a/tests/test_util.cc b/tests/test_util.cc index 193e6293..d1e8fcaf 100644 --- a/tests/test_util.cc +++ b/tests/test_util.cc @@ -31,7 +31,8 @@ TEST_CASE("Test split", "[unit-test]") const C empty{}; - CHECK(split("", " ") == C{""}); + CHECK(split("", " ") == C{}); + CHECK(split("", ".") == C{}); CHECK(split("ABCD", " ") == C{"ABCD"}); CHECK(split("::A", "::") == C{"A"}); CHECK(split("::", "::") == C{});