Skip to content

Commit

Permalink
Added class diagram typed elements test cases (#328)
Browse files Browse the repository at this point in the history
  • Loading branch information
bkryza committed Oct 30, 2024
1 parent 7704192 commit 92bad7d
Show file tree
Hide file tree
Showing 22 changed files with 370 additions and 15 deletions.
8 changes: 8 additions & 0 deletions src/class_diagram/model/class_element.cc
Original file line number Diff line number Diff line change
Expand Up @@ -48,4 +48,12 @@ inja::json class_element::context() const
ctx["access"] = to_string(access());
return ctx;
}

void class_element::set_qualified_name(const std::string &qn)
{
qualified_name_ = qn;
}

std::string class_element::qualified_name() const { return qualified_name_; }

} // namespace clanguml::class_diagram::model
5 changes: 5 additions & 0 deletions src/class_diagram/model/class_element.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,9 +79,14 @@ class class_element : public common::model::decorated_element,
*/
virtual inja::json context() const;

void set_qualified_name(const std::string &qn);

std::string qualified_name() const;

private:
common::model::access_t access_;
std::string name_;
std::string qualified_name_;
std::string type_;
};

Expand Down
12 changes: 11 additions & 1 deletion src/class_diagram/visitor/translation_unit_visitor.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1269,6 +1269,8 @@ void translation_unit_visitor::process_objc_ivar(
common::access_specifier_to_access_t(ivar.getAccessControl()),
field_name, field_type_str};

field.set_qualified_name(ivar.getQualifiedNameAsString());

process_comment(ivar, field);
set_source_location(ivar, field);

Expand Down Expand Up @@ -1518,6 +1520,8 @@ void translation_unit_visitor::process_method(
util::trim(method_name),
config().simplify_template_type(method_return_type)};

method.set_qualified_name(mf.getQualifiedNameAsString());

process_method_properties(mf, c, method_name, method);

process_comment(mf, method);
Expand Down Expand Up @@ -1613,6 +1617,8 @@ void translation_unit_visitor::process_objc_method(
objc_method method{common::access_specifier_to_access_t(mf.getAccess()),
util::trim(mf.getNameAsString()), method_return_type};

method.set_qualified_name(mf.getQualifiedNameAsString());

process_comment(mf, method);

// Register the source location of the field declaration
Expand Down Expand Up @@ -2214,6 +2220,8 @@ void translation_unit_visitor::process_field(
common::access_specifier_to_access_t(field_declaration.getAccess()),
field_name, config().simplify_template_type(field_type_str)};

field.set_qualified_name(field_declaration.getQualifiedNameAsString());

// Parse the field comment
process_comment(field_declaration, field);
// Register the source location of the field declaration
Expand Down Expand Up @@ -2391,7 +2399,9 @@ void translation_unit_visitor::process_field(
}
}

c.add_member(std::move(field));
if (diagram().should_include(field)) {
c.add_member(std::move(field));
}
}

void translation_unit_visitor::add_incomplete_forward_declarations()
Expand Down
69 changes: 64 additions & 5 deletions src/common/model/filters/diagram_filter.cc
Original file line number Diff line number Diff line change
Expand Up @@ -474,6 +474,62 @@ tvl::value_t element_filter::match(const diagram &d, const element &e) const
});
}

tvl::value_t element_filter::match(
const diagram & /*d*/, const class_diagram::model::class_method &m) const
{
return tvl::any_of(elements_.begin(), elements_.end(),
[&m](const auto &ef) -> tvl::value_t {
// Apply this filter only if it had `method` type, do not apply
// `any` filters to methods for backward compatibility
if (ef.type != config::element_filter_t::filtered_type::method)
return {};

return ef.name == m.qualified_name();
});
}

tvl::value_t element_filter::match(
const diagram & /*d*/, const class_diagram::model::class_member &m) const
{
return tvl::any_of(elements_.begin(), elements_.end(),
[&m](const auto &ef) -> tvl::value_t {
// Apply this filter only if it had `member` type, do not apply
// `any` filters to methods for backward compatibility
if (ef.type != config::element_filter_t::filtered_type::member)
return {};

return ef.name == m.qualified_name();
});
}

