From b623ce45bb108ef9d54e1b4577488a2d38dea541 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Cie=C5=9Blar?= Date: Thu, 16 Nov 2023 00:16:29 +0100 Subject: [PATCH] refactor generating full name (#260) --- CMakeLists.txt | 10 ++-- src/common/FormatHelper.cpp | 45 +++++++++++++++ src/common/FormatHelper.h | 16 ++++++ src/common/FormatHelperTest.cpp | 40 ++++++++++++++ src/common/StringHelper.cpp | 9 +-- .../errors/TokenGeneratorNotFoundError.h | 11 ++++ src/modules/person/Person.cpp | 55 +++---------------- 7 files changed, 131 insertions(+), 55 deletions(-) create mode 100644 src/common/FormatHelper.cpp create mode 100644 src/common/FormatHelper.h create mode 100644 src/common/FormatHelperTest.cpp create mode 100644 src/common/errors/TokenGeneratorNotFoundError.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 7c6b09e0..5ae863e8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -33,8 +33,9 @@ set(FAKER_SOURCES src/modules/person/Person.cpp src/modules/string/String.cpp src/modules/word/Word.cpp - src/common/StringHelper.cpp src/modules/phone/Phone.cpp + src/common/StringHelper.cpp + src/common/FormatHelper.cpp src/common/LuhnCheck.cpp src/common/mappers/precisionMapper/PrecisionMapper.cpp src/modules/system/System.cpp @@ -50,7 +51,7 @@ set(FAKER_SOURCES src/common/WeatherHelper.cpp src/modules/airline/Airline.cpp src/modules/image/Image.cpp -) + ) set(FAKER_UT_SOURCES src/modules/animal/AnimalTest.cpp @@ -72,6 +73,7 @@ set(FAKER_UT_SOURCES src/modules/phone/PhoneTest.cpp src/modules/helper/HelperTest.cpp src/common/LuhnCheckTest.cpp + src/common/FormatHelperTest.cpp src/common/mappers/precisionMapper/PrecisionMapperTest.cpp src/modules/system/SystemTest.cpp src/modules/database/DatabaseTest.cpp @@ -86,7 +88,7 @@ set(FAKER_UT_SOURCES src/common/WeatherHelperTest.cpp src/modules/airline/AirlineTest.cpp src/modules/image/ImageTest.cpp -) + ) add_library(${LIBRARY_NAME} ${FAKER_SOURCES}) @@ -96,7 +98,7 @@ target_include_directories(${LIBRARY_NAME} PRIVATE "${CMAKE_CURRENT_LIST_DIR}/include" ${FMT_INCLUDE_DIR} -) + ) add_subdirectory(externals/fmt) diff --git a/src/common/FormatHelper.cpp b/src/common/FormatHelper.cpp new file mode 100644 index 00000000..a0fb0619 --- /dev/null +++ b/src/common/FormatHelper.cpp @@ -0,0 +1,45 @@ +#include "FormatHelper.h" + +#include "errors/TokenGeneratorNotFoundError.h" +#include "fmt/format.h" + +namespace faker +{ + +std::string FormatHelper::fillTokenValues(const std::string& format, + std::map> tokenValueGenerators) +{ + std::string filledFormat; + + int tokenStart = -1; + + for (auto i = 0u; i < format.size(); i++) + { + if (format[i] == '{') + { + tokenStart = static_cast(i) + 1; + } + else if (format[i] == '}' && tokenStart != -1 && static_cast(tokenStart) < i) + { + const auto token = format.substr(static_cast(tokenStart), i - static_cast(tokenStart)); + + const auto foundTokenGenerator = tokenValueGenerators.find(token); + + if (foundTokenGenerator == tokenValueGenerators.end()) + { + throw errors::TokenGeneratorNotFoundError{fmt::format("Generator not found for token {}.", token)}; + } + + filledFormat += foundTokenGenerator->second(); + + tokenStart = -1; + } + else if (tokenStart == -1) + { + filledFormat += format[i]; + } + } + + return filledFormat; +} +} diff --git a/src/common/FormatHelper.h b/src/common/FormatHelper.h new file mode 100644 index 00000000..1c774111 --- /dev/null +++ b/src/common/FormatHelper.h @@ -0,0 +1,16 @@ +#pragma once + +#include +#include +#include +#include + +namespace faker +{ +class FormatHelper +{ +public: + static std::string fillTokenValues(const std::string& format, + std::map> tokenValueGenerators); +}; +} diff --git a/src/common/FormatHelperTest.cpp b/src/common/FormatHelperTest.cpp new file mode 100644 index 00000000..b4e7d10a --- /dev/null +++ b/src/common/FormatHelperTest.cpp @@ -0,0 +1,40 @@ +#include "FormatHelper.h" + +#include "gtest/gtest.h" + +#include "src/common/errors/TokenGeneratorNotFoundError.h" + +using namespace ::testing; +using namespace faker; + +class FormatHelperTest : public Test +{ +public: +}; + +TEST_F(FormatHelperTest, fillFormatTokensData) +{ + const auto format = "{hello} {faker}-{cxx} {library}"; + + const auto dataGeneratorsMapping = + std::map>{{"hello", []() { return "library"; }}, + {"faker", []() { return "cxx"; }}, + {"cxx", []() { return "faker"; }}, + {"library", []() { return "hello"; }}}; + + const auto result = FormatHelper::fillTokenValues(format, dataGeneratorsMapping); + + const auto expectedResult = "library cxx-faker hello"; + + EXPECT_EQ(result, expectedResult); +} + +TEST_F(FormatHelperTest, givenTokensWithNotDefinedGenerator_shouldThrow) +{ + const auto format = "{hello} {faker}-{cxx} {library}"; + + const auto dataGeneratorsMapping = std::map>{ + {"hello", []() { return "library"; }}, {"faker", []() { return "cxx"; }}, {"cxx", []() { return "faker"; }}}; + + ASSERT_THROW(FormatHelper::fillTokenValues(format, dataGeneratorsMapping), errors::TokenGeneratorNotFoundError); +} diff --git a/src/common/StringHelper.cpp b/src/common/StringHelper.cpp index 173c56c1..6a7abd33 100644 --- a/src/common/StringHelper.cpp +++ b/src/common/StringHelper.cpp @@ -3,7 +3,6 @@ #include #include #include -#include namespace faker { @@ -48,10 +47,12 @@ std::string StringHelper::join(const std::vector& data, const std:: std::string StringHelper::repeat(const std::string& data, int repetition) { std::string result; + for (int i = 0; i < repetition; ++i) { result += data; } + return result; } @@ -64,17 +65,17 @@ std::string StringHelper::toLower(const std::string& data) return lowerData; } -// Function to check if a character is punctuation bool StringHelper::isPunctuation(char c) { return (c == '.' || c == ',' || c == '!' || c == '?' || c == ';' || c == ':'); } -// Function to remove punctuation from a word std::string StringHelper::removePunctuation(const std::string& word) { - std::string result = word; + std::string result{word}; + result.erase(std::remove_if(result.begin(), result.end(), isPunctuation), result.end()); + return result; } } diff --git a/src/common/errors/TokenGeneratorNotFoundError.h b/src/common/errors/TokenGeneratorNotFoundError.h new file mode 100644 index 00000000..4cd77217 --- /dev/null +++ b/src/common/errors/TokenGeneratorNotFoundError.h @@ -0,0 +1,11 @@ +#pragma once + +#include + +namespace faker::errors +{ +struct TokenGeneratorNotFoundError : std::runtime_error +{ + using std::runtime_error::runtime_error; +}; +} diff --git a/src/modules/person/Person.cpp b/src/modules/person/Person.cpp index b5c7e2b6..4067e6d0 100644 --- a/src/modules/person/Person.cpp +++ b/src/modules/person/Person.cpp @@ -4,7 +4,7 @@ #include #include -#include "../../common/StringHelper.h" +#include "../../common/FormatHelper.h" #include "data/czech/CzechPeopleNames.h" #include "data/denmark/DanishPeopleNames.h" #include "data/england/EnglishPeopleNames.h" @@ -170,53 +170,14 @@ std::string Person::fullName(Country country, std::optional sex) const auto nameFormat = Helper::weightedArrayElement(weightedElements); - std::string fullName; + const auto dataGeneratorsMapping = std::map>{ + {"firstName", [&country, &sex]() { return Person::firstName(country, sex); }}, + {"middleName", [&country, &sex]() { return middleNameForCountry(country, sex); }}, + {"lastName", [&country, &sex]() { return Person::lastName(country, sex); }}, + {"prefix", [&country, &sex]() { return prefixForCountry(country, sex); }}, + {"suffix", [&country, &sex]() { return suffixForCountry(country, sex); }}}; - int tokenStart = -1; - - for (auto i = 0u; i <= nameFormat.size(); i++) - { - if (nameFormat[i] == '{') - { - tokenStart = static_cast(i) + 1; - } - else if (nameFormat[i] == '}' && tokenStart != -1 && static_cast(tokenStart) < i) - { - const auto token = - nameFormat.substr(static_cast(tokenStart), i - static_cast(tokenStart)); - - std::string nameElement; - - if (token == "firstName") - { - nameElement = Person::firstName(country, sex); - } - else if (token == "middleName") - { - nameElement = middleNameForCountry(country, sex); - } - else if (token == "lastName") - { - nameElement = Person::lastName(country, sex); - } - else if (token == "prefix") - { - nameElement = prefixForCountry(country, sex); - } - else if (token == "suffix") - { - nameElement = suffixForCountry(country, sex); - } - - fullName += nameElement; - - tokenStart = -1; - } - else if (tokenStart == -1) - { - fullName += nameFormat[i]; - } - } + auto fullName = FormatHelper::fillTokenValues(nameFormat, dataGeneratorsMapping); return fullName; }