diff --git a/util/generate_test_case.py b/util/generate_test_case.py new file mode 100755 index 00000000..933ad835 --- /dev/null +++ b/util/generate_test_case.py @@ -0,0 +1,157 @@ +#!/usr/bin/python3 + +## +## util/generate_test_case.py +## +## Copyright (c) 2021-2022 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. +## + +import os +import sys +import jinja2 + +TEST_CASE_MULTIPLIER = 10000 + +CLASS_DIAGRAM_TEST_CASE_EXAMPLES = """ + // Check if all classes exist + //REQUIRE_THAT(puml, IsClass(_A("A"))); + + // Check if class templates exist + //REQUIRE_THAT(puml, IsClassTemplate("A", "T,P,CMP,int N")); + + // Check if all enums exist + //REQUIRE_THAT(puml, IsEnum(_A("Lights"))); + + // Check if all inner classes exist + //REQUIRE_THAT(puml, IsInnerClass(_A("A"), _A("AA"))); + + // Check if all inheritance relationships exist + //REQUIRE_THAT(puml, IsBaseClass(_A("Base"), _A("Child"))); + + // Check if all methods exist + //REQUIRE_THAT(puml, (IsMethod("foo"))); + + // Check if all fields exist + //REQUIRE_THAT(puml, (IsField("private_member", "int"))); + + // Check if all relationships exist + //REQUIRE_THAT(puml, IsAssociation(_A("D"), _A("A"), "-as")); + //REQUIRE_THAT(puml, IsDependency(_A("R"), _A("B"))); + //REQUIRE_THAT(puml, IsAggregation(_A("R"), _A("D"))); + //REQUIRE_THAT(puml, IsComposition(_A("R"), _A("D"))); + //REQUIRE_THAT(puml, IsInstantiation(_A("ABCD::F"), _A("F"))); +""" + +SEQUENCE_DIAGRAM_TEST_CASE_EXAMPLES = """ + // Check if all calls exist + //REQUIRE_THAT(puml, HasCall("A", "log_result")); + //REQUIRE_THAT(puml, HasCallWithResponse("B", "A", "add3")); +""" + +PACKAGE_DIAGRAM_TEST_CASE_EXAMPLES = """ + // Check if all packages exist + //REQUIRE_THAT(puml, IsPackage("ns1")); +""" + +INCLUDE_DIAGRAM_TEST_CASE_EXAMPLES = """ + // Check all folders exist + //REQUIRE_THAT(puml, IsFolder("lib1")); + + // Check if all files exist + //REQUIRE_THAT(puml, IsFile("lib1.h")); + + // Check if all includes exists + //REQUIRE_THAT(puml, IsAssociation(_A("t40002.cc"), _A("lib1.h"))); + //REQUIRE_THAT(puml, IsDependency(_A("t40001_include1.h"), _A("string"))); +""" + +def test_case_already_exists(name): + return os.path.isdir(os.path.join(os.path.dirname(__file__), '..', name)) + + +def test_case_category(type): + if type == 'class': + return 0 + elif type == 'sequence': + return 2 * TEST_CASE_MULTIPLIER + elif type == 'package': + return 3 * TEST_CASE_MULTIPLIER + elif type == 'include': + return 4 * TEST_CASE_MULTIPLIER + else: + print(f"Invalid test case type '{type}' - aborting...") + sys.exit(1) + + +def examples_for_type(type): + if type == 'class': + return CLASS_DIAGRAM_TEST_CASE_EXAMPLES + elif type == 'sequence': + return SEQUENCE_DIAGRAM_TEST_CASE_EXAMPLES + elif type == 'package': + return PACKAGE_DIAGRAM_TEST_CASE_EXAMPLES + elif type == 'include': + return INCLUDE_DIAGRAM_TEST_CASE_EXAMPLES + else: + print(f"Invalid test case type '{type}' - aborting...") + sys.exit(1) + + +def generate(environment, variables, src, dst, dst_path): + template = environment.get_template(src) + + output = template.render(variables) + + with open(os.path.join(dst_path, dst), 'wb+') as fh: + fh.write(output.encode("UTF-8")) + + +def main(args): + if len(args) != 2: + print("Usage: ./generate_test_cases.py ") + + test_case_type = args[0] + test_case_number = int(args[1]) + test_case_name = f't{test_case_category(test_case_type) + test_case_number:05d}' + + if test_case_already_exists(test_case_name): + print(f"Test case 'test_case_name' already exists - aborting...") + sys.exit(1) + + template_directory = os.path.join(os.path.dirname(__file__), 'templates', 'test_cases') + + loader = jinja2.FileSystemLoader(searchpath=template_directory) + + env_parameters = dict( + loader=loader, + undefined=jinja2.StrictUndefined + ) + environment = jinja2.Environment(**env_parameters) + + test_case_directory = os.path.join(os.path.dirname(__file__), '..', 'tests', test_case_name) + + os.mkdir(test_case_directory) + + examples = examples_for_type(test_case_type) + + variables = dict(type = test_case_type, name = test_case_name, examples = examples) + + generate(environment, variables, '.clang-uml', '.clang-uml', test_case_directory) + generate(environment, variables, 't00000.cc', f'{test_case_name}.cc', test_case_directory) + generate(environment, variables, 'test_case.h', 'test_case.h', test_case_directory) + + +if __name__ == '__main__': + main(sys.argv[1:]) diff --git a/util/templates/test_cases/.clang-uml b/util/templates/test_cases/.clang-uml new file mode 100644 index 00000000..4e1e2749 --- /dev/null +++ b/util/templates/test_cases/.clang-uml @@ -0,0 +1,10 @@ +compilation_database_dir: .. +output_directory: puml +diagrams: + {{ name }}_{{ type }}: + type: {{ type }} + glob: + - ../../tests/{{ name }}/{{ name }}.cc + include: + namespaces: + - clanguml::{{ name }} \ No newline at end of file diff --git a/util/templates/test_cases/t00000.cc b/util/templates/test_cases/t00000.cc new file mode 100644 index 00000000..94401c8f --- /dev/null +++ b/util/templates/test_cases/t00000.cc @@ -0,0 +1,5 @@ +namespace clanguml { +namespace {{ name }} +{ +} +} diff --git a/util/templates/test_cases/test_case.h b/util/templates/test_cases/test_case.h new file mode 100644 index 00000000..7f10d637 --- /dev/null +++ b/util/templates/test_cases/test_case.h @@ -0,0 +1,41 @@ +/** + * tests/{{ name }}/test_case.h + * + * Copyright (c) 2021-2022 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("{{ name }}", "[test-case][{{ type }}]") +{ + auto [config, db] = load_config("{{ name }}"); + + auto diagram = config.diagrams["{{ name }}_{{ type }}"]; + + REQUIRE(diagram->name == "{{ name }}_{{ type }}"); + + auto model = generate_{{ type }}_diagram(db, diagram); + + REQUIRE(model->name() == "{{ name }}_{{ type }}"); + + auto puml = generate_{{ type }}_puml(diagram, *model); + AliasMatcher _A(puml); + + REQUIRE_THAT(puml, StartsWith("@startuml")); + REQUIRE_THAT(puml, EndsWith("@enduml\n")); + + {{ examples }} + + save_puml( + "./" + config.output_directory() + "/" + diagram->name + ".puml", puml); +}