Skip to content

Commit

Permalink
Added iban support for missing eu members (#74)
Browse files Browse the repository at this point in the history
* Added iban support for missing eu members

* Added missing tests based on regex
Added gmock neccessary for ASSERT_THAT

* Added macro to match regex using std::regex
Link gmock for tests
  • Loading branch information
jsbwilken committed Aug 8, 2023
1 parent ab2ca46 commit ab056bb
Show file tree
Hide file tree
Showing 4 changed files with 180 additions and 86 deletions.
5 changes: 3 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ if (BUILD_FAKER_TESTS)
add_subdirectory(externals/googletest)

set(GTEST_INCLUDE_DIR "${CMAKE_SOURCE_DIR}/externals/googletest/googletest/include")
set(GMOCK_INCLUDE_DIR "${CMAKE_SOURCE_DIR}/externals/googletest/googlemock/include")

enable_testing()

Expand All @@ -84,9 +85,9 @@ if (BUILD_FAKER_TESTS)

add_executable(${LIBRARY_NAME}-UT ${FAKER_UT_SOURCES})

target_link_libraries(${LIBRARY_NAME}-UT PRIVATE gtest_main faker-cxx)
target_link_libraries(${LIBRARY_NAME}-UT PRIVATE gtest_main gmock_main faker-cxx)

target_include_directories(${LIBRARY_NAME}-UT PRIVATE ${GTEST_INCLUDE_DIR} ${CMAKE_CURRENT_LIST_DIR})
target_include_directories(${LIBRARY_NAME}-UT PRIVATE ${GTEST_INCLUDE_DIR} ${GMOCK_INCLUDE_DIR} ${CMAKE_CURRENT_LIST_DIR})

add_test(NAME ${LIBRARY_NAME}-UT COMMAND ${LIBRARY_NAME}-UT WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR})

Expand Down
58 changes: 54 additions & 4 deletions include/faker-cxx/types/IbanCountry.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,63 @@ namespace faker
{
enum class IbanCountry
{
Poland,
Austria,
Belgium,
Bulgaria,
Croatia,
Cyprus,
Czechia,
Denmark,
Estonia,
Finland,
France,
Germany,
Italy
Greece,
Hungary,
Ireland,
Italy,
Latvia,
Lithuania,
Luxembourg,
Malta,
Netherlands,
Poland,
Portugal,
Romania,
Slovakia,
Slovenia,
Spain,
Sweden
};

const std::vector<IbanCountry> supportedIbanCountries{IbanCountry::Poland, IbanCountry::France, IbanCountry::Germany,
IbanCountry::Italy};
const std::vector<IbanCountry> supportedIbanCountries{
IbanCountry::Austria,
IbanCountry::Belgium,
IbanCountry::Bulgaria,
IbanCountry::Croatia,
IbanCountry::Cyprus,
IbanCountry::Czechia,
IbanCountry::Denmark,
IbanCountry::Estonia,
IbanCountry::Finland,
IbanCountry::France,
IbanCountry::Germany,
IbanCountry::Greece,
IbanCountry::Hungary,
IbanCountry::Ireland,
IbanCountry::Italy,
IbanCountry::Latvia,
IbanCountry::Lithuania,
IbanCountry::Luxembourg,
IbanCountry::Malta,
IbanCountry::Netherlands,
IbanCountry::Poland,
IbanCountry::Portugal,
IbanCountry::Romania,
IbanCountry::Slovakia,
IbanCountry::Slovenia,
IbanCountry::Spain,
IbanCountry::Sweden,
};

}
175 changes: 97 additions & 78 deletions src/modules/finance/FinanceTest.cpp
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
#include "faker-cxx/Finance.h"

#include <algorithm>
#include <regex>
#include <ranges>

#include "gtest/gtest.h"
#include "gmock/gmock.h"

#include "../../common/LuhnCheck.h"
#include "../../common/StringHelper.h"
Expand All @@ -11,15 +14,75 @@
#include "data/BankIndentifiersCodes.h"
#include "data/Currencies.h"


