diff --git a/include/faker-cxx/types/locale.h b/include/faker-cxx/types/locale.h index 484482c5a..0bdd72504 100644 --- a/include/faker-cxx/types/locale.h +++ b/include/faker-cxx/types/locale.h @@ -3,6 +3,7 @@ #include #include #include +#include namespace faker { @@ -258,6 +259,15 @@ const std::vector locales{ Locale::zh_MO, Locale::zh_SG, Locale::zh_TW, Locale::zu_ZA }; +inline const std::set postCodeSet{ + Locale::cy_GB, Locale::gd_GB, Locale::en_GB, + Locale::en_CA, Locale::fr_CA, Locale::moh_CA, + Locale::fy_NL, Locale::nl_NL, + Locale::es_AR, + Locale::ms_BN, + Locale::mt_MT, Locale::en_MT +}; + inline std::string toString(Locale locale) { std::unordered_map localeToStringMapping{ diff --git a/src/common/algo_helper.h b/src/common/algo_helper.h index 48c221c78..2e2a3553c 100644 --- a/src/common/algo_helper.h +++ b/src/common/algo_helper.h @@ -71,6 +71,8 @@ static std::vector toVector(const std::array& arr) FAKER_CXX_EXPORT std::string replaceSymbolWithNumber(const std::string& str, const char& symbol = '#'); +FAKER_CXX_EXPORT std::string replaceSymbolWithLetter(const std::string& str, const char& symbol = '_'); + FAKER_CXX_EXPORT std::string replaceCreditCardSymbols(const std::string& inputString = "6453-####-####-####-###L", char symbol = '#'); diff --git a/src/modules/helper.cpp b/src/modules/helper.cpp index 132ffbd21..264703561 100644 --- a/src/modules/helper.cpp +++ b/src/modules/helper.cpp @@ -42,6 +42,25 @@ std::string replaceSymbolWithNumber(const std::string& str, const char& symbol) return result; } +std::string replaceSymbolWithLetter(const std::string& str, const char& symbol) +{ + std::string result; + + for (const auto& ch : str) + { + if (ch == symbol) + { + result += static_cast(number::integer(65, 90)); + } + else + { + result += ch; + } + } + + return result; +} + std::string replaceCreditCardSymbols(const std::string& inputString, char symbol) { std::string modifiedString = regexpStyleStringParse(inputString); diff --git a/src/modules/location.cpp b/src/modules/location.cpp index 0fec2ab20..f1d19c4d2 100644 --- a/src/modules/location.cpp +++ b/src/modules/location.cpp @@ -66,6 +66,8 @@ CountryAddressesInfo getAddresses(const Locale& locale) return finlandAddresses; case Locale::et_EE: return estoniaAddresses; + case Locale::en_GB: + return unitedkingdomAddresses; default: return usaAddresses; } @@ -117,7 +119,14 @@ std::string zipCode(Locale locale) { const auto& localeAddresses = getAddresses(locale); - return helper::replaceSymbolWithNumber(static_cast(localeAddresses.zipCodeFormat)); + std::string zip_with_symbols = static_cast(localeAddresses.zipCodeFormat); + + if (postCodeSet.count(locale) == 1) + { + return helper::replaceSymbolWithLetter(helper::replaceSymbolWithNumber(zip_with_symbols)); + } + + return helper::replaceSymbolWithNumber(zip_with_symbols); } std::string streetAddress(Locale locale) diff --git a/src/modules/location_data.h b/src/modules/location_data.h index c90a47b76..572498d1e 100644 --- a/src/modules/location_data.h +++ b/src/modules/location_data.h @@ -6685,6 +6685,157 @@ const CountryAddressesInfo ukraineAddresses{ (ukraineStates), }; +// United Kingdom + +const auto unitedkingdomCities = std::to_array({ + // clang-format off + "Aberdeen", + "Barnsley", + "Birmingham", + "Blackburn", + "Blackpool", + "Bournemouth", + "Bradford", + "Bristol", + "Brent", + "Bromley", + "Burnley", + "Cambridge", + "Chesterfield", + "Coventry", + "Crawley", + "Derby", + "Derry", + "Dudley", + "Dundee", + "Dover", + "Eastbourne", + "East Lindsey", + "Edinburgh", + "Erewash", + "Glasgow", + "Gateshead", + "Halton", + "Hastings", + "Harrow", + "Hull", + "Ipswich", + "Kingston upon Hull", + "Leeds", + "Leicester", + "Lisburn", + "Liverpool", + "Luton", + "Milton Keynes", + "Middlesbrough", + "Newcastle upon Tyne", + "Newport", + "Norwich", + "Nottingham", + "Oxford", + "Peterborough", + "Plymouth", + "Portsmouth", + "Reading", + "Redcar", + "Rotherham", + "Salford", + "Scunthorpe", + "Sheffield", + "Southampton", + "Southend-on-Sea", + "South Tyneside", + "Stafford", + "Sunderland", + "Swansea", + "Telford", + "Wakefield", + "Warrington", + "Wigan", + "Westminster", + "Wolverhampton", + "York" +}); + +const auto unitedkingdomStates = std::to_array({ + "England", + "Northern Ireland", + "Scotland", + "Wales" +}); + +const auto unitedkingdomStreetSuffixes = std::to_array({ + "Avenue", + "Bank", + "Brook", + "Circus", + "Close", + "Crescent", + "Drive", + "Field", + "Gardens", + "Grove", + "Hill", + "Lane", + "Mead" + "Mews", + "Place", + "Reach", + "Rise", + "Road", + "Row", + "Square", + "Square", + "Street", + "Way", + "Wharf", + "Yard", + }); + +const std::string_view unitedkingdomPostCodeFormat{"__## #__"}; + +const auto unitedkingdomAddressFormats = std::to_array({ + "{buildingNumber} {street}", +}); + +const auto unitedkingdomSecondaryAddressFormats = std::to_array({ + "Apt. ###", + "Suite ###", + "Flat ##" +}); + +const auto unitedkingdomBuildingNumberFormats = std::to_array({ + "###", + "####", + "#####", +}); + +const auto unitedkingdomStreetFormats = + std::to_array({ + "{firstName} {streetSuffix}", + "{lastName} {streetSuffix}", +}); + +const auto unitedkingdomCityFormats = std::to_array({ + "{cityName}", +}); + +const CountryAddressesInfo unitedkingdomAddresses{ + unitedkingdomPostCodeFormat, + (unitedkingdomAddressFormats), + (unitedkingdomSecondaryAddressFormats), + (unitedkingdomStreetFormats), + {}, + {}, + (unitedkingdomStreetSuffixes), + (unitedkingdomBuildingNumberFormats), + (unitedkingdomCityFormats), + {}, + (unitedkingdomCities), + {}, + {unitedkingdomStates}, +}; + // USA const auto usaCities = std::to_array({ diff --git a/tests/modules/helper_test.cpp b/tests/modules/helper_test.cpp index 802720a33..24798b413 100644 --- a/tests/modules/helper_test.cpp +++ b/tests/modules/helper_test.cpp @@ -132,6 +132,15 @@ TEST_F(HelperTest, ReplaceSymbolWithNumber) ASSERT_TRUE(std::ranges::all_of(result, ::isdigit)); } +TEST_F(HelperTest, ReplaceSymbolWithLetter) +{ + std::string input = "ABCD_FGH"; + + const auto result = replaceSymbolWithLetter(input); + + ASSERT_TRUE(std::ranges::all_of(result, ::isalpha)); +} + TEST_F(HelperTest, RegexpStyleStringParse) { std::string input = "#{5}[2-4]test[1-3]"; diff --git a/tests/modules/location_test.cpp b/tests/modules/location_test.cpp index d382375cb..2a7091571 100644 --- a/tests/modules/location_test.cpp +++ b/tests/modules/location_test.cpp @@ -67,6 +67,8 @@ CountryAddressesInfo getAddresses(const Locale& locale) return finlandAddresses; case Locale::et_EE: return estoniaAddresses; + case Locale::en_GB: + return unitedkingdomAddresses; default: return usaAddresses; } @@ -89,6 +91,19 @@ class LocationTest : public TestWithParam }); } + static bool checkIfPostCode(const std::string& postCode) + { + const std::string postCodeCharacters = "0123456789-ABCDEFGHIJKLMNOPQRSTUVWXYZ "; + + return std::ranges::all_of(postCode, + [&postCodeCharacters](char dataCharacter) + { + return std::ranges::any_of(postCodeCharacters, + [dataCharacter](char alphaNumericCharacter) + { return alphaNumericCharacter == dataCharacter; }); + }); + } + static bool checkIfAllCharactersAreNumeric(const std::string& data) { return std::ranges::all_of(data, @@ -165,7 +180,14 @@ TEST_P(LocationTest, shouldGenerateZipCode) ASSERT_EQ(generatedZipCode.size(), countryAddresses.zipCodeFormat.size()); - ASSERT_TRUE(checkIfZipCode(generatedZipCode)); + if(postCodeSet.count(country) == 1){ + + ASSERT_TRUE(checkIfPostCode(generatedZipCode)); + } + else{ + + ASSERT_TRUE(checkIfZipCode(generatedZipCode)); + } } TEST_P(LocationTest, shouldGenerateBuildingNumber) @@ -798,3 +820,51 @@ TEST_F(LocationTest, shouldGenerateEstoniaStreetAddress) ASSERT_TRUE(std::ranges::any_of(estoniaStreetNames, [&generatedStreetAddress](const std::string_view& streetName) { return generatedStreetAddress.find(streetName) != std::string::npos; })); } +TEST_F(LocationTest, shouldGenerateUnitedKingdomStreet) +{ + const auto generatedStreet = street(Locale::en_GB); + + const auto generatedStreetElements = common::split(generatedStreet, " "); + + const auto& generatedFirstOrLastName = generatedStreetElements[0]; + const auto& generatedStreetSuffix = generatedStreetElements[1]; + + std::vector firstNames(person::englishMaleFirstNames.begin(), + person::englishMaleFirstNames.end()); + firstNames.insert(firstNames.end(), person::englishFemaleFirstNames.begin(), person::englishFemaleFirstNames.end()); + + ASSERT_EQ(generatedStreetElements.size(), 2); + ASSERT_TRUE(std::ranges::any_of(firstNames, [&generatedFirstOrLastName](const std::string_view& firstName) + { return firstName == generatedFirstOrLastName; }) || + std::ranges::any_of(person::englishLastNames, + [&generatedFirstOrLastName](const std::string_view& lastName) + { return lastName == generatedFirstOrLastName; })); + ASSERT_TRUE(std::ranges::any_of(unitedkingdomStreetSuffixes, [&generatedStreetSuffix](const std::string_view& streetSuffix) + { return streetSuffix == generatedStreetSuffix; })); +} + +TEST_F(LocationTest, shouldGenerateUnitedKingdomStreetAddress) +{ + const auto generatedStreetAddress = streetAddress(Locale::en_GB); + + const auto generatedStreetAddressElements = common::split(generatedStreetAddress, " "); + + const auto& generatedBuildingNumber = generatedStreetAddressElements[0]; + const auto& generatedFirstOrLastName = generatedStreetAddressElements[1]; + const auto& generatedStreetSuffix = generatedStreetAddressElements[2]; + + std::vector firstNames(person::englishMaleFirstNames.begin(), + person::englishMaleFirstNames.end()); + firstNames.insert(firstNames.end(), person::englishFemaleFirstNames.begin(), person::englishFemaleFirstNames.end()); + + ASSERT_EQ(generatedStreetAddressElements.size(), 3); + ASSERT_TRUE(generatedBuildingNumber.size() >= 3 && generatedBuildingNumber.size() <= 5); + ASSERT_TRUE(checkIfAllCharactersAreNumeric(generatedBuildingNumber)); + ASSERT_TRUE(std::ranges::any_of(firstNames, [&generatedFirstOrLastName](const std::string_view& firstName) + { return firstName == generatedFirstOrLastName; }) || + std::ranges::any_of(person::englishLastNames, + [&generatedFirstOrLastName](const std::string_view& lastName) + { return lastName == generatedFirstOrLastName; })); + ASSERT_TRUE(std::ranges::any_of(unitedkingdomStreetSuffixes, [&generatedStreetSuffix](const std::string_view& streetSuffix) + { return streetSuffix == generatedStreetSuffix; })); +}