Packages

Construct streams of values by specifying composable generator functions. For example list(tuple(like: {atom, string})) will generate a random length keyword list with random keys and values. Constraints can be applied at all levels.

Current section

Files

Jump to
pollution lib pollution generators atom.ex
Raw

lib/pollution/generators/atom.ex

defmodule Pollution.Generator.Atom do
@moduledoc false
alias Pollution.{State, VG}
alias Pollution.Generator, as: G
alias Pollution.Shrinker.Params, as: SP
@defaults %State{
type: __MODULE__,
must_have: [],
min: 0, # atom length
max: 255,
extra: %{
delegate: nil, # VG.list(min: 0, max: 6)
},
}
def create(options) do
@defaults
|> State.add_derived_to_state(options)
|> State.add_min_max_length_to_state(options)
|> create_delegate(options)
end
def filters, do: %{}
@doc """
Return a tuple containing the next value for this type, along with a
potentially updated type state.
The next value is chosen randomly from generator_constraints.list
"""
def next_value(state, locals) do
G.after_emptying_must_have(state, fn (state) ->
{ list, list_state } = G.next_value(state.extra.delegate, locals)
val = List.to_atom(list)
state = update_delegate(state, list_state)
{val, state}
end)
end
def update_constraints(state) do
State.trim_must_have_to_range_based_on(state, &atom_length/1)
end
defp atom_length(atom) do
atom |> Atom.to_string |> String.length
end
defp create_delegate(state, options) do
must_have = convert_must_have(options[:must_have], state.must_have)
delegate = VG.list(min: state.min,
max: state.max,
of: VG.int(min: 33, max: 126),
must_have: must_have)
update_delegate(state, delegate)
end
defp update_delegate(state, delegate) do
Map.put(state, :extra, %{ delegate: delegate })
end
defp convert_must_have(nil, must_have), do: must_have
defp convert_must_have(must_haves, _) when is_list(must_haves) do
must_haves |> Enum.map(&convert_one_must_have/1)
end
defp convert_one_must_have(atom) when is_atom(atom), do: Atom.to_charlist(atom)
defp convert_one_must_have(str) when is_binary(str), do: String.to_charlist(str)
defp convert_one_must_have(list) when is_list(list), do: list
###################
# Shrinking stuff #
###################
def params_for_shrink(%{ min: min, max: max }, current) do
%SP{
low: min, # lengths
high: max,
current: current,
shrink: &shrink_one/1,
backtrack: &shrink_backtrack/1
}
end
def shrink_one(sp = %SP{low: low, current: current}) do
chars = Atom.to_charlist(current)
len = length(chars)
cond do
len == low ->
%SP{ sp | done: true }
true ->
%SP{ sp | current: tl(chars) |> List.to_atom }
end
end
def shrink_backtrack(sp = %SP{}) do
%SP{ sp | done: true }
end
end