using namespace ::testing;
using namespace faker;

namespace
{
const std::string creditCardCharacters = "0123456789-";
const std::map<IbanCountry, std::string> expectedRegex {
{IbanCountry::Austria, "^(AT)([0-9]{2})([0-9]{5})([0-9]{11})$"},
{IbanCountry::Belgium, "^(BE)([0-9]{2})([0-9]{3})([0-9]{7})([0-9]{2})$"},
{IbanCountry::Bulgaria, "^(BG)([0-9]{2})([A-Z]{4})([0-9]{4})([0-9]{2})([a-zA-Z0-9]{8})$"},
{IbanCountry::Croatia, "^(HR)([0-9]{2})([0-9]{7})([0-9]{10})$"},
{IbanCountry::Cyprus, "^(CY)([0-9]{2})([0-9]{3})([0-9]{5})([a-zA-Z0-9]{16})$"},
{IbanCountry::Czechia, "^(CZ)([0-9]{2})([0-9]{4})([0-9]{6})([0-9]{10})$"},
{IbanCountry::Denmark, "^(DK)([0-9]{2})([0-9]{4})([0-9]{9})([0-9]{1})$"},
{IbanCountry::Estonia, "^(EE)([0-9]{2})([0-9]{2})([0-9]{2})([0-9]{11})([0-9]{1})$"},
{IbanCountry::Finland, "^(FI)([0-9]{2})([0-9]{6})([0-9]{7})([0-9]{1})$"},
{IbanCountry::France, "^(FR)([0-9]{2})([0-9]{5})([0-9]{5})([a-zA-Z0-9]{11})([0-9]{2})$"},
{IbanCountry::Germany, "^(DE)([0-9]{2})([0-9]{8})([0-9]{10})$"},
{IbanCountry::Greece, "^(GR)([0-9]{2})([0-9]{3})([0-9]{4})([a-zA-Z0-9]{16})$"},
{IbanCountry::Hungary, "^(HU)([0-9]{2})([0-9]{3})([0-9]{4})([0-9]{1})([0-9]{15})([0-9]{1})$"},
{IbanCountry::Ireland, "^(IE)([0-9]{2})([A-Z]{4})([0-9]{6})([0-9]{8})$"},
{IbanCountry::Italy, "^(IT)([0-9]{2})([A-Z]{1})([0-9]{5})([0-9]{5})([a-zA-Z0-9]{12})$"},
{IbanCountry::Latvia, "^(LV)([0-9]{2})([A-Z]{4})([a-zA-Z0-9]{13})$"},
{IbanCountry::Lithuania, "^(LT)([0-9]{2})([0-9]{5})([0-9]{11})$"},
{IbanCountry::Luxembourg, "^(LU)([0-9]{2})([0-9]{3})([a-zA-Z0-9]{13})$"},
{IbanCountry::Malta, "^(MT)([0-9]{2})([A-Z]{4})([0-9]{5})([a-zA-Z0-9]{18})$"},
{IbanCountry::Netherlands, "^(NL)([0-9]{2})([A-Z]{4})([0-9]{10})$"},
{IbanCountry::Poland, "^(PL)([0-9]{2})([0-9]{3})([0-9]{4})([0-9]{1})([0-9]{16})$"},
{IbanCountry::Portugal, "^(PT)([0-9]{2})([0-9]{4})([0-9]{4})([0-9]{11})([0-9]{2})$"},
{IbanCountry::Romania, "^(RO)([0-9]{2})([A-Z]{4})([a-zA-Z0-9]{16})$"},
{IbanCountry::Slovakia, "^(SK)([0-9]{2})([0-9]{4})([0-9]{6})([0-9]{10})$"},
{IbanCountry::Slovenia, "^(SI)([0-9]{2})([0-9]{2})([0-9]{3})([0-9]{8})([0-9]{2})$"},
{IbanCountry::Spain, "^(ES)([0-9]{2})([0-9]{4})([0-9]{4})([0-9]{2})([0-9]{10})$"},
{IbanCountry::Sweden, "^(SE)([0-9]{2})([0-9]{3})([0-9]{17})$"},
};

const std::map<IbanCountry, std::string> generatedTestName {
{IbanCountry::Austria, "shouldGenerateAustriaIban"},
{IbanCountry::Belgium, "shouldGenerateBelgiumIban"},
{IbanCountry::Bulgaria, "shouldGenerateBulgariaIban"},
{IbanCountry::Croatia, "shouldGenerateCroatiaIban"},
{IbanCountry::Cyprus, "shouldGenerateCyprusIban"},
{IbanCountry::Czechia, "shouldGenerateCzechiaIban"},
{IbanCountry::Denmark, "shouldGenerateDenmarkIban"},
{IbanCountry::Estonia, "shouldGenerateEstoniaIban"},
{IbanCountry::Finland, "shouldGenerateFinlandIban"},
{IbanCountry::France, "shouldGenerateFranceIban"},
{IbanCountry::Germany, "shouldGenerateGermanyIban"},
{IbanCountry::Greece, "shouldGenerateGreeceIban"},
{IbanCountry::Hungary, "shouldGenerateHungaryIban"},
{IbanCountry::Ireland, "shouldGenerateIrelandIban"},
{IbanCountry::Italy, "shouldGenerateItalyIban"},
{IbanCountry::Latvia, "shouldGenerateLatviaIban"},
{IbanCountry::Lithuania, "shouldGenerateLithuaniaIban"},
{IbanCountry::Luxembourg, "shouldGenerateLuxembourgIban"},
{IbanCountry::Malta, "shouldGenerateMaltaIban"},
{IbanCountry::Netherlands, "shouldGenerateNetherlandsIban"},
{IbanCountry::Poland, "shouldGeneratePolandIban"},
{IbanCountry::Portugal, "shouldGeneratePortugalIban"},
{IbanCountry::Romania, "shouldGenerateRomaniaIban"},
{IbanCountry::Slovakia, "shouldGenerateSlovakiaIban"},
{IbanCountry::Slovenia, "shouldGenerateSloveniaIban"},
{IbanCountry::Spain, "shouldGenerateSpainIban"},
{IbanCountry::Sweden, "shouldGenerateSwedenIban"},
};
}

