keep : Outcome
Mark a generated value as useful after the property has held.
:= []
Define typed, deterministic inputs and the pure property that roc-fuzz tests.
Most targets use target, return keep for useful
inputs, and build their input generator from u8, u64, str, bytes,
and list. Generators for record fields compose with Roc's .Fuzz record
builder.
Input := { bytes : List(U8), radix : U8 }.{
generator_for = |_| {
{ bytes: Fuzz.bytes, radix: Fuzz.u8_in(2, 36) }.Fuzz
}
}
target = Fuzz.target({
name: "decode",
test: |input| if input.bytes.is_empty() Fuzz.reject else Fuzz.keep,
show: Str.inspect,
})
Start with these typed combinators. target_with,
from_bytes, and the Arbitrary module support advanced or
migration use cases.
keep : Outcome
Mark a generated value as useful after the property has held.
reject : Outcome
Discard a generated value that is outside the property's valid domain.
Prefer generators that produce valid inputs directly. Use reject for
preconditions that are awkward or expensive to encode in a generator.
target : { name : Str, test : a -> Outcome, show : a -> Str } -> Target where [a.generator_for : FuzzEncoding -> Generator(a)]
Build a fuzz target using the input type's statically dispatched generator.
The input type must define generator_for : FuzzEncoding -> Generator(a).
For each fuzzer input, target generates one value, calls test, and uses
show when a person asks the runner to render that saved input.
target_with : { name : Str, generator : Generator(a), test : a -> Outcome, show : a -> Str } -> Target
Build a target from an explicit generator.
This is useful for a one-off structural input that does not need a nominal
generator_for method. Prefer target when the input type owns
its generation policy.
Adapt an existing List(U8) -> U8 quality target.
The returned byte is ignored; a crash or failed expect still reports a
failure. This is a migration bridge for existing byte-oriented targets.
New targets should prefer target and typed generators.
constant : a -> Generator(a)
Generate the same value without consuming any input bytes.
map : Generator(a), (a -> b) -> Generator(b)
Transform the value produced by a generator while preserving its state.
map2 : Generator(a), Generator(b), (a, b -> c) -> Generator(c)
Generate two values in sequence and combine them.
Roc's { first: gen_a, second: gen_b }.Fuzz record-builder syntax lowers
to this combinator and chains it for larger records. Calling map2
directly is useful for tuples and custom constructors.
Generate any U8 value.
Generate a U8 in the inclusive range from low through high.
The generator crashes if low is greater than high.
Generate any U64 value.
Generate a U64 in the inclusive range from low through high.
The generator crashes if low is greater than high.
Generate a byte list with a length and allocation shape chosen from input.
Use raw_bytes when the target must receive every fuzzer
byte unchanged.
Generate the complete fuzzer input as one byte list without decoding it.
This is mainly useful for migration and byte-format targets. Typed targets usually get better mutations and clearer properties from smaller generators composed into their real input shape.
Generate a valid UTF-8 Str with varied length and allocation shape.
Generate a list containing at most max_len values.
Lengths range from zero through max_len, inclusive. max_len limits the
decoded list length; the runner's maximum raw input size is configured
separately.
:= [Keep, Reject]
Whether a generated value belongs to the useful input domain.
Return Keep after the property holds. Return Reject when a generated
value does not satisfy a precondition. A crash or failed expect is a
fuzz failure; Reject is not.
A deterministic decoder from fuzzer bytes to a typed Roc value.
Each generator returns the generated value and the unconsumed state, so
combinators can decode several values from one input. Most applications do
not need to inspect Arbitrary directly.
:= [Default]
Selects the generator used by a nominal type's generator_for method.
Default is currently the only encoding. The marker gives static dispatch
the same shape as APIs such as Json.parser_for and leaves room for future
generation policies.