Merge pull request #6 from bkryza/add-template-overload-pattern-test-case
Add template overload pattern test case
This commit is contained in:
2
Makefile
2
Makefile
@@ -62,4 +62,4 @@ init_compile_commands: debug
|
|||||||
|
|
||||||
.PHONY: clang-format
|
.PHONY: clang-format
|
||||||
clang-format:
|
clang-format:
|
||||||
docker run --rm -v $(CURDIR):/root/sources bkryza/clang-format-check:1.2
|
docker run --rm -v $(CURDIR):/root/sources bkryza/clang-format-check:1.3
|
||||||
|
|||||||
11
README.md
11
README.md
@@ -163,6 +163,17 @@ The following decorators are currently supported:
|
|||||||
- [aggregation](docs/test_cases/t00030.md) - document the property as aggregation
|
- [aggregation](docs/test_cases/t00030.md) - document the property as aggregation
|
||||||
- [style](docs/test_cases/t00031.md) - add PlantUML style to a C++ entity
|
- [style](docs/test_cases/t00031.md) - add PlantUML style to a C++ entity
|
||||||
|
|
||||||
|
##### Doxygen integration
|
||||||
|
`clang-uml` can be omitted completed in , by adding the following
|
||||||
|
lines to the Doxygen config file:
|
||||||
|
|
||||||
|
```
|
||||||
|
ALIASES += clanguml=""
|
||||||
|
ALIASES += clanguml{1}=""
|
||||||
|
ALIASES += clanguml{2}=""
|
||||||
|
ALIASES += clanguml{3}=""
|
||||||
|
```
|
||||||
|
|
||||||
### Sequence diagrams
|
### Sequence diagrams
|
||||||
|
|
||||||
#### Example
|
#### Example
|
||||||
|
|||||||
@@ -30,6 +30,7 @@
|
|||||||
* [t00029](./test_cases/t00029.md) - PlantUML skip decorator test case
|
* [t00029](./test_cases/t00029.md) - PlantUML skip decorator test case
|
||||||
* [t00030](./test_cases/t00030.md) - PlantUML relationship decorators test case
|
* [t00030](./test_cases/t00030.md) - PlantUML relationship decorators test case
|
||||||
* [t00031](./test_cases/t00031.md) - PlantUML style decorator test case
|
* [t00031](./test_cases/t00031.md) - PlantUML style decorator test case
|
||||||
|
* [t00032](./test_cases/t00032.md) - Class template with template base classes test case
|
||||||
## Sequence diagrams
|
## Sequence diagrams
|
||||||
* [t20001](./test_cases/t20001.md) - Basic sequence diagram
|
* [t20001](./test_cases/t20001.md) - Basic sequence diagram
|
||||||
## Configuration diagrams
|
## Configuration diagrams
|
||||||
|
|||||||
@@ -28,7 +28,8 @@ class A {
|
|||||||
}
|
}
|
||||||
|
|
||||||
namespace ns2_v0_9_0 {
|
namespace ns2_v0_9_0 {
|
||||||
class [[deprecated]] A {};
|
class [[deprecated]] A {
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|||||||
62
docs/test_cases/t00032.md
Normal file
62
docs/test_cases/t00032.md
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
# t00032 - Class template with template base classes test case
|
||||||
|
## Config
|
||||||
|
```yaml
|
||||||
|
compilation_database_dir: ..
|
||||||
|
output_directory: puml
|
||||||
|
diagrams:
|
||||||
|
t00032_class:
|
||||||
|
type: class
|
||||||
|
glob:
|
||||||
|
- ../../tests/t00032/t00032.cc
|
||||||
|
using_namespace:
|
||||||
|
- clanguml::t00032
|
||||||
|
include:
|
||||||
|
namespaces:
|
||||||
|
- clanguml::t00032
|
||||||
|
|
||||||
|
```
|
||||||
|
## Source code
|
||||||
|
File t00032.cc
|
||||||
|
```cpp
|
||||||
|
#include <memory>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace clanguml {
|
||||||
|
namespace t00032 {
|
||||||
|
|
||||||
|
struct Base {
|
||||||
|
};
|
||||||
|
|
||||||
|
struct TBase {
|
||||||
|
};
|
||||||
|
|
||||||
|
struct A {
|
||||||
|
void operator()() { }
|
||||||
|
};
|
||||||
|
|
||||||
|
struct B {
|
||||||
|
void operator()() { }
|
||||||
|
};
|
||||||
|
|
||||||
|
struct C {
|
||||||
|
void operator()() { }
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T, typename L, typename... Ts>
|
||||||
|
struct Overload : public Base, public T, public Ts... {
|
||||||
|
using Ts::operator()...;
|
||||||
|
L counter;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class... Ts> Overload(Ts...) -> Overload<Ts...>;
|
||||||
|
|
||||||
|
struct R {
|
||||||
|
Overload<TBase, int, A, B, C> overload;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace t00032
|
||||||
|
} // namespace clanguml
|
||||||
|
|
||||||
|
```
|
||||||
|
## Generated UML diagrams
|
||||||
|

|
||||||
BIN
docs/test_cases/t00032_class.png
Normal file
BIN
docs/test_cases/t00032_class.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 24 KiB |
@@ -31,6 +31,8 @@
|
|||||||
#include <cppast/cpp_variable.hpp>
|
#include <cppast/cpp_variable.hpp>
|
||||||
#include <spdlog/spdlog.h>
|
#include <spdlog/spdlog.h>
|
||||||
|
|
||||||
|
#include <deque>
|
||||||
|
|
||||||
namespace clanguml {
|
namespace clanguml {
|
||||||
namespace visitor {
|
namespace visitor {
|
||||||
namespace class_diagram {
|
namespace class_diagram {
|
||||||
@@ -1185,6 +1187,8 @@ class_ tu_visitor::build_template_instantiation(
|
|||||||
class_ tinst;
|
class_ tinst;
|
||||||
std::string full_template_name;
|
std::string full_template_name;
|
||||||
|
|
||||||
|
std::deque<std::tuple<std::string, int, bool>> template_base_params{};
|
||||||
|
|
||||||
if (t.primary_template().get(ctx.entity_index).size()) {
|
if (t.primary_template().get(ctx.entity_index).size()) {
|
||||||
const auto &primary_template_ref =
|
const auto &primary_template_ref =
|
||||||
static_cast<const cppast::cpp_class_template &>(
|
static_cast<const cppast::cpp_class_template &>(
|
||||||
@@ -1201,6 +1205,54 @@ class_ tu_visitor::build_template_instantiation(
|
|||||||
if (full_template_name.back() == ':')
|
if (full_template_name.back() == ':')
|
||||||
tinst.name = full_template_name + tinst.name;
|
tinst.name = full_template_name + tinst.name;
|
||||||
|
|
||||||
|
std::vector<std::pair<std::string, bool>> template_parameter_names{};
|
||||||
|
if (primary_template_ref.scope_name().has_value()) {
|
||||||
|
for (const auto &tp : primary_template_ref.scope_name()
|
||||||
|
.value()
|
||||||
|
.template_parameters()) {
|
||||||
|
template_parameter_names.emplace_back(
|
||||||
|
tp.name(), tp.is_variadic());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the primary template has any base classes
|
||||||
|
int base_index = 0;
|
||||||
|
for (const auto &base : primary_template_ref.bases()) {
|
||||||
|
if (base.kind() == cppast::cpp_entity_kind::base_class_t) {
|
||||||
|
const auto &base_class =
|
||||||
|
static_cast<const cppast::cpp_base_class &>(base);
|
||||||
|
|
||||||
|
const auto base_class_name =
|
||||||
|
cppast::to_string(base_class.type());
|
||||||
|
|
||||||
|
LOG_DBG("Found template instantiation base: {}, {}, {}",
|
||||||
|
cppast::to_string(base.kind()), base_class_name,
|
||||||
|
base_index);
|
||||||
|
|
||||||
|
// Check if any of the primary template arguments has a
|
||||||
|
// parameter equal to this type
|
||||||
|
auto it = std::find_if(template_parameter_names.begin(),
|
||||||
|
template_parameter_names.end(),
|
||||||
|
[&base_class_name](
|
||||||
|
const auto &p) { return p.first == base_class_name; });
|
||||||
|
|
||||||
|
if (it != template_parameter_names.end()) {
|
||||||
|
// Found base class which is a template parameter
|
||||||
|
LOG_DBG("Found base class which is a template parameter "
|
||||||
|
"{}, {}, {}",
|
||||||
|
it->first, it->second,
|
||||||
|
std::distance(template_parameter_names.begin(), it));
|
||||||
|
template_base_params.emplace_back(it->first, it->second,
|
||||||
|
std::distance(template_parameter_names.begin(), it));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// This is a regular base class - it is handled by
|
||||||
|
// process_template
|
||||||
|
}
|
||||||
|
}
|
||||||
|
base_index++;
|
||||||
|
}
|
||||||
|
|
||||||
if (primary_template_ref.user_data()) {
|
if (primary_template_ref.user_data()) {
|
||||||
tinst.base_template_usr =
|
tinst.base_template_usr =
|
||||||
static_cast<const char *>(primary_template_ref.user_data());
|
static_cast<const char *>(primary_template_ref.user_data());
|
||||||
@@ -1232,7 +1284,11 @@ class_ tu_visitor::build_template_instantiation(
|
|||||||
|
|
||||||
tinst.is_template_instantiation = true;
|
tinst.is_template_instantiation = true;
|
||||||
|
|
||||||
|
// Process template argumetns
|
||||||
|
int arg_index{0};
|
||||||
|
bool variadic_params{false};
|
||||||
for (const auto &targ : t.arguments().value()) {
|
for (const auto &targ : t.arguments().value()) {
|
||||||
|
bool add_template_argument_as_base_class{false};
|
||||||
class_template ct;
|
class_template ct;
|
||||||
if (targ.type()) {
|
if (targ.type()) {
|
||||||
ct.type = cppast::to_string(targ.type().value());
|
ct.type = cppast::to_string(targ.type().value());
|
||||||
@@ -1250,6 +1306,31 @@ class_ tu_visitor::build_template_instantiation(
|
|||||||
.as_string();
|
.as_string();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// In case any of the template arguments are base classes, add
|
||||||
|
// them as parents of the current template instantiation class
|
||||||
|
if (template_base_params.size() > 0) {
|
||||||
|
auto [arg_name, is_variadic, index] = template_base_params.front();
|
||||||
|
if (variadic_params)
|
||||||
|
add_template_argument_as_base_class = true;
|
||||||
|
else {
|
||||||
|
variadic_params = is_variadic;
|
||||||
|
if (arg_index == index) {
|
||||||
|
add_template_argument_as_base_class = true;
|
||||||
|
template_base_params.pop_front();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (add_template_argument_as_base_class) {
|
||||||
|
LOG_DBG("Adding template argument '{}' as base class", ct.type);
|
||||||
|
|
||||||
|
class_parent cp;
|
||||||
|
cp.access = class_parent::access_t::kPublic;
|
||||||
|
cp.name = ct.type;
|
||||||
|
|
||||||
|
tinst.bases.emplace_back(std::move(cp));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
LOG_DBG("Adding template argument '{}'", ct.type);
|
LOG_DBG("Adding template argument '{}'", ct.type);
|
||||||
|
|
||||||
tinst.templates.emplace_back(std::move(ct));
|
tinst.templates.emplace_back(std::move(ct));
|
||||||
|
|||||||
@@ -853,8 +853,9 @@ constexpr auto operator"" _catch_sr(
|
|||||||
INTERNAL_CATCH_MAKE_TYPE_LIST2(INTERNAL_CATCH_REMOVE_PARENS(__VA_ARGS__))
|
INTERNAL_CATCH_MAKE_TYPE_LIST2(INTERNAL_CATCH_REMOVE_PARENS(__VA_ARGS__))
|
||||||
#else
|
#else
|
||||||
#define INTERNAL_CATCH_MAKE_TYPE_LIST2(...) \
|
#define INTERNAL_CATCH_MAKE_TYPE_LIST2(...) \
|
||||||
INTERNAL_CATCH_EXPAND_VARGS(decltype( \
|
INTERNAL_CATCH_EXPAND_VARGS( \
|
||||||
get_wrapper<INTERNAL_CATCH_REMOVE_PARENS_GEN(__VA_ARGS__)>()))
|
decltype(get_wrapper<INTERNAL_CATCH_REMOVE_PARENS_GEN( \
|
||||||
|
__VA_ARGS__)>()))
|
||||||
#define INTERNAL_CATCH_MAKE_TYPE_LIST(...) \
|
#define INTERNAL_CATCH_MAKE_TYPE_LIST(...) \
|
||||||
INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_MAKE_TYPE_LIST2( \
|
INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_MAKE_TYPE_LIST2( \
|
||||||
INTERNAL_CATCH_REMOVE_PARENS(__VA_ARGS__)))
|
INTERNAL_CATCH_REMOVE_PARENS(__VA_ARGS__)))
|
||||||
@@ -1277,8 +1278,8 @@ template <typename> struct true_given : std::true_type {
|
|||||||
};
|
};
|
||||||
struct is_callable_tester {
|
struct is_callable_tester {
|
||||||
template <typename Fun, typename... Args>
|
template <typename Fun, typename... Args>
|
||||||
true_given<decltype(
|
true_given<decltype(std::declval<Fun>()(
|
||||||
std::declval<Fun>()(std::declval<Args>()...))> static test(int);
|
std::declval<Args>()...))> static test(int);
|
||||||
template <typename...> std::false_type static test(...);
|
template <typename...> std::false_type static test(...);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1634,8 +1635,8 @@ struct AutoReg : NonCopyable {
|
|||||||
}; \
|
}; \
|
||||||
static int INTERNAL_CATCH_UNIQUE_NAME(globalRegistrar) = []() { \
|
static int INTERNAL_CATCH_UNIQUE_NAME(globalRegistrar) = []() { \
|
||||||
using TestInit = typename create<TestName, \
|
using TestInit = typename create<TestName, \
|
||||||
decltype( \
|
decltype(get_wrapper<INTERNAL_CATCH_REMOVE_PARENS( \
|
||||||
get_wrapper<INTERNAL_CATCH_REMOVE_PARENS(TmplTypes)>()), \
|
TmplTypes)>()), \
|
||||||
TypeList<INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES( \
|
TypeList<INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES( \
|
||||||
INTERNAL_CATCH_REMOVE_PARENS(TypesList))>>::type; \
|
INTERNAL_CATCH_REMOVE_PARENS(TypesList))>>::type; \
|
||||||
TestInit t; \
|
TestInit t; \
|
||||||
@@ -1851,8 +1852,8 @@ struct AutoReg : NonCopyable {
|
|||||||
}; \
|
}; \
|
||||||
static int INTERNAL_CATCH_UNIQUE_NAME(globalRegistrar) = []() { \
|
static int INTERNAL_CATCH_UNIQUE_NAME(globalRegistrar) = []() { \
|
||||||
using TestInit = typename create<TestNameClass, \
|
using TestInit = typename create<TestNameClass, \
|
||||||
decltype( \
|
decltype(get_wrapper<INTERNAL_CATCH_REMOVE_PARENS( \
|
||||||
get_wrapper<INTERNAL_CATCH_REMOVE_PARENS(TmplTypes)>()), \
|
TmplTypes)>()), \
|
||||||
TypeList<INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES( \
|
TypeList<INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES( \
|
||||||
INTERNAL_CATCH_REMOVE_PARENS(TypesList))>>::type; \
|
INTERNAL_CATCH_REMOVE_PARENS(TypesList))>>::type; \
|
||||||
TestInit t; \
|
TestInit t; \
|
||||||
@@ -2194,8 +2195,9 @@ template <typename T> std::string rawMemoryToString(const T &object)
|
|||||||
|
|
||||||
template <typename T> class IsStreamInsertable {
|
template <typename T> class IsStreamInsertable {
|
||||||
template <typename Stream, typename U>
|
template <typename Stream, typename U>
|
||||||
static auto test(int) -> decltype(
|
static auto test(int)
|
||||||
std::declval<Stream &>() << std::declval<U>(), std::true_type());
|
-> decltype(std::declval<Stream &>() << std::declval<U>(),
|
||||||
|
std::true_type());
|
||||||
|
|
||||||
template <typename, typename> static auto test(...) -> std::false_type;
|
template <typename, typename> static auto test(...) -> std::false_type;
|
||||||
|
|
||||||
@@ -4698,8 +4700,10 @@ struct IGeneratorTracker {
|
|||||||
|
|
||||||
namespace Catch {
|
namespace Catch {
|
||||||
#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
|
#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
|
||||||
template <typename Ex>
|
template <typename Ex> [[noreturn]] void throw_exception(Ex const &e)
|
||||||
[[noreturn]] void throw_exception(Ex const &e) { throw e; }
|
{
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
#else // ^^ Exceptions are enabled // Exceptions are disabled vv
|
#else // ^^ Exceptions are enabled // Exceptions are disabled vv
|
||||||
[[noreturn]] void throw_exception(std::exception const &e);
|
[[noreturn]] void throw_exception(std::exception const &e);
|
||||||
#endif
|
#endif
|
||||||
@@ -8153,8 +8157,7 @@ EnvironmentEstimate<FloatDuration<Clock>> estimate_clock_cost(
|
|||||||
volatile auto ignored = Clock::now();
|
volatile auto ignored = Clock::now();
|
||||||
(void)ignored;
|
(void)ignored;
|
||||||
}
|
}
|
||||||
})
|
}).elapsed;
|
||||||
.elapsed;
|
|
||||||
};
|
};
|
||||||
time_clock(1);
|
time_clock(1);
|
||||||
int iters = clock_cost_estimation_iterations;
|
int iters = clock_cost_estimation_iterations;
|
||||||
@@ -11868,7 +11871,8 @@ void formatReconstructedExpression(std::ostream &os, std::string const &lhs,
|
|||||||
namespace Catch {
|
namespace Catch {
|
||||||
#if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) && \
|
#if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) && \
|
||||||
!defined(CATCH_CONFIG_DISABLE_EXCEPTIONS_CUSTOM_HANDLER)
|
!defined(CATCH_CONFIG_DISABLE_EXCEPTIONS_CUSTOM_HANDLER)
|
||||||
[[noreturn]] void throw_exception(std::exception const &e) {
|
[[noreturn]] void throw_exception(std::exception const &e)
|
||||||
|
{
|
||||||
Catch::cerr()
|
Catch::cerr()
|
||||||
<< "Catch will terminate because it needed to throw an exception.\n"
|
<< "Catch will terminate because it needed to throw an exception.\n"
|
||||||
<< "The message was: " << e.what() << '\n';
|
<< "The message was: " << e.what() << '\n';
|
||||||
@@ -11881,8 +11885,10 @@ namespace Catch {
|
|||||||
throw_exception(std::logic_error(msg));
|
throw_exception(std::logic_error(msg));
|
||||||
}
|
}
|
||||||
|
|
||||||
[[noreturn]] void throw_domain_error(
|
[[noreturn]] void throw_domain_error(std::string const &msg)
|
||||||
std::string const &msg) { throw_exception(std::domain_error(msg)); }
|
{
|
||||||
|
throw_exception(std::domain_error(msg));
|
||||||
|
}
|
||||||
|
|
||||||
[[noreturn]] void throw_runtime_error(std::string const &msg)
|
[[noreturn]] void throw_runtime_error(std::string const &msg)
|
||||||
{
|
{
|
||||||
@@ -15056,8 +15062,8 @@ int Session::runInternal()
|
|||||||
// the return value to 255 prevents false negative when some multiple
|
// the return value to 255 prevents false negative when some multiple
|
||||||
// of 256 tests has failed
|
// of 256 tests has failed
|
||||||
return (std::min)(MaxExitCode,
|
return (std::min)(MaxExitCode,
|
||||||
(std::max)(
|
(std::max)(totals.error,
|
||||||
totals.error, static_cast<int>(totals.assertions.failed)));
|
static_cast<int>(totals.assertions.failed)));
|
||||||
}
|
}
|
||||||
#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
|
#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
|
||||||
catch (std::exception &ex)
|
catch (std::exception &ex)
|
||||||
|
|||||||
@@ -8,7 +8,8 @@ class A {
|
|||||||
}
|
}
|
||||||
|
|
||||||
namespace ns2_v0_9_0 {
|
namespace ns2_v0_9_0 {
|
||||||
class [[deprecated]] A {};
|
class [[deprecated]] A {
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|||||||
12
tests/t00032/.clang-uml
Normal file
12
tests/t00032/.clang-uml
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
compilation_database_dir: ..
|
||||||
|
output_directory: puml
|
||||||
|
diagrams:
|
||||||
|
t00032_class:
|
||||||
|
type: class
|
||||||
|
glob:
|
||||||
|
- ../../tests/t00032/t00032.cc
|
||||||
|
using_namespace:
|
||||||
|
- clanguml::t00032
|
||||||
|
include:
|
||||||
|
namespaces:
|
||||||
|
- clanguml::t00032
|
||||||
38
tests/t00032/t00032.cc
Normal file
38
tests/t00032/t00032.cc
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
#include <memory>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace clanguml {
|
||||||
|
namespace t00032 {
|
||||||
|
|
||||||
|
struct Base {
|
||||||
|
};
|
||||||
|
|
||||||
|
struct TBase {
|
||||||
|
};
|
||||||
|
|
||||||
|
struct A {
|
||||||
|
void operator()() { }
|
||||||
|
};
|
||||||
|
|
||||||
|
struct B {
|
||||||
|
void operator()() { }
|
||||||
|
};
|
||||||
|
|
||||||
|
struct C {
|
||||||
|
void operator()() { }
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T, typename L, typename... Ts>
|
||||||
|
struct Overload : public Base, public T, public Ts... {
|
||||||
|
using Ts::operator()...;
|
||||||
|
L counter;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class... Ts> Overload(Ts...) -> Overload<Ts...>;
|
||||||
|
|
||||||
|
struct R {
|
||||||
|
Overload<TBase, int, A, B, C> overload;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace t00032
|
||||||
|
} // namespace clanguml
|
||||||
63
tests/t00032/test_case.h
Normal file
63
tests/t00032/test_case.h
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
/**
|
||||||
|
* tests/t00032/test_case.cc
|
||||||
|
*
|
||||||
|
* Copyright (c) 2021 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("t00032", "[test-case][class]")
|
||||||
|
{
|
||||||
|
auto [config, db] = load_config("t00032");
|
||||||
|
|
||||||
|
auto diagram = config.diagrams["t00032_class"];
|
||||||
|
|
||||||
|
REQUIRE(diagram->name == "t00032_class");
|
||||||
|
|
||||||
|
REQUIRE(diagram->include.namespaces.size() == 1);
|
||||||
|
REQUIRE_THAT(diagram->include.namespaces,
|
||||||
|
VectorContains(std::string{"clanguml::t00032"}));
|
||||||
|
|
||||||
|
REQUIRE(diagram->exclude.namespaces.size() == 0);
|
||||||
|
|
||||||
|
REQUIRE(diagram->should_include("clanguml::t00032::A"));
|
||||||
|
|
||||||
|
auto model = generate_class_diagram(db, diagram);
|
||||||
|
|
||||||
|
REQUIRE(model.name == "t00032_class");
|
||||||
|
|
||||||
|
auto puml = generate_class_puml(diagram, model);
|
||||||
|
AliasMatcher _A(puml);
|
||||||
|
|
||||||
|
REQUIRE_THAT(puml, StartsWith("@startuml"));
|
||||||
|
REQUIRE_THAT(puml, EndsWith("@enduml\n"));
|
||||||
|
|
||||||
|
REQUIRE_THAT(puml, IsClass(_A("Base")));
|
||||||
|
REQUIRE_THAT(puml, IsClass(_A("TBase")));
|
||||||
|
REQUIRE_THAT(puml, IsClass(_A("A")));
|
||||||
|
REQUIRE_THAT(puml, IsClass(_A("B")));
|
||||||
|
REQUIRE_THAT(puml, IsClass(_A("C")));
|
||||||
|
REQUIRE_THAT(puml, IsClass(_A("R")));
|
||||||
|
|
||||||
|
REQUIRE_THAT(puml, IsClassTemplate("Overload", "T,L,Ts..."));
|
||||||
|
|
||||||
|
REQUIRE_THAT(puml, IsBaseClass(_A("Base"), _A("Overload<T,L,Ts...>")));
|
||||||
|
REQUIRE_THAT(
|
||||||
|
puml, IsBaseClass(_A("TBase"), _A("Overload<TBase,int,A,B,C>")));
|
||||||
|
REQUIRE_THAT(puml, IsBaseClass(_A("A"), _A("Overload<TBase,int,A,B,C>")));
|
||||||
|
REQUIRE_THAT(puml, IsBaseClass(_A("B"), _A("Overload<TBase,int,A,B,C>")));
|
||||||
|
REQUIRE_THAT(puml, IsBaseClass(_A("C"), _A("Overload<TBase,int,A,B,C>")));
|
||||||
|
|
||||||
|
save_puml(
|
||||||
|
"./" + config.output_directory + "/" + diagram->name + ".puml", puml);
|
||||||
|
}
|
||||||
@@ -135,6 +135,7 @@ using namespace clanguml::test::matchers;
|
|||||||
#include "t00029/test_case.h"
|
#include "t00029/test_case.h"
|
||||||
#include "t00030/test_case.h"
|
#include "t00030/test_case.h"
|
||||||
#include "t00031/test_case.h"
|
#include "t00031/test_case.h"
|
||||||
|
#include "t00032/test_case.h"
|
||||||
|
|
||||||
//
|
//
|
||||||
// Sequence diagram tests
|
// Sequence diagram tests
|
||||||
|
|||||||
@@ -90,6 +90,9 @@ test_cases:
|
|||||||
- name: t00031
|
- name: t00031
|
||||||
title: PlantUML style decorator test case
|
title: PlantUML style decorator test case
|
||||||
description:
|
description:
|
||||||
|
- name: t00032
|
||||||
|
title: Class template with template base classes test case
|
||||||
|
description:
|
||||||
Sequence diagrams:
|
Sequence diagrams:
|
||||||
- name: t20001
|
- name: t20001
|
||||||
title: Basic sequence diagram
|
title: Basic sequence diagram
|
||||||
|
|||||||
Reference in New Issue
Block a user