Added test case for package diagram from modules dependencies

This commit is contained in:
Bartek Kryza
2023-12-22 21:23:53 +01:00
parent a8d646d1bc
commit 913ccb6bdf
28 changed files with 395 additions and 9 deletions

View File

@@ -301,13 +301,18 @@ tvl::value_t modules_filter::match(
if (!e.module().has_value()) if (!e.module().has_value())
return {false}; 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<const package *>(&e) != nullptr &&
e.get_namespace().type() == path_type::kModule) {
module_toks.push_back(e.name());
}
auto result = tvl::any_of(modules_.begin(), modules_.end(), auto result = tvl::any_of(modules_.begin(), modules_.end(),
[&e, &module_toks](const auto &modit) { [&e, &module_toks](const auto &modit) {
if (std::holds_alternative<std::string>(modit.value())) { if (std::holds_alternative<std::string>(modit.value())) {
const auto &modit_str = std::get<std::string>(modit.value()); const auto &modit_str = std::get<std::string>(modit.value());
const auto modit_toks = util::split(modit_str, "."); const auto modit_toks = util::split(modit_str, ".", true);
return e.module() == modit_str || return e.module() == modit_str ||
util::starts_with(module_toks, modit_toks); util::starts_with(module_toks, modit_toks);

View File

@@ -216,20 +216,29 @@ std::vector<std::string> split(
{ {
std::vector<std::string> result; std::vector<std::string> result;
if (!contains(str, delimiter)) if (!contains(str, delimiter)) {
result.push_back(str); if (!str.empty())
result.push_back(std::move(str));
else if (!skip_empty)
result.push_back(std::move(str));
}
else else
while (static_cast<unsigned int>(!str.empty()) != 0U) { while (static_cast<unsigned int>(!str.empty()) != 0U) {
auto index = str.find(delimiter); auto index = str.find(delimiter);
if (index != std::string::npos) { if (index != std::string::npos) {
auto tok = str.substr(0, index); auto tok = str.substr(0, index);
if (!tok.empty() || !skip_empty) if (!tok.empty())
result.push_back(std::move(tok)); result.push_back(std::move(tok));
else if (!skip_empty)
result.push_back(std::move(tok));
str = str.substr(index + delimiter.size()); str = str.substr(index + delimiter.size());
} }
else { else {
if (!str.empty() || !skip_empty) if (!str.empty())
result.push_back(str); result.push_back(std::move(str));
else if (!skip_empty)
result.push_back(std::move(str));
str = ""; str = "";
} }
} }

View File

@@ -7,7 +7,7 @@ file(GLOB_RECURSE TEST_CONFIG_YMLS test_config_data/*.yml
test_compilation_database_data/*.json) test_compilation_database_data/*.json)
set(TEST_CASES_REQUIRING_CXX20 t00056 t00058 t00059 t00065 t00069) 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) if(ENABLE_CXX_MODULES_TEST_CASES)
foreach(CXX20_MOD_TC ${TEST_CASES_REQUIRING_CXX20_MODULES}) foreach(CXX20_MOD_TC ${TEST_CASES_REQUIRING_CXX20_MODULES})

10
tests/t30013/.clang-uml Normal file
View File

@@ -0,0 +1,10 @@
diagrams:
t30013_package:
type: package
glob:
- t30013.cc
package_type: module
include:
modules:
- t30013
using_module: t30013

81
tests/t30013/src/app.cppm Normal file
View File

@@ -0,0 +1,81 @@
module;
#include <array>
#include <map>
#include <memory>
#include <string>
#include <vector>
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<int> cb_;
std::shared_ptr<CC> cc_;
std::map<std::string, std::unique_ptr<CD>> *cd_;
std::array<CO, 5> co_;
static CP *cp_;
CBA() = default;
CBA(CN *cn) { }
friend CR;
template <typename... Item> CBA(std::tuple<Item...> &items) { }
void ce(const std::vector<CE> /*ce_*/) { }
std::shared_ptr<CG> cg() { return {}; }
template <typename T>
void ch(std::map<T, std::shared_ptr<CH>> &ch_)
{
}
template <typename T>
std::map<T, std::shared_ptr<CI>> ci(T * /*t*/)
{
return {};
}
S s;
};
void cj(std::unique_ptr<CJ> /*cj_*/) { }
std::unique_ptr<CK> ck() { return {}; }
template <typename T>
void cl(std::map<T, std::shared_ptr<CL>> & /*ch_*/)
{
}
template <typename T> std::map<T, std::shared_ptr<CM>> cm()
{
return {};
}
} // namespace clanguml::t30013

View File

@@ -0,0 +1,5 @@
export module t30013.mod1;
export namespace clanguml::t30013 {
struct CA { };
}

View File

@@ -0,0 +1,5 @@
export module t30013.mod10;
export namespace clanguml::t30013 {
struct CJ { };
}

View File

@@ -0,0 +1,5 @@
export module t30013.mod11;
export namespace clanguml::t30013 {
struct CK { };
}

View File

@@ -0,0 +1,5 @@
export module t30013.mod12;
export namespace clanguml::t30013 {
struct CL { };
}

View File

@@ -0,0 +1,5 @@
export module t30013.mod13;
export namespace clanguml::t30013 {
struct CM { };
}

View File

@@ -0,0 +1,5 @@
export module t30013.mod14;
export namespace clanguml::t30013 {
struct CN { };
}

View File

@@ -0,0 +1,5 @@
export module t30013.mod15;
export namespace clanguml::t30013 {
struct CO { };
}

View File

@@ -0,0 +1,5 @@
export module t30013.mod16;
export namespace clanguml::t30013 {
struct CP { };
}

View File

@@ -0,0 +1,5 @@
export module t30013.mod17;
export namespace clanguml::t30013 {
struct CR { };
}

View File

@@ -0,0 +1,5 @@
export module t30013.mod18;
export namespace clanguml::t30013 {
enum class S { s1, s2, s3 };
}

View File

@@ -0,0 +1,7 @@
export module t30013.mod2;
export namespace clanguml::t30013 {
template <typename T> struct CB {
T cb;
};
}

View File

@@ -0,0 +1,5 @@
export module t30013.mod3;
export namespace clanguml::t30013 {
struct CC { };
}

View File

@@ -0,0 +1,5 @@
export module t30013.mod4;
export namespace clanguml::t30013 {
struct CD { };
}

View File

@@ -0,0 +1,5 @@
export module t30013.mod5;
export namespace clanguml::t30013 {
struct CE { };
}

View File

@@ -0,0 +1,5 @@
export module t30013.mod6;
export namespace clanguml::t30013 {
struct CF { };
}

View File

@@ -0,0 +1,5 @@
export module t30013.mod7;
export namespace clanguml::t30013 {
struct CG { };
}

View File

@@ -0,0 +1,5 @@
export module t30013.mod8;
export namespace clanguml::t30013 {
struct CH { };
}

View File

@@ -0,0 +1,5 @@
export module t30013.mod9;
export namespace clanguml::t30013 {
struct CI { };
}

24
tests/t30013/t30013.cc Normal file
View File

@@ -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

157
tests/t30013/test_case.h Normal file
View File

@@ -0,0 +1,157 @@
/**
* tests/t30013/test_case.h
*
* Copyright (c) 2021-2023 Bartek Kryza <bkryza@gmail.com>
*
* 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);
}
}

View File

@@ -474,6 +474,7 @@ using namespace clanguml::test::matchers;
#include "t30011/test_case.h" #include "t30011/test_case.h"
#if defined(ENABLE_CXX_MODULES_TEST_CASES) #if defined(ENABLE_CXX_MODULES_TEST_CASES)
#include "t30012/test_case.h" #include "t30012/test_case.h"
#include "t30013/test_case.h"
#endif #endif
/// ///
/// Include diagram tests /// Include diagram tests

View File

@@ -359,6 +359,12 @@ test_cases:
- name: t30011 - name: t30011
title: Package diagram with packages from directory structure for plain C title: Package diagram with packages from directory structure for plain C
description: description:
- name: t30012
title: C++20 modules package diagram test
description:
- name: t30013
title: C++20 modules package dependencies diagram test
description:
Include diagrams: Include diagrams:
- name: t40001 - name: t40001
title: Basic include graph diagram test case title: Basic include graph diagram test case

View File

@@ -31,7 +31,8 @@ TEST_CASE("Test split", "[unit-test]")
const C empty{}; const C empty{};
CHECK(split("", " ") == C{""}); CHECK(split("", " ") == C{});
CHECK(split("", ".") == C{});
CHECK(split("ABCD", " ") == C{"ABCD"}); CHECK(split("ABCD", " ") == C{"ABCD"});
CHECK(split("::A", "::") == C{"A"}); CHECK(split("::A", "::") == C{"A"});
CHECK(split("::", "::") == C{}); CHECK(split("::", "::") == C{});