Compare commits
7 Commits
Author | SHA1 | Date |
---|---|---|
|
83ddceec00 | |
|
e847e2c473 | |
|
a660250af1 | |
|
709f6c50b5 | |
|
5cfc3f5fa2 | |
|
ce90960649 | |
|
e7e6bbda29 |
|
@ -71,7 +71,7 @@ The package can be installed by adding `iban_ex` to your list of dependencies in
|
|||
```elixir
|
||||
def deps do
|
||||
[
|
||||
{:iban_ex, "~> 0.1.6"}
|
||||
{:iban_ex, "~> 0.1.8"}
|
||||
]
|
||||
end
|
||||
```
|
||||
|
|
|
@ -41,6 +41,7 @@ defmodule IbanEx.Country do
|
|||
"IE" => IbanEx.Country.IE,
|
||||
"IL" => IbanEx.Country.IL,
|
||||
"IT" => IbanEx.Country.IT,
|
||||
"IS" => IbanEx.Country.IS,
|
||||
"JO" => IbanEx.Country.JO,
|
||||
"KZ" => IbanEx.Country.KZ,
|
||||
"KW" => IbanEx.Country.KW,
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
defmodule IbanEx.Country.BG do
|
||||
# TODO Bulgaria IBAN contains account type (first 2 digits of account number)
|
||||
|
||||
@moduledoc """
|
||||
Bulgaria IBAN parsing rules
|
||||
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
defmodule IbanEx.Country.IS do
|
||||
# TODO Iceland IBAN contains identification number (last 10 digits of account number)
|
||||
|
||||
@moduledoc """
|
||||
Island IBAN parsing rules
|
||||
|
||||
## Examples
|
||||
|
||||
```elixir
|
||||
iex> %IbanEx.Iban{
|
||||
...> country_code: "IS",
|
||||
...> check_digits: "14",
|
||||
...> bank_code: "0159",
|
||||
...> branch_code: "26",
|
||||
...> national_check: nil,
|
||||
...> account_number: "0076545510730339"
|
||||
...> }
|
||||
...> |> IbanEx.Country.IS.to_string()
|
||||
"IS 14 0159 26 0076545510730339"
|
||||
```
|
||||
"""
|
||||
|
||||
@size 26
|
||||
@rule ~r/^(?<bank_code>[0-9]{4})(?<branch_code>[0-9]{2})(?<account_number>[0-9]{16})$/i
|
||||
|
||||
use IbanEx.Country.Template
|
||||
|
||||
@impl IbanEx.Country.Template
|
||||
@spec to_string(Iban.t()) :: binary()
|
||||
@spec to_string(Iban.t(), binary()) :: binary()
|
||||
def to_string(
|
||||
%Iban{
|
||||
country_code: country_code,
|
||||
check_digits: check_digits,
|
||||
bank_code: bank_code,
|
||||
branch_code: branch_code,
|
||||
national_check: _national_check,
|
||||
account_number: account_number
|
||||
} = _iban,
|
||||
joiner \\ " "
|
||||
) do
|
||||
[country_code, check_digits, bank_code, branch_code, account_number]
|
||||
|> Enum.join(joiner)
|
||||
end
|
||||
end
|
|
@ -9,7 +9,10 @@ defmodule IbanEx.Country.Template do
|
|||
|
||||
@callback size() :: size()
|
||||
@callback rule() :: rule()
|
||||
@callback incomplete_rule() :: rule()
|
||||
@callback rules() :: []
|
||||
@callback rules_map() :: %{}
|
||||
@callback bban_fields() :: [atom()]
|
||||
@callback bban_size() :: non_neg_integer()
|
||||
@callback to_string(Iban.t(), joiner()) :: String.t()
|
||||
@callback to_string(Iban.t()) :: String.t()
|
||||
|
||||
|
@ -47,26 +50,50 @@ defmodule IbanEx.Country.Template do
|
|||
@spec rule() :: Regex.t()
|
||||
def rule(), do: @rule
|
||||
|
||||
@doc """
|
||||
Return Regex without trailing “$” for parsing incomplete BBAN (part of IBAN string) (for partial suggestions)
|
||||
"""
|
||||
@impl IbanEx.Country.Template
|
||||
@spec incomplete_rule() :: Regex.t()
|
||||
def incomplete_rule() do
|
||||
@spec bban_size() :: integer()
|
||||
def bban_size() do
|
||||
{_rules, bban_size} = calculate_rules()
|
||||
bban_size
|
||||
end
|
||||
|
||||
@impl IbanEx.Country.Template
|
||||
@spec bban_fields() :: []
|
||||
def bban_fields(), do: rules_map() |> Map.keys()
|
||||
|
||||
@impl IbanEx.Country.Template
|
||||
@spec rules_map() :: %{}
|
||||
def rules_map(), do: rules() |> Map.new()
|
||||
|
||||
@impl IbanEx.Country.Template
|
||||
@spec rules() :: []
|
||||
def rules() do
|
||||
{rules, _bban_size} = calculate_rules()
|
||||
rules
|
||||
end
|
||||
|
||||
defp calculate_rules() do
|
||||
scanner = ~r/\(\?\<([\w_]+)\>(([^{]+)\{(\d+)\})\)/i
|
||||
|
||||
source =
|
||||
@rule
|
||||
|> Regex.source()
|
||||
|> String.slice(0..-2//1)
|
||||
|> String.replace("{", "{0,")
|
||||
|
||||
opts =
|
||||
@rule
|
||||
|> Regex.opts()
|
||||
{list, bban_length} =
|
||||
Regex.scan(scanner, source)
|
||||
|> Enum.reduce({[], 0}, fn [_part, k, r, _syms, l], {list, position} = acc ->
|
||||
key = String.to_atom(k)
|
||||
{:ok, regex} = Regex.compile(r, "i")
|
||||
length = String.to_integer(l)
|
||||
left = position
|
||||
right = left + length - 1
|
||||
{[{key, %{regex: regex, range: left..right}} | list], right + 1}
|
||||
end)
|
||||
|
||||
Regex.compile!(source, opts)
|
||||
{Enum.reverse(list), bban_length}
|
||||
end
|
||||
|
||||
defoverridable to_string: 1, to_string: 2, size: 0, rule: 0, incomplete_rule: 0
|
||||
defoverridable to_string: 1, to_string: 2, size: 0, rule: 0
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -9,6 +9,10 @@ defmodule IbanEx.Error do
|
|||
| :can_not_parse_map
|
||||
| :length_to_long
|
||||
| :length_to_short
|
||||
| :invalid_bank_code
|
||||
| :invalid_account_number
|
||||
| :invalid_branch_code
|
||||
| :invalid_national_check
|
||||
| atom()
|
||||
@type errors() :: [error()]
|
||||
@errors [
|
||||
|
@ -18,7 +22,11 @@ defmodule IbanEx.Error do
|
|||
:invalid_checksum,
|
||||
:can_not_parse_map,
|
||||
:length_to_long,
|
||||
:length_to_short
|
||||
:length_to_short,
|
||||
:invalid_bank_code,
|
||||
:invalid_account_number,
|
||||
:invalid_branch_code,
|
||||
:invalid_national_check
|
||||
]
|
||||
|
||||
@messages [
|
||||
|
@ -28,8 +36,12 @@ defmodule IbanEx.Error do
|
|||
invalid_checksum: "IBAN's checksum is invalid",
|
||||
can_not_parse_map: "Can't parse map to IBAN struct",
|
||||
length_to_long: "IBAN longer then required length",
|
||||
length_to_short: "IBAN shorter then required length"
|
||||
]
|
||||
length_to_short: "IBAN shorter then required length",
|
||||
invalid_bank_code: "Bank code violates required format",
|
||||
invalid_account_number: "Account number violates required format",
|
||||
invalid_branch_code: "Branch code violates required format",
|
||||
invalid_national_check: "National check symbols violates required format",
|
||||
]
|
||||
|
||||
@spec message(error()) :: String.t()
|
||||
def message(error) when error in @errors, do: @messages[error]
|
||||
|
|
|
@ -2,7 +2,7 @@ defmodule IbanEx.Parser do
|
|||
@moduledoc false
|
||||
|
||||
alias IbanEx.{Country, Iban, Validator}
|
||||
import IbanEx.Commons, only: [normalize_and_slice: 2, blank: 1]
|
||||
import IbanEx.Commons, only: [normalize_and_slice: 2]
|
||||
|
||||
@type iban_string() :: String.t()
|
||||
@type country_code_string() :: <<_::16>>
|
||||
|
@ -20,8 +20,9 @@ defmodule IbanEx.Parser do
|
|||
@spec parse({:ok, binary()}) :: iban_or_error()
|
||||
def parse({:ok, iban_string}), do: parse(iban_string)
|
||||
|
||||
@spec parse(binary()) :: iban_or_error()
|
||||
def parse(iban_string) do
|
||||
def parse(iban_string, options \\ [incomplete: false])
|
||||
|
||||
def parse(iban_string, incomplete: false) do
|
||||
case Validator.validate(iban_string) do
|
||||
{:ok, valid_iban} ->
|
||||
iban_map = %{
|
||||
|
@ -41,26 +42,65 @@ defmodule IbanEx.Parser do
|
|||
end
|
||||
end
|
||||
|
||||
def parse(iban_string, incomplete: true) do
|
||||
iban_map = %{
|
||||
country_code: country_code(iban_string),
|
||||
check_digits: check_digits(iban_string)
|
||||
}
|
||||
|
||||
bban = bban(iban_string)
|
||||
|
||||
case Country.is_country_code_supported?(iban_map.country_code) do
|
||||
true ->
|
||||
result =
|
||||
parse_bban(bban, iban_map.country_code, incomplete: true)
|
||||
|> Map.merge(iban_map)
|
||||
|
||||
{:ok, struct(Iban, result)}
|
||||
|
||||
false ->
|
||||
{:error, :unsupported_country_code}
|
||||
end
|
||||
end
|
||||
|
||||
@spec parse_bban(binary(), <<_::16>>) :: map()
|
||||
def parse_bban(bban_string, country_code, options \\ [incomplete: false])
|
||||
|
||||
def parse_bban(bban_string, country_code, incomplete: true) do
|
||||
Country.country_module(country_code).incomplete_rule()
|
||||
|> parse_bban_by_regex(bban_string)
|
||||
case Country.is_country_code_supported?(country_code) do
|
||||
true ->
|
||||
country_code
|
||||
|> Country.country_module()
|
||||
|> parse_bban_by_country_rules(bban_string)
|
||||
false ->
|
||||
%{}
|
||||
end
|
||||
end
|
||||
|
||||
def parse_bban(bban_string, country_code, _options) do
|
||||
Country.country_module(country_code).rule()
|
||||
|> parse_bban_by_regex(bban_string)
|
||||
def parse_bban(bban_string, country_code, incomplete: false) do
|
||||
case Country.is_country_code_supported?(country_code) do
|
||||
true ->
|
||||
Country.country_module(country_code).rule()
|
||||
|> parse_bban_by_regex(bban_string)
|
||||
false ->
|
||||
%{}
|
||||
end
|
||||
end
|
||||
|
||||
defp parse_bban_by_country_rules(country_module, bban_string) do
|
||||
for {field, rule} <- country_module.rules,
|
||||
into: %{},
|
||||
do: {field, normalize_and_slice(bban_string, rule.range)}
|
||||
end
|
||||
|
||||
defp parse_bban_by_regex(_regex, nil), do: %{}
|
||||
|
||||
defp parse_bban_by_regex(regex, bban_string) do
|
||||
case Regex.named_captures(regex, bban_string) do
|
||||
map when is_map(map) ->
|
||||
for {key, val} <- map,
|
||||
into: %{},
|
||||
do: {String.to_atom(key), blank(val)}
|
||||
do: {String.to_atom(key), val}
|
||||
|
||||
nil ->
|
||||
%{}
|
||||
|
@ -68,11 +108,11 @@ defmodule IbanEx.Parser do
|
|||
end
|
||||
|
||||
@spec country_code(iban_string()) :: country_code_string()
|
||||
def country_code(iban_string), do: normalize_and_slice(iban_string, 0..1) |> blank()
|
||||
def country_code(iban_string), do: normalize_and_slice(iban_string, 0..1)
|
||||
|
||||
@spec check_digits(binary()) :: check_digits_string()
|
||||
def check_digits(iban_string), do: normalize_and_slice(iban_string, 2..3) |> blank()
|
||||
def check_digits(iban_string), do: normalize_and_slice(iban_string, 2..3)
|
||||
|
||||
@spec bban(binary()) :: binary()
|
||||
def bban(iban_string), do: normalize_and_slice(iban_string, 4..-1//1) |> blank()
|
||||
def bban(iban_string), do: normalize_and_slice(iban_string, 4..-1//1)
|
||||
end
|
||||
|
|
|
@ -3,10 +3,11 @@ defmodule IbanEx.Validator do
|
|||
|
||||
alias IbanEx.{Country, Parser}
|
||||
alias IbanEx.Validator.Replacements
|
||||
import IbanEx.Commons, only: [normalize: 1]
|
||||
import IbanEx.Commons, only: [normalize: 1, normalize_and_slice: 2]
|
||||
|
||||
defp error_accumulator(acc, error_message)
|
||||
defp error_accumulator(acc, {:error, error}), do: [error | acc]
|
||||
# defp error_accumulator(acc, list) when is_list(list), do: list ++ acc
|
||||
defp error_accumulator(acc, _), do: acc
|
||||
|
||||
defp violation_functions(),
|
||||
|
@ -15,12 +16,25 @@ defmodule IbanEx.Validator do
|
|||
{&__MODULE__.iban_unsupported_country?/1, {:error, :unsupported_country_code}},
|
||||
{&__MODULE__.iban_violates_length?/1, {:error, :invalid_length}},
|
||||
{&__MODULE__.iban_violates_country_rule?/1, {:error, :invalid_format_for_country}},
|
||||
{&__MODULE__.iban_violates_checksum?/1, {:error, :invalid_checksum}}
|
||||
{&__MODULE__.iban_violates_bank_code_format?/1, {:error, :invalid_bank_code}},
|
||||
{&__MODULE__.iban_violates_account_number_format?/1, {:error, :invalid_account_number}},
|
||||
{&__MODULE__.iban_violates_branch_code_format?/1, {:error, :invalid_branch_code}},
|
||||
{&__MODULE__.iban_violates_national_check_format?/1, {:error, :invalid_national_check}},
|
||||
{&__MODULE__.iban_violates_checksum?/1, {:error, :invalid_checksum}},
|
||||
]
|
||||
|
||||
@doc """
|
||||
Accumulate check results in the list of errors
|
||||
Check iban_violates_format?, iban_unsupported_country?, iban_violates_length?, iban_violates_country_rule?, iban_violates_checksum?
|
||||
Check
|
||||
iban_violates_format?,
|
||||
iban_unsupported_country?,
|
||||
iban_violates_length?,
|
||||
iban_violates_country_rule?,
|
||||
iban_violates_bank_code_format?,
|
||||
iban_violates_account_number_format?
|
||||
iban_violates_branch_code_format?,
|
||||
iban_violates_national_check_format?,
|
||||
iban_violates_checksum?,
|
||||
"""
|
||||
@spec violations(String.t()) :: [] | [atom()]
|
||||
def violations(iban) do
|
||||
|
@ -36,8 +50,11 @@ defmodule IbanEx.Validator do
|
|||
iban_unsupported_country?,
|
||||
iban_violates_length?,
|
||||
iban_violates_country_rule?,
|
||||
iban_violates_checksum?
|
||||
|
||||
iban_violates_bank_code_format?,
|
||||
iban_violates_account_number_format?,
|
||||
iban_violates_branch_code_format?,
|
||||
iban_violates_national_check_format?,
|
||||
iban_violates_checksum?,
|
||||
"""
|
||||
@type iban() :: binary()
|
||||
@type iban_or_error() ::
|
||||
|
@ -46,6 +63,10 @@ defmodule IbanEx.Validator do
|
|||
| {:invalid_format, binary()}
|
||||
| {:invalid_length, binary()}
|
||||
| {:unsupported_country_code, binary()}
|
||||
| {:invalid_bank_code, binary()}
|
||||
| {:invalid_account_number, binary()}
|
||||
| {:invalid_branch_code, binary()}
|
||||
| {:invalid_national_check, binary()}
|
||||
@spec validate(String.t()) :: {:ok, String.t()} | {:error, atom()}
|
||||
|
||||
def validate(iban) do
|
||||
|
@ -54,6 +75,10 @@ defmodule IbanEx.Validator do
|
|||
iban_unsupported_country?(iban) -> {:error, :unsupported_country_code}
|
||||
iban_violates_length?(iban) -> {:error, :invalid_length}
|
||||
iban_violates_country_rule?(iban) -> {:error, :invalid_format_for_country}
|
||||
iban_violates_bank_code_format?(iban) -> {:error, :invalid_bank_code}
|
||||
iban_violates_account_number_format?(iban) -> {:error, :invalid_account_number}
|
||||
iban_violates_branch_code_format?(iban) -> {:error, :invalid_branch_code}
|
||||
iban_violates_national_check_format?(iban) -> {:error, :invalid_national_check}
|
||||
iban_violates_checksum?(iban) -> {:error, :invalid_checksum}
|
||||
true -> {:ok, normalize(iban)}
|
||||
end
|
||||
|
@ -71,6 +96,34 @@ defmodule IbanEx.Validator do
|
|||
def iban_violates_format?(iban),
|
||||
do: Regex.match?(~r/[^A-Z0-9]/i, normalize(iban))
|
||||
|
||||
# - Check whether a given IBAN violates the required format in bank_code.
|
||||
@spec iban_violates_bank_code_format?(binary()) :: boolean
|
||||
def iban_violates_bank_code_format?(iban), do: iban_violates_bban_part_format?(iban, :bank_code)
|
||||
|
||||
# - Check whether a given IBAN violates the required format in branch_code.
|
||||
@spec iban_violates_branch_code_format?(binary()) :: boolean
|
||||
def iban_violates_branch_code_format?(iban), do: iban_violates_bban_part_format?(iban, :branch_code)
|
||||
|
||||
# - Check whether a given IBAN violates the required format in account_number.
|
||||
@spec iban_violates_account_number_format?(binary()) :: boolean
|
||||
def iban_violates_account_number_format?(iban), do: iban_violates_bban_part_format?(iban, :account_number)
|
||||
|
||||
# - Check whether a given IBAN violates the required format in national_check.
|
||||
@spec iban_violates_national_check_format?(binary()) :: boolean
|
||||
def iban_violates_national_check_format?(iban), do: iban_violates_bban_part_format?(iban, :national_check)
|
||||
|
||||
defp iban_violates_bban_part_format?(iban, part) do
|
||||
with country <- Parser.country_code(iban),
|
||||
bban <- Parser.bban(iban),
|
||||
true <- Country.is_country_code_supported?(country),
|
||||
country_module <- Country.country_module(country),
|
||||
{:ok, rule} <- Map.fetch(country_module.rules_map(), part) do
|
||||
!Regex.match?(rule.regex, normalize_and_slice(bban, rule.range))
|
||||
else
|
||||
_ -> false
|
||||
end
|
||||
end
|
||||
|
||||
# - Check whether a given IBAN violates the supported countries.
|
||||
@spec iban_unsupported_country?(String.t()) :: boolean
|
||||
def iban_unsupported_country?(iban) do
|
||||
|
@ -123,7 +176,7 @@ defmodule IbanEx.Validator do
|
|||
rule <- country_module.rule() do
|
||||
!Regex.match?(rule, bban)
|
||||
else
|
||||
{:error, _error} -> true
|
||||
_ -> true
|
||||
end
|
||||
end
|
||||
|
||||
|
|
2
mix.exs
2
mix.exs
|
@ -2,7 +2,7 @@ defmodule IbanEx.MixProject do
|
|||
use Mix.Project
|
||||
|
||||
@source_url "https://g.tulz.dev/opensource/iban-ex"
|
||||
@version "0.1.6"
|
||||
@version "0.1.8"
|
||||
|
||||
def project do
|
||||
[
|
||||
|
|
|
@ -0,0 +1,172 @@
|
|||
defmodule IbanExParserTest do
|
||||
alias IbanEx.{Country, Iban, Parser}
|
||||
use ExUnit.Case, async: true
|
||||
|
||||
@ibans [
|
||||
"AL47212110090000000235698741",
|
||||
"AD1200012030200359100100",
|
||||
"AT611904300234573201",
|
||||
"AZ21NABZ00000000137010001944",
|
||||
"BH67BMAG00001299123456",
|
||||
"BE68539007547034",
|
||||
"BA391290079401028494",
|
||||
"BR1800360305000010009795493C1",
|
||||
"BG80BNBG96611020345678",
|
||||
"CR05015202001026284066",
|
||||
"HR1210010051863000160",
|
||||
"CY17002001280000001200527600",
|
||||
"CZ6508000000192000145399",
|
||||
"DK5000400440116243",
|
||||
"DO28BAGR00000001212453611324",
|
||||
"EG380019000500000000263180002",
|
||||
"SV62CENR00000000000000700025",
|
||||
"EE382200221020145685",
|
||||
"FO6264600001631634",
|
||||
"FI2112345600000785",
|
||||
"FR1420041010050500013M02606",
|
||||
"GE29NB0000000101904917",
|
||||
"DE89370400440532013000",
|
||||
"GI75NWBK000000007099453",
|
||||
"GR1601101250000000012300695",
|
||||
"GL8964710001000206",
|
||||
"GT82TRAJ01020000001210029690",
|
||||
"HU42117730161111101800000000",
|
||||
"IS140159260076545510730339",
|
||||
"IE29AIBK93115212345678",
|
||||
"IL620108000000099999999",
|
||||
"IT60X0542811101000000123456",
|
||||
"JO94CBJO0010000000000131000302",
|
||||
"KZ86125KZT5004100100",
|
||||
"XK051212012345678906",
|
||||
"KW81CBKU0000000000001234560101",
|
||||
"LV80BANK0000435195001",
|
||||
"LB62099900000001001901229114",
|
||||
"LI21088100002324013AA",
|
||||
"LT121000011101001000",
|
||||
"LU280019400644750000",
|
||||
"MK07250120000058984",
|
||||
"MT84MALT011000012345MTLCAST001S",
|
||||
"MR1300020001010000123456753",
|
||||
"MC5811222000010123456789030",
|
||||
"ME25505000012345678951",
|
||||
"NL91ABNA0417164300",
|
||||
"NO9386011117947",
|
||||
"PK36SCBL0000001123456702",
|
||||
"PL61109010140000071219812874",
|
||||
"PT50000201231234567890154",
|
||||
"QA58DOHB00001234567890ABCDEFG",
|
||||
"MD24AG000225100013104168",
|
||||
"RO49AAAA1B31007593840000",
|
||||
"SM86U0322509800000000270100",
|
||||
"SA0380000000608010167519",
|
||||
"RS35260005601001611379",
|
||||
"SK3112000000198742637541",
|
||||
"SI56263300012039086",
|
||||
"ES9121000418450200051332",
|
||||
"SE4550000000058398257466",
|
||||
"CH9300762011623852957",
|
||||
"TL380080012345678910157",
|
||||
"TR330006100519786457841326",
|
||||
"UA213223130000026007233566001",
|
||||
"AE070331234567890123456",
|
||||
"GB29NWBK60161331926819",
|
||||
"VA59001123000012345678",
|
||||
"VG96VPVG0000012345678901"
|
||||
]
|
||||
|
||||
test "parsing valid IBANs from available countries returns {:ok, %IbanEx.Iban{}}" do
|
||||
Enum.all?(@ibans, fn iban ->
|
||||
iban_country =
|
||||
iban
|
||||
|> String.upcase()
|
||||
|> String.slice(0..1)
|
||||
|
||||
result =
|
||||
case {Country.is_country_code_supported?(iban_country), Parser.parse(iban)} do
|
||||
{true, {:ok, %Iban{}}} ->
|
||||
true
|
||||
|
||||
_ ->
|
||||
false
|
||||
end
|
||||
|
||||
assert(result, iban)
|
||||
end)
|
||||
end
|
||||
|
||||
test "parsing invalid IBANs from unavailable countries returns {:error, :unsupported_country_code}" do
|
||||
invalid_ibans =
|
||||
[
|
||||
# Fake country codes
|
||||
"SD3112000000198742637541",
|
||||
"SU56263300012039086",
|
||||
"ZZ9121000418450200051332",
|
||||
"FU4550000000058398257466",
|
||||
"GF9300762011623852957",
|
||||
"FX380080012345678910157",
|
||||
"RT330006100519786457841326",
|
||||
"UL213223130000026007233566001",
|
||||
"AP070331234567890123456",
|
||||
"FF29NWBK60161331926819",
|
||||
"VV59001123000012345678",
|
||||
"GV96VPVG0000012345678901",
|
||||
# Unsupported now by library
|
||||
"AA0096VPVG0000012345",
|
||||
"AO213223130000026",
|
||||
"AX00213223130000026007",
|
||||
"BF3112000000198742637541375",
|
||||
"BI31120000001987",
|
||||
"BJ31120000001987426375413750",
|
||||
"BL3112000000198742637541375",
|
||||
"BY31120000001987426375413754",
|
||||
"CF3112000000198742637541375",
|
||||
"CG3112000000198742637541375",
|
||||
"CI31120000001987426375413750",
|
||||
"CM3112000000198742637541375",
|
||||
"CV31120000001987426375413",
|
||||
"DJ3112000000198742637541375",
|
||||
"DZ3112000000198742637541",
|
||||
"GA3112000000198742637541375",
|
||||
"GF3112000000198742637541375",
|
||||
"GP3112000000198742637541375",
|
||||
"GQ3112000000198742637541375",
|
||||
"GW31120000001987426375413",
|
||||
"HN31120000001987426375413759",
|
||||
"IQ311200000019874263754",
|
||||
"IR311200000019874263754137",
|
||||
"KM3112000000198742637541375",
|
||||
"LC311200000019874263754",
|
||||
"MA31120000001987426375413750",
|
||||
"MF3112000000198742637541375",
|
||||
"MG3112000000198742637541375",
|
||||
"ML31120000001987426375413750",
|
||||
"MQ3112000000198742637541375",
|
||||
"MU3112000000198742637541375000",
|
||||
"MZ31120000001987426375413",
|
||||
"NC3112000000198742637541375",
|
||||
"NE31120000001987426375413750",
|
||||
"NI311200000019874263754137500000",
|
||||
"PF3112000000198742637541375",
|
||||
"PM3112000000198742637541375",
|
||||
"PS311200000019874263754137500",
|
||||
"RE3112000000198742637541375",
|
||||
"SC311200000019874263754137500000",
|
||||
"SN31120000001987426375413750",
|
||||
"ST31120000001987426375413",
|
||||
"TD3112000000198742637541375",
|
||||
"TF3112000000198742637541375",
|
||||
"TG31120000001987426375413750",
|
||||
"TN3112000000198742637541",
|
||||
"WF3112000000198742637541375",
|
||||
"YT3112000000198742637541375"
|
||||
]
|
||||
|
||||
Enum.all?(
|
||||
invalid_ibans,
|
||||
&assert(
|
||||
match?({:error, :unsupported_country_code}, Parser.parse(&1)),
|
||||
"expected #{&1} to match {:error, :unsupported_country_code}"
|
||||
)
|
||||
)
|
||||
end
|
||||
end
|
|
@ -1,6 +1,6 @@
|
|||
defmodule IbanExTest do
|
||||
alias IbanEx.{Country, Iban, Parser}
|
||||
use ExUnit.Case, async: true
|
||||
|
||||
doctest_file "README.md"
|
||||
doctest IbanEx.Country.AD
|
||||
doctest IbanEx.Country.AE
|
||||
|
@ -37,6 +37,7 @@ defmodule IbanExTest do
|
|||
doctest IbanEx.Country.IE
|
||||
doctest IbanEx.Country.IL
|
||||
doctest IbanEx.Country.IT
|
||||
doctest IbanEx.Country.IS
|
||||
doctest IbanEx.Country.KZ
|
||||
doctest IbanEx.Country.KW
|
||||
doctest IbanEx.Country.LB
|
||||
|
@ -70,93 +71,4 @@ defmodule IbanExTest do
|
|||
doctest IbanEx.Country.VA
|
||||
doctest IbanEx.Country.VG
|
||||
doctest IbanEx.Country.XK
|
||||
|
||||
@ibans [
|
||||
"AL47212110090000000235698741",
|
||||
"AD1200012030200359100100",
|
||||
"AT611904300234573201",
|
||||
"AZ21NABZ00000000137010001944",
|
||||
"BH67BMAG00001299123456",
|
||||
"BE68539007547034",
|
||||
"BA391290079401028494",
|
||||
"BR1800360305000010009795493C1",
|
||||
"BG80BNBG96611020345678",
|
||||
"CR05015202001026284066",
|
||||
"HR1210010051863000160",
|
||||
"CY17002001280000001200527600",
|
||||
"CZ6508000000192000145399",
|
||||
"DK5000400440116243",
|
||||
"DO28BAGR00000001212453611324",
|
||||
"EG380019000500000000263180002",
|
||||
"SV62CENR00000000000000700025",
|
||||
"EE382200221020145685",
|
||||
"FO6264600001631634",
|
||||
"FI2112345600000785",
|
||||
"FR1420041010050500013M02606",
|
||||
"GE29NB0000000101904917",
|
||||
"DE89370400440532013000",
|
||||
"GI75NWBK000000007099453",
|
||||
"GR1601101250000000012300695",
|
||||
"GL8964710001000206",
|
||||
"GT82TRAJ01020000001210029690",
|
||||
"HU42117730161111101800000000",
|
||||
"IS140159260076545510730339",
|
||||
"IE29AIBK93115212345678",
|
||||
"IL620108000000099999999",
|
||||
"IT60X0542811101000000123456",
|
||||
"JO94CBJO0010000000000131000302",
|
||||
"KZ86125KZT5004100100",
|
||||
"XK051212012345678906",
|
||||
"KW81CBKU0000000000001234560101",
|
||||
"LV80BANK0000435195001",
|
||||
"LB62099900000001001901229114",
|
||||
"LI21088100002324013AA",
|
||||
"LT121000011101001000",
|
||||
"LU280019400644750000",
|
||||
"MK07250120000058984",
|
||||
"MT84MALT011000012345MTLCAST001S",
|
||||
"MR1300020001010000123456753",
|
||||
"MC5811222000010123456789030",
|
||||
"ME25505000012345678951",
|
||||
"NL91ABNA0417164300",
|
||||
"NO9386011117947",
|
||||
"PK36SCBL0000001123456702",
|
||||
"PL61109010140000071219812874",
|
||||
"PT50000201231234567890154",
|
||||
"QA58DOHB00001234567890ABCDEFG",
|
||||
"MD24AG000225100013104168",
|
||||
"RO49AAAA1B31007593840000",
|
||||
"SM86U0322509800000000270100",
|
||||
"SA0380000000608010167519",
|
||||
"RS35260005601001611379",
|
||||
"SK3112000000198742637541",
|
||||
"SI56263300012039086",
|
||||
"ES9121000418450200051332",
|
||||
"SE4550000000058398257466",
|
||||
"CH9300762011623852957",
|
||||
"TL380080012345678910157",
|
||||
"TR330006100519786457841326",
|
||||
"UA213223130000026007233566001",
|
||||
"AE070331234567890123456",
|
||||
"GB29NWBK60161331926819",
|
||||
"VA59001123000012345678",
|
||||
"VG96VPVG0000012345678901"
|
||||
]
|
||||
|
||||
test "parsing valid IBANs from available countries returns {:ok, %IbanEx.Iban{}}" do
|
||||
assert Enum.all?(@ibans, fn iban ->
|
||||
iban_country = iban |> String.upcase() |> String.slice(0..1)
|
||||
|
||||
case {Country.is_country_code_supported?(iban_country), Parser.parse(iban)} do
|
||||
{true, {:ok, %Iban{}}} ->
|
||||
true
|
||||
|
||||
{false, {:error, :unsupported_country_code}} ->
|
||||
true
|
||||
|
||||
_ ->
|
||||
false
|
||||
end
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -2,7 +2,121 @@ defmodule IbanExValidatorTest do
|
|||
alias IbanEx.{Validator}
|
||||
use ExUnit.Case, async: true
|
||||
|
||||
test "check IBANs length" do
|
||||
@ibans [
|
||||
"AL47212110090000000235698741",
|
||||
"AD1200012030200359100100",
|
||||
"AT611904300234573201",
|
||||
"AZ21NABZ00000000137010001944",
|
||||
"BH67BMAG00001299123456",
|
||||
"BE68539007547034",
|
||||
"BA391290079401028494",
|
||||
"BR1800360305000010009795493C1",
|
||||
"BG80BNBG96611020345678",
|
||||
"CR05015202001026284066",
|
||||
"HR1210010051863000160",
|
||||
"CY17002001280000001200527600",
|
||||
"CZ6508000000192000145399",
|
||||
"DK5000400440116243",
|
||||
"DO28BAGR00000001212453611324",
|
||||
"EG380019000500000000263180002",
|
||||
"SV62CENR00000000000000700025",
|
||||
"EE382200221020145685",
|
||||
"FO6264600001631634",
|
||||
"FI2112345600000785",
|
||||
"FR1420041010050500013M02606",
|
||||
"GE29NB0000000101904917",
|
||||
"DE89370400440532013000",
|
||||
"GI75NWBK000000007099453",
|
||||
"GR1601101250000000012300695",
|
||||
"GL8964710001000206",
|
||||
"GT82TRAJ01020000001210029690",
|
||||
"HU42117730161111101800000000",
|
||||
"IS140159260076545510730339",
|
||||
"IE29AIBK93115212345678",
|
||||
"IL620108000000099999999",
|
||||
"IT60X0542811101000000123456",
|
||||
"JO94CBJO0010000000000131000302",
|
||||
"KZ86125KZT5004100100",
|
||||
"XK051212012345678906",
|
||||
"KW81CBKU0000000000001234560101",
|
||||
"LV80BANK0000435195001",
|
||||
"LB62099900000001001901229114",
|
||||
"LI21088100002324013AA",
|
||||
"LT121000011101001000",
|
||||
"LU280019400644750000",
|
||||
"MK07250120000058984",
|
||||
"MT84MALT011000012345MTLCAST001S",
|
||||
"MR1300020001010000123456753",
|
||||
"MC5811222000010123456789030",
|
||||
"ME25505000012345678951",
|
||||
"NL91ABNA0417164300",
|
||||
"NO9386011117947",
|
||||
"PK36SCBL0000001123456702",
|
||||
"PL61109010140000071219812874",
|
||||
"PT50000201231234567890154",
|
||||
"QA58DOHB00001234567890ABCDEFG",
|
||||
"MD24AG000225100013104168",
|
||||
"RO49AAAA1B31007593840000",
|
||||
"SM86U0322509800000000270100",
|
||||
"SA0380000000608010167519",
|
||||
"RS35260005601001611379",
|
||||
"SK3112000000198742637541",
|
||||
"SI56263300012039086",
|
||||
"ES9121000418450200051332",
|
||||
"SE4550000000058398257466",
|
||||
"CH9300762011623852957",
|
||||
"TL380080012345678910157",
|
||||
"TR330006100519786457841326",
|
||||
"UA213223130000026007233566001",
|
||||
"AE070331234567890123456",
|
||||
"GB29NWBK60161331926819",
|
||||
"VA59001123000012345678",
|
||||
"VG96VPVG0000012345678901"
|
||||
]
|
||||
|
||||
test "Check Account number format positive cases" do
|
||||
Enum.all?(@ibans, &assert(!Validator.iban_violates_account_number_format?(&1), &1))
|
||||
end
|
||||
|
||||
test "Check National check format positive cases" do
|
||||
Enum.all?(@ibans, &assert(!Validator.iban_violates_national_check_format?(&1), &1))
|
||||
end
|
||||
|
||||
test "Check Branch code format positive cases" do
|
||||
Enum.all?(@ibans, &assert(!Validator.iban_violates_branch_code_format?(&1), &1))
|
||||
end
|
||||
|
||||
test "Check Bank code format positive cases" do
|
||||
Enum.all?(@ibans, &assert(!Validator.iban_violates_bank_code_format?(&1), &1))
|
||||
end
|
||||
|
||||
test "Check Account number format negative cases" do
|
||||
cases = [
|
||||
# shorter then need
|
||||
{"AL4721211009000000023568741", true},
|
||||
{"AD120001203020035900100", true},
|
||||
{"AZ21NABZ0000000013701000944", true},
|
||||
# invalid characters (leters) in number
|
||||
{"AT6119043002A4573201", true},
|
||||
{"BH67BMAG000012991A3456", true},
|
||||
{"BE685390075X7034", true},
|
||||
{"BA391290079401S28494", true},
|
||||
{"BR180036030500001000979549CC1", true},
|
||||
{"HR12100100518630001", true},
|
||||
# shorter then need and has
|
||||
# invalid characters (leters) in number
|
||||
{"BR18003603050000100097CC1", true},
|
||||
{"CR050152020010262806Ї", true},
|
||||
# FIXME it is invalid IBAN for Bulgaria — need to change a rules function in Country Template module
|
||||
# {"BG80BNBG9661102034567Ї", true},
|
||||
]
|
||||
|
||||
Enum.all?(cases, fn {iban, result} ->
|
||||
assert(Validator.iban_violates_account_number_format?(iban) == result, iban)
|
||||
end)
|
||||
end
|
||||
|
||||
test "Check IBANs length" do
|
||||
cases = [
|
||||
{"FG2112345CC6000007", {:error, :unsupported_country_code}},
|
||||
{"UK2112345CC6000007", {:error, :unsupported_country_code}},
|
||||
|
|
Loading…
Reference in New Issue