Packages
protox
0.7.1
2.0.9
2.0.8
2.0.7
2.0.6
2.0.5
2.0.4
2.0.3
2.0.2
2.0.1
2.0.0
2.0.0-dev
1.7.8
1.7.7
1.7.6
1.7.5
1.7.4
retired
1.7.3
1.7.2
1.7.1
1.7.0
1.6.10
1.6.9
1.6.8
1.6.7
1.6.6
1.6.5
1.6.4
1.6.3
1.6.2
1.6.1
1.6.0
1.5.1
1.5.0
1.4.0
1.3.2
1.3.1
1.3.0
1.2.4
1.2.3
1.2.2
1.2.1
1.2.0
1.1.1
1.1.0
1.0.0
0.25.0
0.24.0
0.23.1
0.23.0
0.22.0
0.21.0
0.20.0
0.19.1
0.19.0
0.18.0
0.17.0
0.16.2
0.16.1
0.16.0
0.15.2
0.15.1
0.15.0
0.14.0
0.13.0
0.12.1
0.12.0
0.11.1
0.11.0
0.10.0
0.9.1
0.9.0
0.8.0
0.7.1
0.7.0
A fast, easy to use and 100% conformant Elixir library for Google Protocol Buffers (aka protobuf)
Current section
Files
Jump to
Current section
Files
lib/protox/random_init.ex
defmodule Protox.RandomInit do
@moduledoc"""
Provides a way to randomly init a message. Useful for tests or benchmarks.
"""
import Protox.Guards
@doc"""
Generates a randomly initialized message using its definition. It's possible to
give a seed as the second parameter to get reproducible results.
"""
@spec generate(atom, nil | integer) :: struct
def generate(mod, seed \\ nil) do
if seed != nil do
:rand.seed(:exs1024, {seed, seed, seed})
end
do_generate(mod)
end
# -- Private
defp do_generate(mod) do
Enum.reduce(mod.defs(), struct(mod.__struct__),
fn ({_, {name, kind, type}}, msg) ->
case kind do
{:oneof, _} -> msg # TODO.
_ -> struct!(msg, [{name, value(kind, type)}])
end
end)
end
# Recursively descend a message definition to randomly init fields.
defp value({:default, _}, {:enum, enum}) do
enum.constants() |> Map.new() |> Map.values() |> Enum.random()
end
defp value({:default, _}, :bool) do
:rand.uniform(2) == 1
end
defp value({:default, _}, ty)
when ty == :int32 or ty == :int64 or ty == :sint32 or ty == :sint64 or ty == :sfixed32
or ty == :sfixed64
do
:rand.uniform(100) * sign()
end
defp value({:default, _}, ty) when ty == :double or ty == :float do
:rand.uniform(1_000_000) * :rand.uniform() * sign()
end
defp value({:default, _}, ty) when is_primitive(ty) do
:rand.uniform(1_000_000)
end
defp value({:default, _}, :bytes) do
Enum.reduce(1..:rand.uniform(10), <<>>, fn (b, acc) -> <<b, acc::binary>> end)
end
defp value({:default, _}, :string) do
if sign() == 1, do: "#{Protox.Util.random_string(:rand.uniform(100))}", else: ""
end
defp value({:default, _}, {:message, name}) do
if :rand.uniform(2) == 1 do
do_generate(name)
else
nil
end
end
defp value(kind, :bool) when kind == :packed or kind == :unpacked do
for _ <- 1..:rand.uniform(10), do: value({:default, nil}, :bool)
end
defp value(kind, ty) when is_primitive(ty) and (kind == :packed or kind == :unpacked) do
for _ <- 1..:rand.uniform(10), do: :rand.uniform(100)
end
defp value(kind, e = {:enum, _}) when kind == :packed or kind == :unpacked do
for _ <- 1..:rand.uniform(10), do: value({:default, nil}, e)
end
defp value(:unpacked, m = {:message, _}) do
Enum.reduce(
1..:rand.uniform(10),
[],
fn (_ , acc) ->
sub = value({:default, nil}, m)
if sub do
[sub | acc]
else
acc
end
end
)
end
defp value(:map, {key_type, value_type}) do
Enum.reduce(
1..:rand.uniform(10),
%{},
fn (_ , acc) ->
key = value({:default, nil}, key_type)
value = value({:default, nil}, value_type)
if key && value do
Map.put(acc, key, value)
else
acc
end
end
)
end
# Get a random sign.
defp sign() do
if :rand.uniform(2) == 1, do: -1, else: 1
end
end