aiken/fuzz

Functions

Constructing

Primitives

bool() -> Fuzzer<Bool>

Generate a random Bool value from a uniform distribution.

test prop_bool(is_true via fuzz.bool()) {
  is_true || !is_true
}

constant(a: a) -> Fuzzer<a>

Create a constant Fuzzer from an arbitrary value.

byte() -> Fuzzer<Int>

Generate a byte uniformly across the range [0; 255].

bytearray() -> Fuzzer<ByteArray>

Generate a random ByteArray of 32 bytes.

bytearray_between(min: Int, max: Int) -> Fuzzer<ByteArray>

Generate a random ByteArray of size within a lower and upper bounds.

bytearray_fixed(len: Int) -> Fuzzer<ByteArray>

Generate a random ByteArray of len bytes.

int() -> Fuzzer<Int>

Generate a random integer value. It favors small values near zero, but generate across the range [-255; 16383] with the following distribution:

25.0%  [-255; 0[      ████████████
 2.5%  0              █
50.0%  ]0; 255]       █████████████████████████
22.5%  [256; 16383]   ██████████

The distribution is uniform within those buckets. If you need larger values, use int_between.

int_between(min: Int, max: Int) -> Fuzzer<Int>

Generate integers values uniformly between a lower and upper bounds (both inclusive).

int_at_least(min: Int) -> Fuzzer<Int>

Generate a random integer which is at least min.

int_at_most(max: Int) -> Fuzzer<Int>

Generate a random integer which is at most max.

Data-structures

list(fuzzer: Fuzzer<a>) -> Fuzzer<List<a>>

Generate a random list of elements from a given fuzzer. The list contains at most 20 elements, and has a higher probability of generating smaller lists.

For lists of a specific length, use list_between.

list_between(fuzzer: Fuzzer<a>, min: Int, max: Int) -> Fuzzer<List<a>>

Generate a random list of elements with length within specified bounds. The resulting list contains at least min elements and at most max elements, with a higher probability of generating smaller lists.

More specifically, there’s approximately 1/n chance of generating n elements within the range. For example, the distribution when generating a list between 0 and 10 elements resemble the following:

22.7%   0 elements  ████████
19.7%   1 element   ███████
13.5%   2 elements  █████
 9.5%   3 elements  ███
 6.3%   4 elements  ██
 5.6%   5 elements  ██
 5.6%   6 elements  ██
 4.0%   7 elements  █
 3.1%   8 elements  █
 2.0%   9 elements  █
 8.0%  10 elements  ███

list_at_least(fuzzer: Fuzzer<a>, min: Int) -> Fuzzer<List<a>>

Generate a random list of elements from a given fuzzer, with at least min elements.

list_at_most(fuzzer: Fuzzer<a>, max: Int) -> Fuzzer<List<a>>

Generate a random list of elements from a given fuzzer, with at most max elements.

list_with_elem(fuzzer: Fuzzer<a>) -> Fuzzer<(List<a>, a)>

Generate a random list and pick an element from that list. Return both.

pick(xs: List<a>) -> Fuzzer<(Int, a)>

Pick an element from a list, returning its index.

set(fuzzer: Fuzzer<a>) -> Fuzzer<List<a>>

Generate a random list of unique elements (a.k.a. a set) from a given fuzzer. The list contains at most 20 elements, and has a higher probability of generating smaller lists.

Important: The specified fuzzer must have a high enough entropy to yield enough unique values to fill the set with the required size!

For sets of a specific length, use set_between.

set_between(fuzzer: Fuzzer<a>, min: Int, max: Int) -> Fuzzer<List<a>>

Generate a random list of unique elements (a.k.a a set) with length within specified bounds. The resulting set contains at least min elements and at most max elements, with a higher probability of generating smaller sets.

More specifically, there’s approximately 1/n chance of generating n elements within the range. For example, the distribution when generating a set between 0 and 10 elements resemble the following:

Important: The specified fuzzer must have a high enough entropy to yield enough unique values to fill the set with the required size!

22.7%   0 elements  ████████
19.7%   1 element   ███████
13.5%   2 elements  █████
 9.5%   3 elements  ███
 6.3%   4 elements  ██
 5.6%   5 elements  ██
 5.6%   6 elements  ██
 4.0%   7 elements  █
 3.1%   8 elements  █
 2.0%   9 elements  █
 8.0%  10 elements  ███

set_at_least(fuzzer: Fuzzer<a>, min: Int) -> Fuzzer<List<a>>

Generate a random set of elements from a given fuzzer, with at least min elements.

set_at_most(fuzzer: Fuzzer<a>, max: Int) -> Fuzzer<List<a>>

