Packages
propcheck_commons
0.1.0
A set of common `generators` for use with `PropCheck` and `ProPEr`.
Current section
Files
Jump to
Current section
Files
lib/network.ex
defmodule PropCheckCommons.Network do
@moduledoc """
A set of `ProPEr` generators for common _network_ based inputs.
"""
use PropCheck
import PropCheckCommons.Text, only: [alphanumeric: 0]
@email_symbols ["" | String.split(". _ - +")]
@domain_symbols ["" | String.split(". -")]
@type proper_type :: :proper_types.type()
@type static_range_16 :: non_neg_integer()
@type static_range_24 :: {non_neg_integer(), non_neg_integer()}
@type static_range_32 :: {non_neg_integer(), non_neg_integer(), non_neg_integer()}
@type ip_format :: :tuple | :string
@doc """
Get an IPv4 address when there is a given subnet mask. There are two format types that
it can return, `:tuple` and `:string` for `{192, 168, 0, 0}` and `"192.168.0.0"` respectively.
The default is `:string`.
## Examples
iex> use PropCheck
iex> alias PropCheckCommons.Network
iex> {:ok, "192.168" <> _} = produce(Network.ipv4(0))
iex> {:ok, {10, 10, 1, num}} = produce(Network.ipv4(24, {10, 10, 1}, :tuple))
iex> num >= 0 and num < 256
:true
"""
@spec ipv4(
non_neg_integer(),
static_range_16() | static_range_24() | static_range_32(),
ip_format()
) :: proper_type()
def ipv4(subnet_mask \\ 24, static \\ {192, 168}, format \\ :string)
def ipv4(subnet_mask, {one, two, three}, format) when subnet_mask > 24 and subnet_mask <= 32 do
mask_range = get_min_range_from_mask(subnet_mask - 24)
let four <- range(mask_range, 255) do
ipv4_format(format, {one, two, three, four})
end
end
def ipv4(subnet_mask, {one, two}, format) when subnet_mask > 16 and subnet_mask <= 24 do
mask_range = get_min_range_from_mask(subnet_mask - 16)
let {three, four} <- {range(mask_range, 255), range(0, 255)} do
ipv4_format(format, {one, two, three, four})
end
end
def ipv4(subnet_mask, one, format) when subnet_mask > 8 and subnet_mask <= 16 do
mask_range = get_min_range_from_mask(subnet_mask - 8)
let {two, three, four} <- {range(mask_range, 255), range(0, 255), range(0, 255)} do
ipv4_format(format, {one, two, three, four})
end
end
def ipv4(subnet_mask, _, format) when subnet_mask >= 0 and subnet_mask <= 8 do
mask_range = get_min_range_from_mask(subnet_mask)
let {one, two, three, four} <-
{range(mask_range, 255), range(0, 255), range(0, 255), range(0, 255)} do
ipv4_format(format, {one, two, three, four})
end
end
defp get_min_range_from_mask(8), do: 255
defp get_min_range_from_mask(7), do: 254
defp get_min_range_from_mask(6), do: 252
defp get_min_range_from_mask(5), do: 248
defp get_min_range_from_mask(4), do: 240
defp get_min_range_from_mask(3), do: 224
defp get_min_range_from_mask(2), do: 192
defp get_min_range_from_mask(1), do: 128
defp get_min_range_from_mask(0), do: 0
defp ipv4_format(:tuple, addr_tuple), do: addr_tuple
defp ipv4_format(:string, addr_tuple), do: Enum.join(Tuple.to_list(addr_tuple), ".")
# TODO: Define a generator based on the email specifications
@doc """
Generic email address with alphanumeric characters and common symbols.
This does not generate emails based on the email name specifications which
are in general, too relaxed for most software systems.
"""
@spec email(pos_integer()) :: proper_type()
def email(size \\ 100) when is_integer(size) do
var_gen =
such_that(
{lp1, _mid, lp2, lp3, _tld} <- {
non_empty(alphanumeric()),
oneof(@email_symbols),
non_empty(alphanumeric()),
non_empty(alphanumeric()),
tld()
},
when: Enum.sum([length(lp1), length(lp2), length(lp3)]) < size
)
let {lp1, mid, lp2, lp3, tld} <- var_gen do
Enum.join([to_string(lp1), mid, to_string(lp2), "@", to_string(lp3), tld])
end
end
# TODO: create option for internationalized domain names
@doc """
Non-internationalized domain names
"""
@spec domain_name() :: proper_type()
def domain_name do
var_gen =
such_that(
{lp1, _mid, lp2, _tld} <- {
non_empty(alphanumeric()),
oneof(@domain_symbols),
non_empty(alphanumeric()),
tld()
},
when: length(lp1) < 30 && length(lp2) < 30
)
let {lp1, mid, lp2, tld} <- var_gen do
Enum.join([to_string(lp1), mid, to_string(lp2), tld])
end
end
@doc """
Chooses from a list of well-defined and valid top level domains.
"""
@spec tld() :: proper_type()
def tld do
oneof([
".com",
".co",
".co.jp",
".org",
".net",
".team",
".biz",
".gov",
".cancer",
".cn",
".rs",
".ez",
".eu",
".nk",
".int",
".edu",
".mil"
])
end
end