diff --git a/USAGE.md b/USAGE.md index a323a03c6..ea400cb6e 100644 --- a/USAGE.md +++ b/USAGE.md @@ -96,6 +96,7 @@ - [Faker.Person.PtBr](lib/faker/person/pt_br.ex) - [Faker.Phone.EnUs](lib/faker/phone/en_us.ex) - [Faker.Phone.EnGb](lib/faker/phone/en_gb.ex) +- [Faker.Phone.EnZa](lib/faker/phone/en_za.ex) - [Faker.Phone.Hy](lib/faker/phone/hy.ex) - [Faker.Phone.PtBr](lib/faker/phone/pt_br.ex) - [Faker.Pizza](lib/faker/pizza.ex) diff --git a/lib/faker/phone/en_za.ex b/lib/faker/phone/en_za.ex new file mode 100644 index 000000000..9c6e02d68 --- /dev/null +++ b/lib/faker/phone/en_za.ex @@ -0,0 +1,117 @@ +defmodule Faker.Phone.EnZa do + import Faker, only: [samplerp: 2] + + @moduledoc """ + This follows the rules outlined in the Telephone numbers in South Africa + at https://en.wikipedia.org/wiki/Telephone_numbers_in_South_Africa + + + The NPR (Numbering Plan Regulations) number format may be summarized in the notation (AB)XXX-XXXX: + Access codes: + - Country calling code = +27, appended for internationally calling + - Trunk prefix = 0, appended for calling within the country + + The allowed area codes within the system are generally organized geographically, per province/state. + The telephone within the system comes in two formats, landline and cellular. + + The allowed numbers ranges are: + + Landline format range: + - [011-058] + + Cellular format range: + - [060-089] + """ + + @mobile_start_digit 6 + @landline_start_digit 1 + @number_formats ~w(cellular landline)a + + @doc """ + Returns a random ZA phone number + + Possible returned formats: + 0113456789 + 0603456789 + 0713456789 + 27613456789 + 0823456789 + + ## Examples + iex> Faker.Phone.EnZa.phone() + "0603456789" + iex> Faker.Phone.EnZa.phone() + "27823456789" + iex> Faker.Phone.EnZa.phone() + "27613456789" + iex> Faker.Phone.EnZa.phone() + "0113456789" + """ + @spec phone() :: String.t() + def phone() do + @number_formats + |> Enum.random() + |> phone_output_format() + end + + @doc """ + Returns a random ZA cell phone number + + ## Examples + iex> Faker.Phone.EnZa.cell_number() + "0603456789" + iex> Faker.Phone.EnZa.cell_number() + "27823456789" + iex> Faker.Phone.EnZa.cell_number() + "27613456789" + iex> Faker.Phone.EnZa.cell_number() + "27713456789" + """ + @spec cell_number() :: String.t() + def cell_number(), do: phone_output_format(:cellular) + + @doc """ + Returns a random ZA landline phone number + + ## Examples + iex> Faker.Phone.EnZa.landline_number() + "0113456789" + iex> Faker.Phone.EnZa.landline_number() + "0123456789" + iex> Faker.Phone.EnZa.landline_number() + "0133456789" + iex> Faker.Phone.EnZa.landline_number() + "0143456789" + """ + @spec landline_number() :: String.t() + def landline_number(), do: phone_output_format(:landline) + + @spec phone_output_format(Atom.t()) :: String.t() + defp phone_output_format(_output_format = :cellular) do + cellular_number_format() + |> number_format(@mobile_start_digit) + end + + defp phone_output_format(_output_format = :landline) do + landline_number_format() + |> number_format(@landline_start_digit) + end + + @spec number_format(String.t(), number()) :: String.t() + defp number_format(phone_number, initial_n) do + phone_number + |> String.replace("x", "#{digit(initial_n, 8)}") + |> Faker.format() + end + + defp digit(min, max), do: Faker.random_between(min, max) + + samplerp(:cellular_number_format, [ + "0x########", + "27x########" + ]) + + samplerp(:landline_number_format, [ + "01x#######" + ]) +end diff --git a/test/faker/phone/en_za_test.exs b/test/faker/phone/en_za_test.exs new file mode 100644 index 000000000..3652ad576 --- /dev/null +++ b/test/faker/phone/en_za_test.exs @@ -0,0 +1,24 @@ +defmodule Faker.Phone.EnZaTest do + use ExUnit.Case, async: true + + import Faker.Phone.EnZa + + @iterations 10_000 + @max_phone_number_length 10 + + test "landline_number/0 has a valid length" do + Stream.repeatedly(&landline_number/0) + |> Enum.take(@iterations) + |> Enum.each(fn generated_value -> + assert String.length(generated_value) == @max_phone_number_length + end) + end + + test "cell_number/0 return starts with 0, 27" do + Stream.repeatedly(&cell_number/0) + |> Enum.take(@iterations) + |> Enum.each(fn generated_value -> + assert String.match?(generated_value, ~r/^(27|0)[0-9]{9}$/) + end) + end +end