Generate a random set of elements from a given fuzzer, with at most max elements.

set_with_elem(fuzzer: Fuzzer<a>) -> Fuzzer<(List<a>, a)>

Generate a random set and pick an element from that set. Return both.

Combining

and_then(fuzz_a: Fuzzer<a>, f: fn(a) -> Fuzzer<b>) -> Fuzzer<b>

Combine a Fuzzer with the result of a another one. This function works great with backpassing.

pub fn either(left: Fuzzer<a>, right: Fuzzer<a>) -> Fuzzer<a> {
  let pick_left <- fuzz.and_then(fuzz.bool())
  if pick_left {
    left
  } else {
    right
  }
}

both(left: Fuzzer<a>, right: Fuzzer<b>) -> Fuzzer<(a, b)>

Combine two fuzzers into a 2-tuple.

either(left: Fuzzer<a>, right: Fuzzer<a>) -> Fuzzer<a>

Choose either of two fuzzers with an equal probability.

either3(
  a: Fuzzer<result>,
  b: Fuzzer<result>,
  c: Fuzzer<result>,
) -> Fuzzer<result>

Choose either of three fuzzers with an equal probability.

either4(
  a: Fuzzer<result>,
  b: Fuzzer<result>,
  c: Fuzzer<result>,
  d: Fuzzer<result>,
) -> Fuzzer<result>

Choose either of four fuzzers with an equal probability.

either5(
  a: Fuzzer<result>,
  b: Fuzzer<result>,
  c: Fuzzer<result>,
  d: Fuzzer<result>,
  e: Fuzzer<result>,
) -> Fuzzer<result>

Choose either of five fuzzers with an equal probability.

either6(
  a: Fuzzer<result>,
  b: Fuzzer<result>,
  c: Fuzzer<result>,
  d: Fuzzer<result>,
  e: Fuzzer<result>,
  f: Fuzzer<result>,
) -> Fuzzer<result>

Choose either of six fuzzers with an equal probability.

either7(
  a: Fuzzer<result>,
  b: Fuzzer<result>,
  c: Fuzzer<result>,
  d: Fuzzer<result>,
  e: Fuzzer<result>,
  f: Fuzzer<result>,
  g: Fuzzer<result>,
) -> Fuzzer<result>

Choose either of seven fuzzers with an equal probability.

either8(
  a: Fuzzer<result>,
  b: Fuzzer<result>,
  c: Fuzzer<result>,
  d: Fuzzer<result>,
  e: Fuzzer<result>,
  f: Fuzzer<result>,
  g: Fuzzer<result>,
  h: Fuzzer<result>,
) -> Fuzzer<result>

Choose either of height fuzzers with an equal probability.

either9(
  a: Fuzzer<result>,
  b: Fuzzer<result>,
  c: Fuzzer<result>,
  d: Fuzzer<result>,
  e: Fuzzer<result>,
  f: Fuzzer<result>,
  g: Fuzzer<result>,
  h: Fuzzer<result>,
  i: Fuzzer<result>,
) -> Fuzzer<result>

Choose either of nine fuzzers with an equal probability.

map(fuzz_a: Fuzzer<a>, f: fn(a) -> b) -> Fuzzer<b>

Transform the result of a Fuzzer using a function. This function works great with backpassing.

fn bool() -> Fuzzer<Bool> {
  let n <- map(int_between(1, 100))
  n % 2
}

map2(
  fuzz_0: Fuzzer<t0>,
  fuzz_1: Fuzzer<t1>,
  f: fn(t0, t1) -> result,
) -> Fuzzer<result>

Combine the results of two Fuzzers.

map3(
  fuzz_0: Fuzzer<t0>,
  fuzz_1: Fuzzer<t1>,
  fuzz_2: Fuzzer<t2>,
  f: fn(t0, t1, t2) -> result,
) -> Fuzzer<result>

Combine the results of three Fuzzers.

map4(
  fuzz_0: Fuzzer<t0>,
  fuzz_1: Fuzzer<t1>,
  fuzz_2: Fuzzer<t2>,
  fuzz_3: Fuzzer<t3>,
  f: fn(t0, t1, t2, t3) -> result,
) -> Fuzzer<result>

Combine the results of four Fuzzers.

map5(
  fuzz_0: Fuzzer<t0>,
  fuzz_1: Fuzzer<t1>,
  fuzz_2: Fuzzer<t2>,
  fuzz_3: Fuzzer<t3>,
  fuzz_4: Fuzzer<t4>,
  f: fn(t0, t1, t2, t3, t4) -> result,
) -> Fuzzer<result>