tvl::value_t element_filter::match(
const diagram & /*d*/, const class_diagram::model::objc_method &m) const
{
return tvl::any_of(elements_.begin(), elements_.end(),
[&m](const auto &ef) -> tvl::value_t {
// Apply this filter only if it had `objc_method` type, do not apply
// `any` filters to methods for backward compatibility
if (ef.type != config::element_filter_t::filtered_type::objc_method)
return {};

return ef.name == m.qualified_name();
});
}

tvl::value_t element_filter::match(
const diagram & /*d*/, const class_diagram::model::objc_member &m) const
{
return tvl::any_of(elements_.begin(), elements_.end(),
[&m](const auto &ef) -> tvl::value_t {
// Apply this filter only if it had `method` type, do not apply
// `any` filters to methods for backward compatibility
if (ef.type != config::element_filter_t::filtered_type::objc_member)
return {};

return ef.name == m.qualified_name();
});
}

tvl::value_t element_filter::match(
const diagram &d, const sequence_diagram::model::participant &p) const
{
Expand All @@ -500,8 +556,9 @@ tvl::value_t element_filter::match(
sequence_model.get_participant<participant>(class_id)
.value();

return el.name == p.full_name(false) ||
el.name == class_participant.full_name(false);
return (el.name == p.name_and_ns()) ||
(el.name == p.full_name(false)) ||
(el.name == class_participant.full_name(false));
}

return el.name == p.full_name(false);
Expand All @@ -515,8 +572,9 @@ element_type_filter::element_type_filter(
{
}

tvl::value_t element_type_filter::match(
const diagram & /*d*/, const element &e) const
tvl::value_t element_type_filter::match(const diagram & /*d*/
,
const element &e) const
{
return tvl::any_of(element_types_.begin(), element_types_.end(),
[&e](const auto &element_type) {
Expand Down Expand Up @@ -791,7 +849,8 @@ void context_filter::initialize_effective_context(

auto &effective_context = effective_contexts_[idx];

// First add to effective context all elements matching context_ patterns
// First add to effective context all elements matching context_
// patterns
const auto &context_cfg = context_.at(idx);
const auto &context_matches =
dynamic_cast<const class_diagram::model::diagram &>(d)
Expand Down
12 changes: 12 additions & 0 deletions src/common/model/filters/diagram_filter.h
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,18 @@ struct element_filter : public filter_visitor {

tvl::value_t match(const diagram &d, const element &e) const override;

tvl::value_t match(const diagram &d,
const class_diagram::model::class_method &m) const override;

tvl::value_t match(const diagram &d,
const class_diagram::model::class_member &m) const override;

tvl::value_t match(const diagram &d,
const class_diagram::model::objc_method &m) const override;

tvl::value_t match(const diagram &d,
const class_diagram::model::objc_member &m) const override;

tvl::value_t match(const diagram &d,
const sequence_diagram::model::participant &p) const override;

Expand Down
16 changes: 15 additions & 1 deletion src/config/config.cc
Original file line number Diff line number Diff line change
Expand Up @@ -58,12 +58,26 @@ std::string to_string(element_filter_t::filtered_type ft)
return "function";
case element_filter_t::filtered_type::method:
return "method";
case element_filter_t::filtered_type::member:
return "member";
case element_filter_t::filtered_type::enum_:
return "enum";
case element_filter_t::filtered_type::concept_:
return "concept_";
return "concept";
case element_filter_t::filtered_type::package:
return "package";
case element_filter_t::filtered_type::function_template:
return "function_template";
case element_filter_t::filtered_type::objc_method:
return "objc_method";
case element_filter_t::filtered_type::objc_member:
return "objc_member";
case element_filter_t::filtered_type::objc_protocol:
return "objc_protocol";
case element_filter_t::filtered_type::objc_category:
return "objc_category";
case element_filter_t::filtered_type::objc_interface:
return "objc_interface";
default:
assert(false);
return "";
Expand Down
11 changes: 9 additions & 2 deletions src/config/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,18 @@ struct element_filter_t {
enum class filtered_type {
any,
function,
function_template,
class_,
method,
enum_,
method,
member,
concept_,
package
package,
objc_method,
objc_member,
objc_protocol,
objc_category,
objc_interface
};

filtered_type type{filtered_type::any};
Expand Down
20 changes: 17 additions & 3 deletions src/config/yaml_decoders.cc
Original file line number Diff line number Diff line change
Expand Up @@ -552,11 +552,25 @@ template <> struct convert<element_filter_t> {
rhs.type = element_filter_t::filtered_type::function;
else if (node["type"].as<std::string>() == "method")
rhs.type = element_filter_t::filtered_type::method;
else if (node["type"].as<std::string>() == "member")
rhs.type = element_filter_t::filtered_type::member;
else if (node["type"].as<std::string>() == "concept")
rhs.type = element_filter_t::filtered_type::concept_;
else if (node["type"].as<std::string>() == "concept")
rhs.type = element_filter_t::filtered_type::concept_;

else if (node["type"].as<std::string>() == "package")
rhs.type = element_filter_t::filtered_type::package;
else if (node["type"].as<std::string>() == "function_template")
rhs.type =
element_filter_t::filtered_type::function_template;
else if (node["type"].as<std::string>() == "objc_method")
rhs.type = element_filter_t::filtered_type::objc_method;
else if (node["type"].as<std::string>() == "objc_member")
rhs.type = element_filter_t::filtered_type::objc_member;
else if (node["type"].as<std::string>() == "objc_protocol")
rhs.type = element_filter_t::filtered_type::objc_protocol;
else if (node["type"].as<std::string>() == "objc_category")
rhs.type = element_filter_t::filtered_type::objc_category;
else if (node["type"].as<std::string>() == "objc_interface")
rhs.type = element_filter_t::filtered_type::objc_interface;
auto name = node["name"];
if (name.IsMap() && has_key(name, "r")) {
auto pattern = name["r"].as<std::string>();
Expand Down
1 change: 1 addition & 0 deletions tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ set(TEST_CASES_REQUIRING_OBJC
t00084
t00085
t00086
t00088
t20057
t20058
t30016
Expand Down
22 changes: 22 additions & 0 deletions tests/t00087/.clang-uml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
diagrams:
t00087_class:
type: class
glob:
- t00087.cc
using_namespace: clanguml::t00087
include:
namespaces:
- clanguml::t00087
elements:
- type: class
name:
r: '.*Foo.*'
- "clanguml::t00087::Bar<T>"
exclude:
elements:
- type: method
name:
r: '.*FooClass::(get|set).*'
- type: member
name: 'clanguml::t00087::FooClass::pImpl_'
- bar
27 changes: 27 additions & 0 deletions tests/t00087/t00087.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
namespace clanguml {
namespace t00087 {

class FooClass {
int foo_;

void *pImpl_;

public:
FooClass() { }

int getFoo() const { return foo_; }

void setFoo(int f) { foo_ = f; }

void foo() { }

void bar() { }
};

enum FooEnum {};

template <typename T> class Bar {
T bar;
};
}
}
40 changes: 40 additions & 0 deletions tests/t00087/test_case.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/**
* tests/t00087/test_case.h
*
* Copyright (c) 2021-2024 Bartek Kryza <[email protected]>
*
* 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("t00087")
{
using namespace clanguml::test;
using namespace std::string_literals;

auto [config, db, diagram, model] =
CHECK_CLASS_MODEL("t00087", "t00087_class");

CHECK_CLASS_DIAGRAM(*config, diagram, *model, [](const auto &src) {
REQUIRE(IsClass(src, "FooClass"));
REQUIRE(!IsEnum(src, "FooEnum"));
REQUIRE(IsClassTemplate(src, "Bar<T>"));

REQUIRE(!IsMethod<Public, Const>(src, "FooClass", "getFoo"));
REQUIRE(!IsMethod<Public>(src, "FooClass", "setFoo", "int"));
REQUIRE(IsMethod<Public>(src, "FooClass", "foo"));
REQUIRE(IsMethod<Public>(src, "FooClass", "bar"));

REQUIRE(IsField<Private>(src, "FooClass", "foo_", "int"));
REQUIRE(!IsField<Private>(src, "FooClass", "pImpl_", "void *"));
});
}
22 changes: 22 additions & 0 deletions tests/t00088/.clang-uml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
diagrams:
t00088_class:
type: class
glob:
- t00088.m
include:
paths:
- .
elements:
- type: objc_interface
name: It00088_Foo
exclude:
elements:
- type: objc_method
name:
r: 'It00088_Foo::bar.*'
- type: objc_method
name: 'It00088_Foo::baz:with:'
- type: objc_member
name: 'It00088_Foo::_barMember'
- type: objc_protocol
name: Pr00088
Loading

0 comments on commit 92bad7d

Please sign in to comment.