StreamData generators built from a schema, for the round-trip property.
Add stream_data to your own deps to use this — Rupa lists it as optional, so it is not
forced on anyone who only wants to decode.
property "encode and decode are inverses" do
codec = Rupa.compile!(MyApp.Schemas.user())
check all value <- Rupa.Gen.stream(codec) do
assert {:ok, wire} = Rupa.encode(codec, value)
assert {:ok, ^value} = Rupa.decode(codec, wire)
end
endWhat it generates is decoded values — what Rupa.decode/3 returns and Rupa.encode/3
takes — because that is the side the property is stated on. A field carrying default:
is always generated, even though it is optional on the wire: leave it out and decoding
fills it in, and the value that comes back is not the one you started with.
What it refuses
A generator that quietly skips half your schema is worse than one that will not start, so these raise with the path rather than being ignored:
pattern:— generating a string from a PCRE is a project of its ownmultiple_of:on a float, or one that is not a whole number on an integer — the multiples of0.1are not representable, so the values it produced would fail the check they were generated to satisfy- a bound that nothing satisfies, such as
T.integer(gt: 1, lt: 2)or a float interval with no double in it - a recursion with no case that stops, such as
%{child: T.ref(:root)}, which has no finite value at all
Untagged unions
An untagged union generates from one of its variants at random, which round-trips only if
the variants are disjoint — if two of them accept the same value, decoding picks the first
and the property will tell you so. That is the cost tag: :none makes you opt into, and
Rupa.T.tagged/3 is the version with nothing to be ambiguous about.
Summary
Functions
A generator of decoded values for a codec, a generated module, or a schema.
Functions
@spec stream(term()) :: StreamData.t(term())
A generator of decoded values for a codec, a generated module, or a schema.
iex> [value] = %{n: Rupa.T.integer(gte: 1, lte: 3)} |> Rupa.Gen.stream() |> Enum.take(1)
iex> value.n in 1..3
true