Combine the results of five Fuzzers.

map6(
  fuzz_0: Fuzzer<t0>,
  fuzz_1: Fuzzer<t1>,
  fuzz_2: Fuzzer<t2>,
  fuzz_3: Fuzzer<t3>,
  fuzz_4: Fuzzer<t4>,
  fuzz_5: Fuzzer<t5>,
  f: fn(t0, t1, t2, t3, t4, t5) -> result,
) -> Fuzzer<result>

Combine the results of six Fuzzers.

map7(
  fuzz_0: Fuzzer<t0>,
  fuzz_1: Fuzzer<t1>,
  fuzz_2: Fuzzer<t2>,
  fuzz_3: Fuzzer<t3>,
  fuzz_4: Fuzzer<t4>,
  fuzz_5: Fuzzer<t5>,
  fuzz_6: Fuzzer<t6>,
  f: fn(t0, t1, t2, t3, t4, t5, t6) -> result,
) -> Fuzzer<result>

Combine the results of seven Fuzzers.

map8(
  fuzz_0: Fuzzer<t0>,
  fuzz_1: Fuzzer<t1>,
  fuzz_2: Fuzzer<t2>,
  fuzz_3: Fuzzer<t3>,
  fuzz_4: Fuzzer<t4>,
  fuzz_5: Fuzzer<t5>,
  fuzz_6: Fuzzer<t6>,
  fuzz_7: Fuzzer<t7>,
  f: fn(t0, t1, t2, t3, t4, t5, t6, t7) -> result,
) -> Fuzzer<result>

Combine the results of eight Fuzzers.

map9(
  fuzz_0: Fuzzer<t0>,
  fuzz_1: Fuzzer<t1>,
  fuzz_2: Fuzzer<t2>,
  fuzz_3: Fuzzer<t3>,
  fuzz_4: Fuzzer<t4>,
  fuzz_5: Fuzzer<t5>,
  fuzz_6: Fuzzer<t6>,
  fuzz_7: Fuzzer<t7>,
  fuzz_8: Fuzzer<t8>,
  f: fn(t0, t1, t2, t3, t4, t5, t6, t7, t8) -> result,
) -> Fuzzer<result>

Combine the results of nine Fuzzers.

one_of(xs: List<a>) -> Fuzzer<a>

Pick a value from a (non-empty!) list with equal probability.

let any_bool = fuzz.one_of([True, False])

option(fuzz_a: Fuzzer<a>) -> Fuzzer<Option<a>>

Choose between None or Some value with an equal probability.

sublist(xs: List<a>) -> Fuzzer<List<a>>

Take a random sublist from an existing list.

subset(xs: List<a>) -> Fuzzer<List<a>>

Take a random subset from an existing set.

such_that(fuzzer: Fuzzer<a>, predicate: fn(a) -> Bool) -> Fuzzer<a>

Generate a value that satisfies a given predicate. Beware that this function may heavily impact the performances of your fuzzers. In general, you should prefer constraining the fuzzers beforehand than trying to discard values after the fact!

Use with caution.

Inspecting

label(str: String) -> Void

Label a test case. Labels are collected at the end of a property run and a distribution amongst all labels is computed and shown. This is particularly useful to assert that specific scenarios are met or to test your fuzzers.

test prop_bool_distribution(is_true via bool()) {
  label(
    if is_true {
      @"True"
    } else {
      @"False"
    },
  )

  True
}

label_when(predicate: Bool, str: String, default: String) -> Void

Apply a label when a predicate is true, or fallback to a default label. Useful for labelling dichotomies while ensuring that the final label distribution reflects all cases.

test prop_u16(operands via fuzz.both(byte(), byte())) {
  let (msb, lsb) = operands
  fuzz.label_when(msb == 0, @"msb = 0", @"default")
  fuzz.label_when(lsb == 0, @"lsb = 0", @"default")
  builtin.bytearray_to_integer(
    False,
    ""
      |> builtin.cons_bytearray(msb, _)
      |> builtin.cons_bytearray(lsb, _),
  ) == msb * 256 + lsb
}

label_if(str: String, predicate: Bool) -> Void

Apply a label when a predicate is true, or do nothing. Useful for conditionally labelling scenarios in a single line.

test post_conditions(steps via any_scenario()) {
  let (is_register, is_reregister, is_unregister, is_forward) =
    classify_steps(steps)

  @"contains solo registration" |> label_if(is_register)
  @"contains re-registration" |> label_if(is_reregister)
  @"contains solo unregistration" |> label_if(is_unregister)
  @"contains forward-only" |> label_if(is_forward)
}
Search Document