class FinanceTest : public Test
class FinanceTest : public TestWithParam<IbanCountry>
{
public:
static bool checkIfAllCharactersAreNumeric(const std::string& data)
Expand Down Expand Up @@ -100,6 +163,32 @@ TEST_F(FinanceTest, shouldGenerateAmount)
ASSERT_LE(amountAsFloat, 1000);
}

/*
* The default GTest macro "MatchesRegex" has only minimal support on
* windows. Hence, we define our own macro which uses the c++ default
* implementation of the used compiler.
*/
MATCHER_P(MatchesRegexCpp, value, "") {
return std::regex_match(arg, std::regex(value));
}

TEST_P(FinanceTest, CheckIbanGenerator) {
auto ibanCountry = GetParam();

ASSERT_THAT(Finance::iban(ibanCountry), MatchesRegexCpp(expectedRegex.at(ibanCountry)));
}

INSTANTIATE_TEST_SUITE_P(
TestIbanGenerator,
FinanceTest,
ValuesIn(
std::views::keys(expectedRegex).begin(),
std::views::keys(expectedRegex).end()
),
[](const TestParamInfo<IbanCountry> &info) {
return generatedTestName.at(info.param);
});

TEST_F(FinanceTest, shouldGenerateAmountWithSymbol)
{
const auto min = 150;
Expand All @@ -125,83 +214,13 @@ TEST_F(FinanceTest, shouldGenerateIban)
const auto iban = Finance::iban();

// TODO: implement more detailed checks for iban with default argument
ASSERT_TRUE(iban.starts_with("PL") || iban.starts_with("IT") || iban.starts_with("FR") || iban.starts_with("DE"));
}

