Skip to content

Commit

Permalink
feat: Added UK location data (#924)
Browse files Browse the repository at this point in the history
* Created function to convert character to letter, to be used for generating postcodes. Added set of all postcode locales for reference

* Added UK location data. Utilizes new postcode functions
  • Loading branch information
keatonmcarlton authored Sep 28, 2024
1 parent dbfb31f commit 7dfcc5c
Show file tree
Hide file tree
Showing 7 changed files with 272 additions and 2 deletions.
10 changes: 10 additions & 0 deletions include/faker-cxx/types/locale.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include <string>
#include <unordered_map>
#include <vector>
#include <set>

namespace faker
{
Expand Down Expand Up @@ -258,6 +259,15 @@ const std::vector<Locale> locales{
Locale::zh_MO, Locale::zh_SG, Locale::zh_TW, Locale::zu_ZA
};

inline const std::set<Locale> 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<Locale, std::string> localeToStringMapping{
Expand Down
2 changes: 2 additions & 0 deletions src/common/algo_helper.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ static std::vector<T> toVector(const std::array<T, N>& 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 = '#');

Expand Down
19 changes: 19 additions & 0 deletions src/modules/helper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<char>(number::integer(65, 90));
}
else
{
result += ch;
}
}

return result;
}

std::string replaceCreditCardSymbols(const std::string& inputString, char symbol)
{
std::string modifiedString = regexpStyleStringParse(inputString);
Expand Down
11 changes: 10 additions & 1 deletion src/modules/location.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down Expand Up @@ -117,7 +119,14 @@ std::string zipCode(Locale locale)
{
const auto& localeAddresses = getAddresses(locale);

return helper::replaceSymbolWithNumber(static_cast<std::string>(localeAddresses.zipCodeFormat));
std::string zip_with_symbols = static_cast<std::string>(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)
Expand Down
151 changes: 151 additions & 0 deletions src/modules/location_data.h
Original file line number Diff line number Diff line change
Expand Up @@ -6685,6 +6685,157 @@ const CountryAddressesInfo ukraineAddresses{
(ukraineStates),
};

// United Kingdom

const auto unitedkingdomCities = std::to_array<std::string_view>({
// 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<std::string_view>({
"England",
"Northern Ireland",
"Scotland",
"Wales"
});

const auto unitedkingdomStreetSuffixes = std::to_array<std::string_view>({
"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<std::string_view>({
"{buildingNumber} {street}",
});

const auto unitedkingdomSecondaryAddressFormats = std::to_array<std::string_view>({
"Apt. ###",
"Suite ###",
"Flat ##"
});

const auto unitedkingdomBuildingNumberFormats = std::to_array<std::string_view>({
"###",
"####",
"#####",
});

const auto unitedkingdomStreetFormats =
std::to_array<std::string_view>({
"{firstName} {streetSuffix}",
"{lastName} {streetSuffix}",
});

const auto unitedkingdomCityFormats = std::to_array<std::string_view>({
"{cityName}",
});

const CountryAddressesInfo unitedkingdomAddresses{
unitedkingdomPostCodeFormat,
(unitedkingdomAddressFormats),
(unitedkingdomSecondaryAddressFormats),
(unitedkingdomStreetFormats),
{},
{},
(unitedkingdomStreetSuffixes),
(unitedkingdomBuildingNumberFormats),
(unitedkingdomCityFormats),
{},
(unitedkingdomCities),
{},
{unitedkingdomStates},
};

// USA

const auto usaCities = std::to_array<std::string_view>({
Expand Down
9 changes: 9 additions & 0 deletions tests/modules/helper_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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]";
Expand Down
72 changes: 71 additions & 1 deletion tests/modules/location_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand All @@ -89,6 +91,19 @@ class LocationTest : public TestWithParam<Locale>
});
}

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,
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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<std::string_view> 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<std::string_view> 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; }));
}

0 comments on commit 7dfcc5c

Please sign in to comment.