diff --git a/src/util/util.cc b/src/util/util.cc new file mode 100644 index 00000000..dafd830f --- /dev/null +++ b/src/util/util.cc @@ -0,0 +1,72 @@ +/** + * src/util/util.cc + * + * Copyright (c) 2021 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. + */ +#include "util.h" + +namespace clanguml { +namespace util { +std::vector split(std::string str, std::string delimiter) +{ + std::vector result; + + while (str.size()) { + int index = str.find(delimiter); + if (index != std::string::npos) { + result.push_back(str.substr(0, index)); + str = str.substr(index + delimiter.size()); + if (str.size() == 0) + result.push_back(str); + } + else { + result.push_back(str); + str = ""; + } + } + + if (result.empty()) + result.push_back(str); + + return result; +} + +std::string ns_relative( + const std::vector &namespaces, const std::string &n) +{ + std::vector namespaces_sorted{namespaces}; + + std::sort(namespaces_sorted.rbegin(), namespaces_sorted.rend()); + + for (const auto &ns : namespaces_sorted) { + if (ns.empty()) + continue; + + if (n == ns) + return split(n, "::").back(); + + if (n.find(ns) == 0) { + if (n.size() <= ns.size() + 2) + return ""; + + return n.substr(ns.size() + 2); + } + } + + return n; +} +} +} + diff --git a/src/util/util.h b/src/util/util.h index 449f7811..b5471ed6 100644 --- a/src/util/util.h +++ b/src/util/util.h @@ -17,59 +17,44 @@ */ #pragma once +#include #include #include namespace clanguml { namespace util { -std::vector split(std::string str, std::string delimiter) -{ - std::vector result; - - while (str.size()) { - int index = str.find(delimiter); - if (index != std::string::npos) { - result.push_back(str.substr(0, index)); - str = str.substr(index + delimiter.size()); - if (str.size() == 0) - result.push_back(str); - } - else { - result.push_back(str); - str = ""; - } - } - - if (result.empty()) - result.push_back(str); - - return result; -} +/** + * @brief Split a string using delimiter + * + * Basic string split function, because C++ stdlib does not have one. + * In case the string does not contain the delimiter, the original + * string is returned as the only element of the vector. + * + * @param str String to split + * @param delimiter Delimiter string + * + * @return Vector of string tokens. + */ +std::vector split(std::string str, std::string delimiter); +/** + * @brief Get name of the identifier relative to a set of namespaces + * + * This function tries to match a given C++ identifier (e.g. + * clanguml::util::split) to the longest namespace from the provided list + * matching the identifier from the left. + * If a match is found, the relative identifier is returned. If none of + * the namespaces match the identifier or if nothing is left after + * removing the matching namespace from the identifier, original identifier is + * returned. + * + * @param namespaces List of C++ namespaces to consider + * @param n Identifier to relativize + * + * @return Identifier relative to one of the matching namespaces. + */ std::string ns_relative( - const std::vector &namespaces, const std::string &n) -{ - std::vector namespaces_sorted{namespaces}; - - std::sort(namespaces_sorted.rbegin(), namespaces_sorted.rend()); - - for (const auto &ns : namespaces_sorted) { - if (ns.empty()) - continue; - - if (n == ns) - return split(n, "::").back(); - - if (n.find(ns) == 0) { - if (n.size() <= ns.size() + 2) - return ""; - - return n.substr(ns.size() + 2); - } - } - - return n; -} + const std::vector &namespaces, const std::string &n); } } diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index b82e1765..d936947a 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -7,6 +7,14 @@ set(CMAKE_CXX_STANDARD 17) file(GLOB_RECURSE TEST_CASE_SOURCES t*/*.cc) file(GLOB_RECURSE TEST_CASE_CONFIGS t*/.clanguml) +set(CLANG_UML_TEST_UTIL_SRC + test_util.cc + ${TEST_UTIL_SOURCES} +) +set(CLANG_UML_TEST_UTIL_HEADER + catch.h +) + set(CLANG_UML_TEST_CASES_SRC test_cases.cc ${TEST_CASE_SOURCES} @@ -15,6 +23,17 @@ set(CLANG_UML_TEST_CASES_HEADER catch.h ) +add_executable(test_util + ${CLANG_UML_TEST_UTIL_SRC} + ${CLANG_UML_TEST_UTIL_HEADER}) + +target_link_libraries(test_util + PRIVATE + ${LIBCLANG_LIBRARIES} + ${YAML_CPP_LIBRARIES} + spdlog::spdlog clang-umllib) + + add_executable(test_cases ${CLANG_UML_TEST_CASES_SRC} ${CLANG_UML_TEST_CASES_HEADER}) @@ -37,4 +56,5 @@ foreach(TEST_CASE_CONFIG ${TEST_CASE_CONFIGS}) COPYONLY) endforeach() +add_test(NAME test_util COMMAND test_util) add_test(NAME test_cases COMMAND test_cases) diff --git a/tests/test_util.cc b/tests/test_util.cc new file mode 100644 index 00000000..76e70929 --- /dev/null +++ b/tests/test_util.cc @@ -0,0 +1,42 @@ +/** + * tests/test_util.cc + * + * Copyright (c) 2021 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. + */ +#define CATCH_CONFIG_MAIN + +#include "util/util.h" + +#include "catch.h" + +TEST_CASE("Test split", "[unit-test]") +{ + using C = std::vector; + using namespace clanguml::util; + + const C empty{}; + + CHECK(split("", " ") == C{""}); + CHECK(split("ABCD", " ") == C{"ABCD"}); + + CHECK(split("std::vector::detail", "::") == C{"std", "vector", "detail"}); +} + +TEST_CASE("Test ns_relative", "[unit-test]") +{ + using namespace clanguml::util; + + CHECK(ns_relative({}, "std::vector") == "std::vector"); +}