TEST_F(FinanceTest, shouldGeneratePolishIban)
{
const auto iban = Finance::iban(IbanCountry::Poland);

const auto countryCode = iban.substr(0, 2);
const auto checksum = iban.substr(2, 2);
const auto bankCode = iban.substr(4, 3);
const auto branchCode = iban.substr(7, 4);
const auto checkDigit = iban.substr(11, 1);
const auto accountNumber = iban.substr(12, 16);

ASSERT_EQ(iban.size(), 28);
ASSERT_EQ(countryCode, "PL");
ASSERT_TRUE(checkIfAllCharactersAreNumeric(checksum));
ASSERT_TRUE(checkIfAllCharactersAreNumeric(bankCode));
ASSERT_TRUE(checkIfAllCharactersAreNumeric(branchCode));
ASSERT_TRUE(checkIfAllCharactersAreNumeric(checkDigit));
ASSERT_TRUE(checkIfAllCharactersAreNumeric(accountNumber));
}

TEST_F(FinanceTest, shouldGenerateFranceIban)
{
const auto iban = Finance::iban(IbanCountry::France);

const auto countryCode = iban.substr(0, 2);
const auto checksum = iban.substr(2, 2);
const auto bankCode = iban.substr(4, 5);
const auto branchCode = iban.substr(9, 5);
const auto accountNumber = iban.substr(14, 11);
const auto checkDigit = iban.substr(25, 2);

ASSERT_EQ(iban.size(), 27);
ASSERT_EQ(countryCode, "FR");
ASSERT_TRUE(checkIfAllCharactersAreNumeric(checksum));
ASSERT_TRUE(checkIfAllCharactersAreNumeric(bankCode));
ASSERT_TRUE(checkIfAllCharactersAreNumeric(branchCode));
ASSERT_TRUE(checkIfAllCharactersAreAlphanumeric(accountNumber));
ASSERT_TRUE(checkIfAllCharactersAreNumeric(checkDigit));
}

TEST_F(FinanceTest, shouldGenerateItalyIban)
{
const auto iban = Finance::iban(IbanCountry::Italy);

const auto countryCode = iban.substr(0, 2);
const auto checksum = iban.substr(2, 2);
const auto checkDigit = iban.substr(4, 1);
const auto bankCode = iban.substr(5, 5);
const auto branchCode = iban.substr(10, 5);
const auto accountNumber = iban.substr(15, 12);

ASSERT_EQ(iban.size(), 27);
ASSERT_EQ(countryCode, "IT");
ASSERT_TRUE(checkIfAllCharactersAreNumeric(checksum));
ASSERT_TRUE(checkIfAllCharactersAreAlpha(checkDigit));
ASSERT_TRUE(checkIfAllCharactersAreNumeric(bankCode));
ASSERT_TRUE(checkIfAllCharactersAreNumeric(branchCode));
ASSERT_TRUE(checkIfAllCharactersAreAlphanumeric(accountNumber));
}

TEST_F(FinanceTest, shouldGenerateGermanyIban)
{
const auto iban = Finance::iban(IbanCountry::Germany);

const auto countryCode = iban.substr(0, 2);
const auto checksum = iban.substr(2, 2);
const auto blz = iban.substr(4, 8);
const auto accountNumber = iban.substr(12, 10);

ASSERT_EQ(iban.size(), 22);
ASSERT_EQ(countryCode, "DE");
ASSERT_TRUE(checkIfAllCharactersAreNumeric(checksum));
ASSERT_TRUE(checkIfAllCharactersAreNumeric(blz));
ASSERT_TRUE(checkIfAllCharactersAreNumeric(accountNumber));
ASSERT_TRUE(iban.starts_with("AT") || iban.starts_with("BE") || iban.starts_with("BG") || iban.starts_with("HR") ||
iban.starts_with("CY") || iban.starts_with("CZ") || iban.starts_with("DK") || iban.starts_with("EE") ||
iban.starts_with("FI") || iban.starts_with("FR") || iban.starts_with("DE") || iban.starts_with("GR") ||
iban.starts_with("HU") || iban.starts_with("IE") || iban.starts_with("IT") || iban.starts_with("LV") ||
iban.starts_with("LT") || iban.starts_with("LU") || iban.starts_with("MT") || iban.starts_with("NL") ||
iban.starts_with("PL") || iban.starts_with("PT") || iban.starts_with("RO") || iban.starts_with("SK") ||
iban.starts_with("SI") || iban.starts_with("ES") || iban.starts_with("SE"));
}

