Refactored test cases implementation
This commit is contained in:
@@ -10,11 +10,12 @@ diagrams:
|
|||||||
start_from:
|
start_from:
|
||||||
- usr: "c:@F@main#I#**1C#"
|
- usr: "c:@F@main#I#**1C#"
|
||||||
include:
|
include:
|
||||||
namespace:
|
namespaces:
|
||||||
- clanguml
|
- clanguml
|
||||||
exclude:
|
exclude:
|
||||||
namespace:
|
namespaces:
|
||||||
- std
|
- std
|
||||||
|
- CLI
|
||||||
plantuml:
|
plantuml:
|
||||||
before:
|
before:
|
||||||
- "' main test sequence diagram"
|
- "' main test sequence diagram"
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ find_package(yaml-cpp REQUIRED)
|
|||||||
message(STATUS "Checking for libclang...")
|
message(STATUS "Checking for libclang...")
|
||||||
find_package(LibClang REQUIRED)
|
find_package(LibClang REQUIRED)
|
||||||
|
|
||||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17 -O3 ${LIBCLANG_CXXFLAGS}")
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17 -fno-limit-debug-info ${LIBCLANG_CXXFLAGS}")
|
||||||
|
|
||||||
# Thirdparty sources
|
# Thirdparty sources
|
||||||
set(THIRDPARTY_HEADERS_DIR ${PROJECT_SOURCE_DIR}/thirdparty/)
|
set(THIRDPARTY_HEADERS_DIR ${PROJECT_SOURCE_DIR}/thirdparty/)
|
||||||
|
|||||||
@@ -18,13 +18,41 @@ struct plantuml {
|
|||||||
std::vector<std::string> after;
|
std::vector<std::string> after;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct filter {
|
||||||
|
std::vector<std::string> namespaces;
|
||||||
|
};
|
||||||
|
|
||||||
struct diagram {
|
struct diagram {
|
||||||
virtual ~diagram() = default;
|
virtual ~diagram() = default;
|
||||||
|
|
||||||
std::string name;
|
std::string name;
|
||||||
std::vector<std::string> glob;
|
std::vector<std::string> glob;
|
||||||
std::vector<std::string> using_namespace;
|
std::vector<std::string> using_namespace;
|
||||||
|
|
||||||
|
filter include;
|
||||||
|
filter exclude;
|
||||||
|
|
||||||
plantuml puml;
|
plantuml puml;
|
||||||
|
|
||||||
|
bool should_include(const std::string &name) const
|
||||||
|
{
|
||||||
|
for (const auto &ex : exclude.namespaces) {
|
||||||
|
if (name.find(ex) == 0)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If no inclusive namespaces are provided,
|
||||||
|
// allow all
|
||||||
|
if (include.namespaces.empty())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
for (const auto &in : include.namespaces) {
|
||||||
|
if (name.find(in) == 0)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct source_location {
|
struct source_location {
|
||||||
@@ -34,7 +62,7 @@ struct source_location {
|
|||||||
// std::variant requires unique types, so we cannot add
|
// std::variant requires unique types, so we cannot add
|
||||||
// marker here, we need sth like boost::mp_unique
|
// marker here, we need sth like boost::mp_unique
|
||||||
// type function
|
// type function
|
||||||
using variant = std::variant<usr, file>;
|
using variant = std::variant<usr, /* marker, */ file>;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class class_scopes { public_, protected_, private_ };
|
enum class class_scopes { public_, protected_, private_ };
|
||||||
@@ -84,6 +112,7 @@ config load(const std::string &config_file);
|
|||||||
namespace YAML {
|
namespace YAML {
|
||||||
using clanguml::config::class_diagram;
|
using clanguml::config::class_diagram;
|
||||||
using clanguml::config::config;
|
using clanguml::config::config;
|
||||||
|
using clanguml::config::filter;
|
||||||
using clanguml::config::plantuml;
|
using clanguml::config::plantuml;
|
||||||
using clanguml::config::sequence_diagram;
|
using clanguml::config::sequence_diagram;
|
||||||
using clanguml::config::source_location;
|
using clanguml::config::source_location;
|
||||||
@@ -140,6 +169,18 @@ template <> struct convert<plantuml> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//
|
||||||
|
// filter Yaml decoder
|
||||||
|
//
|
||||||
|
template <> struct convert<filter> {
|
||||||
|
static bool decode(const Node &node, filter &rhs)
|
||||||
|
{
|
||||||
|
if (node["namespaces"])
|
||||||
|
rhs.namespaces = node["namespaces"].as<decltype(rhs.namespaces)>();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
//
|
//
|
||||||
// sequence_diagram Yaml decoder
|
// sequence_diagram Yaml decoder
|
||||||
//
|
//
|
||||||
@@ -151,6 +192,12 @@ template <> struct convert<sequence_diagram> {
|
|||||||
rhs.glob = node["glob"].as<std::vector<std::string>>();
|
rhs.glob = node["glob"].as<std::vector<std::string>>();
|
||||||
rhs.puml = node["plantuml"].as<plantuml>();
|
rhs.puml = node["plantuml"].as<plantuml>();
|
||||||
|
|
||||||
|
if (node["include"])
|
||||||
|
rhs.include = node["include"].as<decltype(rhs.include)>();
|
||||||
|
|
||||||
|
if (node["exclude"])
|
||||||
|
rhs.exclude = node["exclude"].as<decltype(rhs.exclude)>();
|
||||||
|
|
||||||
if (node["start_from"])
|
if (node["start_from"])
|
||||||
rhs.start_from = node["start_from"].as<decltype(rhs.start_from)>();
|
rhs.start_from = node["start_from"].as<decltype(rhs.start_from)>();
|
||||||
return true;
|
return true;
|
||||||
@@ -176,14 +223,13 @@ template <> struct convert<config> {
|
|||||||
|
|
||||||
for (const auto &d : diagrams) {
|
for (const auto &d : diagrams) {
|
||||||
const auto diagram_type = d.second["type"].as<std::string>();
|
const auto diagram_type = d.second["type"].as<std::string>();
|
||||||
|
auto name = d.first.as<std::string>();
|
||||||
if (diagram_type == "class") {
|
if (diagram_type == "class") {
|
||||||
rhs.diagrams[d.first.as<std::string>()] =
|
rhs.diagrams[name] = std::make_shared<class_diagram>(
|
||||||
std::make_shared<class_diagram>(
|
|
||||||
d.second.as<class_diagram>());
|
d.second.as<class_diagram>());
|
||||||
}
|
}
|
||||||
if (diagram_type == "sequence") {
|
if (diagram_type == "sequence") {
|
||||||
rhs.diagrams[d.first.as<std::string>()] =
|
rhs.diagrams[name] = std::make_shared<sequence_diagram>(
|
||||||
std::make_shared<sequence_diagram>(
|
|
||||||
d.second.as<sequence_diagram>());
|
d.second.as<sequence_diagram>());
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -191,6 +237,7 @@ template <> struct convert<config> {
|
|||||||
"Diagrams of type {} are not supported at the moment... ",
|
"Diagrams of type {} are not supported at the moment... ",
|
||||||
diagram_type);
|
diagram_type);
|
||||||
}
|
}
|
||||||
|
rhs.diagrams[name]->name = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -14,7 +14,13 @@ compilation_database::compilation_database(CXCompilationDatabase &&d)
|
|||||||
|
|
||||||
compilation_database::~compilation_database()
|
compilation_database::~compilation_database()
|
||||||
{
|
{
|
||||||
clang_CompilationDatabase_dispose(m_database);
|
//clang_CompilationDatabase_dispose(m_database);
|
||||||
|
}
|
||||||
|
|
||||||
|
compilation_database::compilation_database(compilation_database &&d)
|
||||||
|
: m_database{std::move(d.m_database)}
|
||||||
|
, m_index{std::move(d.m_index)}
|
||||||
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
compilation_database compilation_database::from_directory(
|
compilation_database compilation_database::from_directory(
|
||||||
|
|||||||
@@ -15,6 +15,8 @@ public:
|
|||||||
compilation_database(CXCompilationDatabase &&d);
|
compilation_database(CXCompilationDatabase &&d);
|
||||||
~compilation_database();
|
~compilation_database();
|
||||||
|
|
||||||
|
compilation_database(compilation_database &&d);
|
||||||
|
|
||||||
CXCompilationDatabase &db();
|
CXCompilationDatabase &db();
|
||||||
|
|
||||||
CXIndex &index();
|
CXIndex &index();
|
||||||
|
|||||||
@@ -52,8 +52,7 @@ int main(int argc, const char *argv[])
|
|||||||
spdlog::info("Loading compilation database from {} directory",
|
spdlog::info("Loading compilation database from {} directory",
|
||||||
config.compilation_database_dir);
|
config.compilation_database_dir);
|
||||||
|
|
||||||
auto db =
|
auto db = compilation_database::from_directory(config.compilation_database_dir);
|
||||||
compilation_database::from_directory(config.compilation_database_dir);
|
|
||||||
|
|
||||||
for (const auto &[name, diagram] : config.diagrams) {
|
for (const auto &[name, diagram] : config.diagrams) {
|
||||||
using clanguml::config::class_diagram;
|
using clanguml::config::class_diagram;
|
||||||
@@ -82,5 +81,6 @@ int main(int argc, const char *argv[])
|
|||||||
|
|
||||||
ofs.close();
|
ofs.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -156,7 +156,7 @@ clanguml::model::sequence_diagram::diagram generate(
|
|||||||
spdlog::debug("Cursor name: {}",
|
spdlog::debug("Cursor name: {}",
|
||||||
clang_getCString(clang_getCursorDisplayName(cursor)));
|
clang_getCString(clang_getCursorDisplayName(cursor)));
|
||||||
|
|
||||||
clanguml::visitor::sequence_diagram::tu_context ctx(d);
|
clanguml::visitor::sequence_diagram::tu_context ctx(d, diagram);
|
||||||
auto res = clang_visitChildren(cursor,
|
auto res = clang_visitChildren(cursor,
|
||||||
clanguml::visitor::sequence_diagram::translation_unit_visitor,
|
clanguml::visitor::sequence_diagram::translation_unit_visitor,
|
||||||
&ctx);
|
&ctx);
|
||||||
|
|||||||
@@ -21,14 +21,16 @@ using clanguml::model::sequence_diagram::message;
|
|||||||
using clanguml::model::sequence_diagram::message_t;
|
using clanguml::model::sequence_diagram::message_t;
|
||||||
|
|
||||||
struct tu_context {
|
struct tu_context {
|
||||||
tu_context(diagram &d_)
|
tu_context(diagram &d_, const clanguml::config::sequence_diagram &config_)
|
||||||
: d{d_}
|
: d{d_}
|
||||||
|
, config{config_}
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::string> namespace_;
|
std::vector<std::string> namespace_;
|
||||||
cx::cursor current_method;
|
cx::cursor current_method;
|
||||||
clanguml::model::sequence_diagram::diagram &d;
|
clanguml::model::sequence_diagram::diagram &d;
|
||||||
|
const clanguml::config::sequence_diagram &config;
|
||||||
};
|
};
|
||||||
|
|
||||||
static enum CXChildVisitResult translation_unit_visitor(
|
static enum CXChildVisitResult translation_unit_visitor(
|
||||||
@@ -71,20 +73,21 @@ static enum CXChildVisitResult translation_unit_visitor(
|
|||||||
std::string file{clang_getCString(clang_getFileName(f))};
|
std::string file{clang_getCString(clang_getFileName(f))};
|
||||||
|
|
||||||
auto &d = ctx->d;
|
auto &d = ctx->d;
|
||||||
|
auto &config = ctx->config;
|
||||||
if (referenced.kind() == CXCursor_CXXMethod) {
|
if (referenced.kind() == CXCursor_CXXMethod) {
|
||||||
if (true/*sp_name.find("clanguml::") == 0 ||
|
if (config.should_include(sp_name)) {
|
||||||
clang_Location_isFromMainFile(cursor.location())*/) {
|
|
||||||
// Get calling object
|
// Get calling object
|
||||||
std::string caller{};
|
std::string caller{};
|
||||||
if (ctx->current_method.semantic_parent()
|
if (ctx->current_method.semantic_parent()
|
||||||
.is_translation_unit() ||
|
.is_translation_unit() ||
|
||||||
ctx->current_method.semantic_parent().is_namespace()) {
|
ctx->current_method.semantic_parent().is_namespace()) {
|
||||||
caller =
|
caller = ctx->current_method.semantic_parent()
|
||||||
ctx->current_method.semantic_parent().fully_qualified() +
|
.fully_qualified() +
|
||||||
"::" + ctx->current_method.spelling() + "()";
|
"::" + ctx->current_method.spelling() + "()";
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
caller = ctx->current_method.semantic_parent().fully_qualified();
|
caller = ctx->current_method.semantic_parent()
|
||||||
|
.fully_qualified();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto caller_usr = ctx->current_method.usr();
|
auto caller_usr = ctx->current_method.usr();
|
||||||
|
|||||||
@@ -10,6 +10,9 @@ std::string namespace_relative(
|
|||||||
const std::vector<std::string> &namespaces, const std::string &n)
|
const std::vector<std::string> &namespaces, const std::string &n)
|
||||||
{
|
{
|
||||||
for (const auto &ns : namespaces) {
|
for (const auto &ns : namespaces) {
|
||||||
|
if(ns.empty())
|
||||||
|
continue;
|
||||||
|
|
||||||
if (n == ns)
|
if (n == ns)
|
||||||
return "";
|
return "";
|
||||||
|
|
||||||
|
|||||||
@@ -6,10 +6,10 @@ diagrams:
|
|||||||
glob:
|
glob:
|
||||||
- ../../tests/t00001/t00001.cc
|
- ../../tests/t00001/t00001.cc
|
||||||
include:
|
include:
|
||||||
namespace:
|
namespaces:
|
||||||
- clanguml::t00001
|
- clanguml::t00001
|
||||||
exclude:
|
exclude:
|
||||||
namespace:
|
namespaces:
|
||||||
- clanguml::t00001::detail
|
- clanguml::t00001::detail
|
||||||
using_namespace:
|
using_namespace:
|
||||||
- clanguml::t00001
|
- clanguml::t00001
|
||||||
|
|||||||
@@ -9,31 +9,89 @@
|
|||||||
#include "uml/sequence_diagram_visitor.h"
|
#include "uml/sequence_diagram_visitor.h"
|
||||||
|
|
||||||
#include "catch.h"
|
#include "catch.h"
|
||||||
|
|
||||||
#include <complex>
|
#include <complex>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
using Catch::Matchers::Contains;
|
||||||
|
using Catch::Matchers::EndsWith;
|
||||||
|
using Catch::Matchers::StartsWith;
|
||||||
|
using Catch::Matchers::VectorContains;
|
||||||
|
using clanguml::cx::compilation_database;
|
||||||
|
|
||||||
|
auto load_config(const std::string &test_name)
|
||||||
|
{
|
||||||
|
auto config = clanguml::config::load(test_name + "/.clanguml");
|
||||||
|
|
||||||
|
auto db = clanguml::cx::compilation_database::from_directory(
|
||||||
|
config.compilation_database_dir);
|
||||||
|
|
||||||
|
return std::make_pair(std::move(config), std::move(db));
|
||||||
|
}
|
||||||
|
|
||||||
|
auto generate_sequence_diagram(compilation_database &db,
|
||||||
|
std::shared_ptr<clanguml::config::diagram> diagram)
|
||||||
|
{
|
||||||
|
auto diagram_model =
|
||||||
|
clanguml::generators::sequence_diagram::generate(db, diagram->name,
|
||||||
|
dynamic_cast<clanguml::config::sequence_diagram &>(*diagram));
|
||||||
|
|
||||||
|
return diagram_model;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto generate_class_diagram(compilation_database &db,
|
||||||
|
std::shared_ptr<clanguml::config::class_diagram> diagram)
|
||||||
|
{
|
||||||
|
auto diagram_model =
|
||||||
|
clanguml::generators::class_diagram::generate(db, diagram->name,
|
||||||
|
dynamic_cast<clanguml::config::class_diagram &>(*diagram));
|
||||||
|
|
||||||
|
return diagram_model;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string generate_sequence_puml(
|
||||||
|
std::shared_ptr<clanguml::config::diagram> config,
|
||||||
|
clanguml::model::sequence_diagram::diagram &model)
|
||||||
|
{
|
||||||
|
using namespace clanguml::generators::sequence_diagram::puml;
|
||||||
|
|
||||||
|
std::stringstream ss;
|
||||||
|
|
||||||
|
ss << generator(
|
||||||
|
dynamic_cast<clanguml::config::sequence_diagram &>(*config), model);
|
||||||
|
|
||||||
|
return ss.str();
|
||||||
|
}
|
||||||
|
|
||||||
TEST_CASE("Test t00001", "[unit-test]")
|
TEST_CASE("Test t00001", "[unit-test]")
|
||||||
{
|
{
|
||||||
spdlog::set_level(spdlog::level::debug);
|
spdlog::set_level(spdlog::level::debug);
|
||||||
|
|
||||||
// REQUIRE(2 + 5 == 7);
|
auto [config, db] = load_config("t00001");
|
||||||
std::cout << "RUNNING TEST IN " << std::filesystem::current_path()
|
|
||||||
<< std::endl;
|
|
||||||
|
|
||||||
auto config = clanguml::config::load("t00001/.clanguml");
|
|
||||||
|
|
||||||
auto db = clanguml::cx::compilation_database::from_directory(
|
|
||||||
config.compilation_database_dir);
|
|
||||||
|
|
||||||
auto diagram = config.diagrams["t00001_sequence"];
|
auto diagram = config.diagrams["t00001_sequence"];
|
||||||
auto diagram_model =
|
|
||||||
clanguml::generators::sequence_diagram::generate(db, "t00001_sequence",
|
|
||||||
dynamic_cast<clanguml::config::sequence_diagram &>(*diagram));
|
|
||||||
|
|
||||||
REQUIRE(diagram_model.name == "t00001_sequence");
|
REQUIRE(diagram->include.namespaces.size() == 1);
|
||||||
|
REQUIRE_THAT(diagram->include.namespaces,
|
||||||
|
VectorContains(std::string{"clanguml::t00001"}));
|
||||||
|
|
||||||
auto generator = clanguml::generators::sequence_diagram::puml::generator(
|
REQUIRE(diagram->exclude.namespaces.size() == 1);
|
||||||
dynamic_cast<clanguml::config::sequence_diagram &>(*diagram), diagram_model);
|
REQUIRE_THAT(diagram->exclude.namespaces,
|
||||||
std::cout << generator;
|
VectorContains(std::string{"clanguml::t00001::detail"}));
|
||||||
|
|
||||||
|
REQUIRE(diagram->should_include("clanguml::t00001::A"));
|
||||||
|
REQUIRE(!diagram->should_include("clanguml::t00001::detail::C"));
|
||||||
|
REQUIRE(!diagram->should_include("std::vector"));
|
||||||
|
|
||||||
|
REQUIRE(diagram->name == "t00001_sequence");
|
||||||
|
|
||||||
|
auto model = generate_sequence_diagram(db, diagram);
|
||||||
|
|
||||||
|
REQUIRE(model.name == "t00001_sequence");
|
||||||
|
|
||||||
|
auto puml = generate_sequence_puml(diagram, model);
|
||||||
|
|
||||||
|
REQUIRE_THAT(puml, StartsWith("@startuml"));
|
||||||
|
REQUIRE_THAT(puml, EndsWith("@enduml\n"));
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user