OCaml fuzz testing with Crowbar for protocol implementations. Use when Claude needs to: (1) Write fuzz tests for parsers and encoders, (2) Test roundtrip invariants (parse(encode(x)) = x), (3) Verify boundary conditions and error handling, (4) Test state machines and transitions, (5) Organize fuzz test suites for large codebases
View on GitHubavsm/ocaml-claude-marketplace
ocaml-dev
January 20, 2026
Select agents to install to:
npx add-skill https://github.com/avsm/ocaml-claude-marketplace/blob/main/plugins/ocaml-dev/skills/fuzz/SKILL.md -a claude-code --skill fuzzInstallation paths:
.claude/skills/fuzz/# OCaml Fuzz Testing with Crowbar
## Core Philosophy
1. **One fuzz file per module**: `fuzz_foo.ml` tests `lib/foo.ml`. Keeps tests organized and discoverable.
2. **Roundtrip everything**: If you have `encode` and `decode`, test `decode(encode(x)) = x`.
3. **Crash-safety first**: Parsers must never crash on arbitrary input, even malformed data.
4. **Boundary conditions matter**: Test edge cases (0, max values, empty input, overflow).
5. **State machines need transition coverage**: Test all valid and invalid state transitions.
## Build Configuration
### Dune setup for fuzz tests
```lisp
(executable
(name fuzz)
(libraries crowbar borealis)
(modules
fuzz
fuzz_common
fuzz_foo
fuzz_bar))
```
### Main entry point (`fuzz/fuzz.ml`)
```ocaml
(* Force linking of modules that register tests via side effects *)
let () =
Fuzz_common.run ();
Fuzz_foo.run ();
Fuzz_bar.run ()
```
Each fuzz module ends with:
```ocaml
let run () = ()
```
This ensures the module is linked and its `add_test` calls execute.
---
## Test Patterns
### 1. Crash-safety test (parsers must not crash)
```ocaml
open Crowbar
open Fuzz_common
let () =
add_test ~name:"foo: decode" [ bytes ] @@ fun buf ->
(match Foo.decode (to_bytes buf) with
| Ok _ -> ()
| Error _ -> ());
check true
```
**Key points**:
- Use `bytes` generator for arbitrary binary input
- Match both `Ok` and `Error` branches (don't crash on either)
- `check true` signals test passed
### 2. Roundtrip test (encode/decode pairs)
```ocaml
let () =
add_test ~name:"foo: roundtrip" [ bytes ] @@ fun buf ->
match Foo.decode (to_bytes buf) with
| Error _ -> check true (* Invalid input is fine *)
| Ok original ->
let encoded = Foo.encode original in
match Foo.decode encoded with
| Error _ -> fail "re-decode failed"
| Ok decoded ->
if original <> decoded then fail "roundtrip mismatch"
else check true
```
**Key points**:
- If initial decode fails, that's OK (inpu