TEST_F(FinanceTest, shouldGenerateBic)
Expand Down
28 changes: 26 additions & 2 deletions src/modules/finance/data/IbanFormats.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include <map>
#include <string>
#include <vector>
#include <ranges>

#include "faker-cxx/types/IbanCountry.h"

Expand All @@ -11,9 +12,32 @@ namespace faker
// Iban format structure from https://bank.codes/iban/structure/
// Note: a - alphabets (letters only), c - characters (letters & numbers), n - numbers (numbers only)
const std::map<IbanCountry, std::vector<std::string>> ibanFormats{
{IbanCountry::Poland, {"PL", "2n", "3n", "4n", "1n", "16n"}},
{IbanCountry::Austria, {"AT", "2n", "5n", "11n"}},
{IbanCountry::Belgium, {"BE", "2n", "3n", "7n", "2n"}},
{IbanCountry::Bulgaria, {"BG", "2n", "4a", "4n", "2n", "8c"}},
{IbanCountry::Croatia, {"HR", "2n", "7n", "10n"}},
{IbanCountry::Cyprus, {"CY", "2n", "3n", "5n", "16c"}},
{IbanCountry::Czechia, {"CZ", "2n", "4n", "6n", "10n"}},
{IbanCountry::Denmark, {"DK", "2n", "4n", "9n", "1n"}},
{IbanCountry::Estonia, {"EE", "2n", "2n", "2n", "11n", "1n"}},
{IbanCountry::Finland, {"FI", "2n", "6n", "7n", "1n"}},
{IbanCountry::France, {"FR", "2n", "5n", "5n", "11c", "2n"}},
{IbanCountry::Italy, {"IT", "2n", "1a", "5n", "5n", "12c"}},
{IbanCountry::Germany, {"DE", "2n", "8n", "10n"}},
{IbanCountry::Greece, {"GR", "2n", "3n", "4n", "16c"}},
{IbanCountry::Hungary, {"HU", "2n", "3n", "4n", "1n", "15n", "1n"}},
{IbanCountry::Ireland, {"IE", "2n", "4a", "6n", "8n"}},
{IbanCountry::Italy, {"IT", "2n", "1a", "5n", "5n", "12c"}},
{IbanCountry::Latvia, {"LV", "2n", "4a", "13n"}},
{IbanCountry::Lithuania, {"LT", "2n", "5n", "11n"}},
{IbanCountry::Luxembourg, {"LU", "2n", "3n", "13c"}},
{IbanCountry::Malta, {"MT", "2n", "4a", "5n", "18c"}},
{IbanCountry::Netherlands, {"NL", "2n", "4a", "10n"}},
{IbanCountry::Poland, {"PL", "2n", "3n", "4n", "1n", "16n"}},
{IbanCountry::Portugal, {"PT", "2n", "4n", "4n", "11n", "2n"}},
{IbanCountry::Romania, {"RO", "2n", "4a", "16c"}},
{IbanCountry::Slovakia, {"SK", "2n", "4n", "6n", "10n"}},
{IbanCountry::Slovenia, {"SI", "2n", "2n", "3n", "8n", "2n"}},
{IbanCountry::Spain, {"ES", "2n", "4n", "4n", "2n", "10n"}},
{IbanCountry::Sweden, {"SE", "2n", "3n", "16n", "1n"}},
};
}

0 comments on commit ab056bb

Please sign in to comment.