package alcobar

  1. Overview
  2. Docs
Write tests, let a fuzzer find failing cases

Install

dune-project
 Dependency

Authors

Maintainers

Sources

alcobar-0.3.tbz
sha256=de27258a56db63f690a3bb8edbc8215ce85acfdac8ab1be44f172d2314f0177c
sha512=9ee5749483379cabececa99d53a54f1d3987d80490ad81266c9eb5d133f8d8b4bf6a59db79363b7bd5a5d0aa77345e628530c8b57e0482739eeda63ee0b1d4e6

Description

Alcobar is Crowbar with an Alcotest-compatible API. It is a library for testing code, combining QuickCheck-style property-based testing and the magical bug-finding powers of afl-fuzz.

Published: 31 Mar 2026

README

Alcobar

Alcobar is Crowbar with an Alcotest-compatible API.

It is a library for testing code, combining QuickCheck-style property-based testing and the magical bug-finding powers of afl-fuzz.

Writing tests

Tests are organized into suites using an Alcotest-style API. Each test case takes a list of generators and a property to check:

open Alcobar

let test_roundtrip input =
  let encoded = My_module.encode input in
  let decoded = My_module.decode encoded in
  check_eq ~pp:pp_string input decoded

let test_no_crash input n =
  ignore (My_module.parse input n)

let suite =
  ("my_module",
   [
     test_case "roundtrip" [bytes] test_roundtrip;
     test_case "no crash" [bytes; int] test_no_crash;
   ])

let () = run "my_project" [ suite ]

See the examples directory for more.

Project setup

dune-workspace

Create a dune-workspace at the root of your project with two build contexts: default (normal compilation) and afl (AFL-instrumented). The afl context uses the profile afl, which enables the -afl-instrument flag for the native compiler. This is what makes (enabled_if (= %{profile} afl)) work in dune rules -- the fuzz rule only activates when building under the afl context, while dune test uses the default context and runs quick property-based tests.

(lang dune 3.0)

(context default)

(context
 (default
  (name afl)
  (profile afl)))

(env
 (afl
  (ocamlopt_flags (:standard -afl-instrument))))

Building with dune build --context=afl compiles everything with AFL instrumentation. Building without --context (or with dune test) uses the default context with no instrumentation.

Fuzz directory layout

my_package/fuzz/
  dune
  fuzz.ml           -- entry point
  fuzz_foo.ml       -- test suite for module Foo
  fuzz_foo.mli      -- exports: val suite : string * Alcobar.test_case list
  corpus/           -- seed input files (auto-generated)

dune

(executable
 (name fuzz)
 (modules fuzz fuzz_foo)
 (libraries my_package alcobar))

(rule
 (alias runtest)
 (enabled_if (<> %{profile} afl))
 (deps fuzz.exe)
 (action
  (run %{exe:fuzz.exe})))

(rule
 (alias fuzz)
 (enabled_if (= %{profile} afl))
 (deps fuzz.exe)
 (action
  (progn
   (run %{exe:fuzz.exe} --gen-corpus corpus)
   (run afl-fuzz -V 60 -i corpus -o _fuzz -- %{exe:fuzz.exe} @@))))

fuzz.ml

let () = Alcobar.run "my_project" [ Fuzz_foo.suite ]

fuzz_foo.mli

val suite : string * Alcobar.test_case list

Running tests

Without AFL (quick property-based testing):

dune test

Generate seed corpus (uses the test generators to produce valid inputs):

./fuzz.exe --gen-corpus corpus/

With AFL instrumentation:

dune build --context=afl @fuzz

Dependencies (5)

  1. afl-persistent >= "1.1"
  2. cmdliner >= "1.1.0"
  3. alcotest
  4. ocaml >= "4.10.0"
  5. dune >= "3.21"

Dev Dependencies (7)

  1. odoc with-doc
  2. uutf with-test
  3. uunf with-test
  4. uucp with-test
  5. pprint with-test
  6. fpath with-test
  7. calendar >= "2.00" & with-test

Used by

None

Conflicts

None