### Alcobar Entry Point Source: https://github.com/samoht/alcobar/blob/main/README.md Set the entry point for the Alcobar application, specifying the project name and the test suites to run. This file should be named fuzz.ml. ```ocaml let () = Alcobar.run "my_project" [ Fuzz_foo.suite ] ``` -------------------------------- ### Dune Workspace Configuration for AFL Source: https://github.com/samoht/alcobar/blob/main/README.md Set up multiple build contexts in dune-workspace, including a default and an 'afl' context for AFL-instrumented builds. The 'afl' profile enables the -afl-instrument flag. ```dune (lang dune 3.0) (context default) (context (default (name afl) (profile afl))) (env (afl (ocamlopt_flags (:standard -afl-instrument)))) ``` -------------------------------- ### Organize Tests into Suites with Alcobar Source: https://context7.com/samoht/alcobar/llms.txt Define individual test cases and group them into suites using the Alcotest-compatible API. Run all defined suites with the `run` function. ```ocaml open Alcobar (* Define individual test cases *) let test_addition a b = check_eq (a + b) (b + a) (* Commutativity *) let test_multiplication a b = check_eq (a * b) (b * a) (* Commutativity *) let test_distributive a b c = check_eq (a * (b + c)) (a * b + a * c) (* Group test cases into a suite *) let arithmetic_suite = ("arithmetic", [ test_case "addition_commutative" [int; int] test_addition; test_case "multiplication_commutative" [int; int] test_multiplication; test_case "distributive" [int8; int8; int8] test_distributive; ]) (* Another suite *) let string_suite = ("string", [ test_case "concat_length" [bytes; bytes] (fun s1 s2 -> check_eq (String.length s1 + String.length s2) (String.length (s1 ^ s2))); test_case "reverse_length" [bytes] (fun s -> check_eq (String.length s) (String.length (String.to_seq s |> List.of_seq |> List.rev |> List.to_seq |> String.of_seq))); ]) (* Run all suites *) let () = run "my_project" [arithmetic_suite; string_suite] ``` -------------------------------- ### Attaching Pretty Printers with `with_printer` Source: https://context7.com/samoht/alcobar/llms.txt Enhance test failure messages by attaching a custom pretty-printer to a generator using `with_printer`. This function takes a printer function and a generator, returning a new generator with the attached printer. ```ocaml open Alcobar type point = { x: int; y: int } let pp_point ppf p = pp ppf "{ x = %d; y = %d }" p.x p.y let point_gen : point gen = with_printer pp_point @@ map [int; int] (fun x y -> { x; y }) (* When a test fails, the printer shows readable output *) let test_origin_distance p = let dist = sqrt (float_of_int (p.x * p.x + p.y * p.y)) in check (dist >= 0.0) (* Always true, just for demonstration *) let suite = ("point", [test_case "distance" [point_gen] test_origin_distance]) ``` -------------------------------- ### Dune Executable and Rule Configuration Source: https://github.com/samoht/alcobar/blob/main/README.md Configure the main fuzz executable and define rules for running tests and fuzzing. The 'runtest' alias runs quick property-based tests, while the 'fuzz' alias activates AFL instrumentation. ```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} @@)))) ``` -------------------------------- ### Project Configuration for AFL Fuzzing Source: https://context7.com/samoht/alcobar/llms.txt Configure your OCaml project using Dune to support both property-based testing and AFL fuzzing. This includes setting up build contexts and rules for fuzzing. ```ocaml (* dune-project *) (* (lang dune 3.0) (name my_project) *) (* dune-workspace *) (* (lang dune 3.0) (context default) (context (default (name afl) (profile afl))) (env (afl (ocamlopt_flags (:standard -afl-instrument)))) *) (* fuzz/dune *) (* (executable (name fuzz) (modules fuzz fuzz_mymodule) (libraries my_project 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/fuzz.ml *) let () = Alcobar.run "my_project" [ Fuzz_mymodule.suite; ] (* Run property tests: dune test *) (* Generate corpus: ./fuzz.exe --gen-corpus corpus/ *) (* Run AFL fuzzing: dune build --context=afl @fuzz *) ``` -------------------------------- ### Test Map Implementation with Generators Source: https://context7.com/samoht/alcobar/llms.txt Demonstrates recursive generators, custom types, and property testing for a Map data structure. Ensures map consistency by comparing bindings to a deduplicated list representation. ```ocaml open Alcobar module IntMap = Map.Make(Int) type map_state = (int * int) list * int IntMap.t (* Generator for map states: maintains a list shadow of the map *) let map_gen : map_state gen = fix (fun map_gen -> choose [ (* Empty map *) const ([], IntMap.empty); (* Add an element *) map [uint8; uint8; map_gen] (fun k v (lst, m) -> ((k, v) :: lst, IntMap.add k v m)); (* Singleton map *) map [uint8; uint8] (fun k v -> ([(k, v)], IntMap.singleton k v)); (* Remove an element *) map [uint8; map_gen] (fun k (lst, m) -> let rec remove_all k = function | [] -> [] | (k', _) :: rest when k' = k -> remove_all k rest | x :: rest -> x :: remove_all k rest in (remove_all k lst, IntMap.remove k m)); (* Merge two maps *) map [map_gen; map_gen] (fun (l1, m1) (l2, m2) -> (l1 @ l2, IntMap.union (fun _ a _ -> Some a) m1 m2)); ]) (* Deduplicate list keeping last occurrence *) let dedup_list lst = let sorted = List.stable_sort (fun (k1, _) (k2, _) -> compare k1 k2) lst in let rec dedup prev = function | [] -> [] | (k, v) :: rest when k = prev -> dedup k rest | (k, v) :: rest -> (k, v) :: dedup k rest in match sorted with | [] -> [] | (k, v) :: rest -> (k, v) :: dedup k rest (* Property: map bindings match deduplicated list *) let test_map_consistency (lst, m) = let expected = dedup_list lst in let actual = IntMap.bindings m in check_eq expected actual let suite = ("intmap", [test_case "consistency" [map_gen] test_map_consistency]) let () = run "map_tests" [suite] ``` -------------------------------- ### Equality Check with `check_eq` Source: https://context7.com/samoht/alcobar/llms.txt Verify equality between two values using `check_eq`. It supports custom pretty-printers (`pp`) and custom equality functions (`eq`). This is useful for comparing complex data structures or floating-point numbers with tolerance. ```ocaml open Alcobar (* Equality check with optional printer and comparator *) let test_roundtrip s = let encoded = Base64.encode s in let decoded = Base64.decode encoded in check_eq ~pp:pp_string s decoded ``` ```ocaml (* With custom equality function *) let test_float_approx x = guard (Float.is_finite x); let y = sin x *. sin x +. cos x *. cos x in check_eq ~eq:(fun a b -> Float.abs (a -. b) < 1e-10) 1.0 y ``` ```ocaml (* With custom comparator *) type person = { name: string; age: int } let compare_by_age p1 p2 = compare p1.age p2.age let test_sort_stable people = let sorted = List.stable_sort compare_by_age people in check_eq ~cmp:(List.compare compare_by_age) sorted (List.stable_sort compare_by_age sorted) ``` -------------------------------- ### Generate Optional and Result Values with Alcobar Source: https://context7.com/samoht/alcobar/llms.txt Use `option` to generate `None` or `Some` values and `result` for `Ok` or `Error` types. Import necessary types and functions. ```ocaml open Alcobar (* Generate optional integers *) let opt_int : int option gen = option int (* Generate result with int success and string error *) let result_gen : (int, string) result gen = result int bytes (* Test Option.map identity *) let test_option_map_id opt = check_eq opt (Option.map Fun.id opt) (* Test Result.map identity *) let test_result_map_id res = check_eq res (Result.map Fun.id res) let suite = ("options", [ test_case "option_map_id" [option int] test_option_map_id; test_case "result_map_id" [result int bytes] test_result_map_id; ]) ``` -------------------------------- ### Define Alcobar Test Suite Source: https://github.com/samoht/alcobar/blob/main/README.md Organize tests into suites using an Alcotest-style API. Each test case takes a list of generators and a property to check. Requires importing Alcobar. ```ocaml 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 ] ``` -------------------------------- ### Monadic Let Operators for Generator Composition Source: https://context7.com/samoht/alcobar/llms.txt Use `let+` for applicative-style mapping and `let*` for monadic-style dynamic binding to compose generators cleanly. These operators simplify the creation of complex data structures from basic generators. ```ocaml open Alcobar open Alcobar.Syntax (* let+ for map (applicative style) *) let point_gen : (int * int) gen = let+ x = int and+ y = int in (x, y) (* Equivalent to: map [int; int] (fun x y -> (x, y)) *) ``` ```ocaml (* let* for dynamic_bind (monadic style) *) let sized_list_gen : int list gen = let* len = range 10 in let rec make n acc = if n <= 0 then const (List.rev acc) else let* x = int in make (n - 1) (x :: acc) in make len [] ``` ```ocaml (* Complex generator combining and+ and let+ *) type rect = { x: int; y: int; width: int; height: int } let rect_gen : rect gen = let+ x = int and+ y = int and+ width = range ~min:1 100 and+ height = range ~min:1 100 in { x; y; width; height } ``` -------------------------------- ### List Generators Source: https://context7.com/samoht/alcobar/llms.txt Utilities for generating lists of arbitrary or non-empty length. ```APIDOC ## List Generators ### list Generates lists of arbitrary length from an element generator. ### list1 Generates non-empty lists (at least one element) from an element generator. ``` -------------------------------- ### OCaml list and list1 - List Generators Source: https://context7.com/samoht/alcobar/llms.txt Generates lists of arbitrary or non-empty length from an element generator. 'list' generates possibly empty lists, while 'list1' guarantees at least one element. ```ocaml open Alcobar (* Generate possibly empty lists *) let int_list_gen : int list gen = list int (* Generate non-empty lists (at least one element) *) let nonempty_ints : int list gen = list1 int (* Test that reverse is its own inverse *) let test_reverse_involution xs = check_eq ~pp:(pp_list pp_int) xs (List.rev (List.rev xs)) let suite = ("list", [ test_case "reverse_involution" [list int] test_reverse_involution ]) ``` -------------------------------- ### Generate Arrays with Alcobar Source: https://context7.com/samoht/alcobar/llms.txt Use `array` to generate possibly empty arrays and `array1` for non-empty arrays from an element generator. Ensure generators are imported. ```ocaml open Alcobar (* Generate possibly empty arrays *) let int_array_gen : int array gen = array int (* Generate non-empty arrays *) let nonempty_array : int array gen = array1 int (* Test that sorting is idempotent *) let test_sort_idempotent arr = Array.sort compare arr; let once = Array.copy arr in Array.sort compare arr; check_eq arr once let suite = ("array", [ test_case "sort_idempotent" [array int] test_sort_idempotent ]) ``` -------------------------------- ### Simple Boolean Check with `check` Source: https://context7.com/samoht/alcobar/llms.txt Use `check` to assert a boolean condition within a test. If the condition is false, the test fails. `guard` can be used to skip tests if preconditions are not met. ```ocaml open Alcobar (* Simple boolean check *) let test_positive n = guard (n > 0); (* Skip test if precondition fails *) check (n * n > 0) (* Squares of positive ints are positive *) ``` -------------------------------- ### Formatted Test Failures with `failf` Source: https://context7.com/samoht/alcobar/llms.txt Use `failf` to report explicit test failures with formatted messages, similar to `Printf.sprintf`. This allows for detailed error reporting including variable values. ```ocaml open Alcobar (* failf: formatted failure message *) let test_invariant x y = let result = compute x y in if result < 0 then failf "Expected non-negative result, got %d for inputs x=%d, y=%d" result x y else check (result >= 0) ``` ```ocaml (* Using failf with complex values *) let test_lookup key map = match Map.find_opt key map with | None -> failf "Key %S not found in map" key | Some value -> if String.length value = 0 then failf "Empty value for key %S" key else check (String.length value > 0) ``` -------------------------------- ### OCaml choose - Selecting Between Generators Source: https://context7.com/samoht/alcobar/llms.txt Randomly selects one generator from a list to produce a value. Essential for generating values of sum types or creating varied test inputs, including recursive structures. ```ocaml open Alcobar (* Choose between different generators *) type expr = | Lit of int | Var of string | Add of expr * expr let var_names = ["x"; "y"; "z"; "n"; "m"] let expr_gen : expr gen = fix (fun expr_gen -> choose [ (* Generate a literal integer *) map [int8] (fun n -> Lit n); (* Generate a variable reference *) map [range (List.length var_names)] (fun i -> Var (List.nth var_names i)); (* Generate an addition of two sub-expressions *) map [expr_gen; expr_gen] (fun e1 e2 -> Add (e1, e2)); ]) (* Test with the generator *) let test_expr e = (* Property: expression evaluation doesn't crash *) ignore (e) let suite = ("expr", [test_case "expr_gen" [expr_gen] test_expr]) ``` -------------------------------- ### Generate Random Permutations with Alcobar Source: https://context7.com/samoht/alcobar/llms.txt Use the `shuffle` generator to create random permutations of a given list. The generated list will contain the same elements as the original list, but in a random order. ```ocaml open Alcobar (* Generate shuffled deck of cards *) let deck = [1; 2; 3; 4; 5; 6; 7; 8; 9; 10; 11; 12; 13] let shuffled_deck : int list gen = shuffle deck (* Test that shuffle preserves all elements *) let test_shuffle_preserves_elements shuffled = let sorted_original = List.sort compare deck in let sorted_shuffled = List.sort compare shuffled in check_eq sorted_original sorted_shuffled let suite = ("shuffle", [ test_case "preserves_elements" [shuffle deck] test_shuffle_preserves_elements ]) ``` -------------------------------- ### Unwrapping Options with `nonetheless` Source: https://context7.com/samoht/alcobar/llms.txt Use `nonetheless` to safely unwrap an option type. If the option is `None`, the test is aborted. This is useful for handling operations that might fail but should not be skipped. ```ocaml open Alcobar (* nonetheless: unwrap option or abort if None *) let test_find_element xs = guard (xs <> []); let first = nonetheless (List.nth_opt xs 0) in check (List.mem first xs) ``` -------------------------------- ### Explicit Test Failures with `fail` Source: https://context7.com/samoht/alcobar/llms.txt Use `fail` to explicitly abort a test with a simple string message. This is useful when a specific condition is not met and a clear failure indication is required. ```ocaml open Alcobar (* fail: simple failure with message *) let test_serialize data = let serialized = serialize data in match deserialize serialized with | None -> fail "deserialization returned None" | Some data' -> check_eq data data' ``` -------------------------------- ### Dependent Generation with Alcobar Source: https://context7.com/samoht/alcobar/llms.txt Use `dynamic_bind` to create a generator whose behavior depends on a previously generated value. This is useful for generating values of types determined at runtime, but should be used sparingly. ```ocaml open Alcobar (* Generate a type representation and a value of that type *) type _ ty = TInt : int ty | TBool : bool ty type any_value = AnyVal : 'a ty * 'a -> any_value let ty_gen : any_value gen = dynamic_bind (choose [const (AnyVal (TInt, 0)); const (AnyVal (TBool, false))]) (function | AnyVal (TInt, _) -> map [int] (fun n -> AnyVal (TInt, n)) | AnyVal (TBool, _) -> map [bool] (fun b -> AnyVal (TBool, b))) (* Generate a list of exactly n elements *) let list_of_length (n_gen : int gen) (elem_gen : 'a gen) : 'a list gen = dynamic_bind n_gen (fun n -> let rec go acc = function | 0 -> const (List.rev acc) | k -> dynamic_bind elem_gen (fun x -> go (x :: acc) (k - 1)) in go [] (abs n mod 10)) ``` -------------------------------- ### Generator Combinators Source: https://context7.com/samoht/alcobar/llms.txt Functions for transforming and combining generators, including map, choose, and const. ```APIDOC ## Generator Combinators ### map Transforms generator outputs by applying a function to generated values. Supports combining multiple generators using list syntax. ### choose Randomly selects one generator from a list to produce a value. Essential for sum types. ### const Creates a generator that always produces the same value, useful for base cases in recursive generators. ``` -------------------------------- ### OCaml Primitive Generators Source: https://context7.com/samoht/alcobar/llms.txt Provides built-in generators for various OCaml primitive types. Use 'bytes_fixed' for fixed-length byte strings and 'range' for integers within a specific range. ```ocaml open Alcobar (* Integer generators with various bit widths *) let _ = int (* Full-range signed integer *) let _ = uint8 (* 0 to 255 *) let _ = int8 (* -128 to 127 *) let _ = uint16 (* 0 to 65535 *) let _ = int16 (* -32768 to 32767 *) let _ = int32 (* 32-bit signed integer *) let _ = int64 (* 64-bit signed integer *) (* Other primitive generators *) let _ = float (* Double-precision floating-point *) let _ = bool (* true or false *) let _ = char (* Single character *) let _ = uchar (* Unicode scalar value *) let _ = bytes (* Arbitrary-length string *) (* Fixed-length byte string *) let fixed_bytes_gen : string gen = bytes_fixed 16 (* Generate integers within a specific range *) let dice_roll : int gen = range 6 ~min:1 (* 1 to 6 inclusive *) let index : int gen = range 100 (* 0 to 99 inclusive *) ``` -------------------------------- ### Skipping Tests with `guard` Source: https://context7.com/samoht/alcobar/llms.txt Use `guard` to conditionally skip a test if a given boolean expression evaluates to false. This is useful for avoiding tests with invalid inputs, such as division by zero. ```ocaml open Alcobar (* guard: skip test if precondition is false *) let test_division a b = guard (b <> 0); (* Skip division by zero *) let q = a / b in let r = a mod b in check_eq a (q * b + r) ``` -------------------------------- ### Generate Tuples with Alcobar Source: https://context7.com/samoht/alcobar/llms.txt Use the `pair` generator to create tuples from two other generators. Nested pairs can be created by composing `pair` generators. ```ocaml open Alcobar (* Generate coordinate pairs *) let coord_gen : (int * int) gen = pair int int (* Generate nested pairs *) let triple_gen : ((int * int) * int) gen = pair (pair int int) int (* Test that pair swap is its own inverse *) let swap (a, b) = (b, a) let test_swap_involution p = check_eq p (swap (swap p)) let suite = ("pair", [ test_case "swap_involution" [pair int int] test_swap_involution ]) ``` -------------------------------- ### Primitive Generators Source: https://context7.com/samoht/alcobar/llms.txt Built-in generators for primitive types such as integers, floats, booleans, and strings. ```APIDOC ## Primitive Generators ### Description Alcobar provides built-in generators for common data types including integers, floats, booleans, characters, and strings. ### Generators - **int** - Full-range signed integer - **uint8** - 0 to 255 - **int8** - -128 to 127 - **uint16** - 0 to 65535 - **int16** - -32768 to 32767 - **int32** - 32-bit signed integer - **int64** - 64-bit signed integer - **float** - Double-precision floating-point - **bool** - true or false - **char** - Single character - **uchar** - Unicode scalar value - **bytes** - Arbitrary-length string - **bytes_fixed(n)** - Fixed-length byte string - **range(max, ~min)** - Integers within a specific range ``` -------------------------------- ### OCaml map - Combining Generators Source: https://context7.com/samoht/alcobar/llms.txt Transforms generator outputs by applying a function. It can combine multiple generators using a list syntax to create complex data structures like tuples, records, and sum types. ```ocaml open Alcobar (* Create a character from a uint8 *) let char_gen : char gen = map [uint8] Char.chr (* Generate a tuple from two generators *) let point_gen : (int * int) gen = map [int; int] (fun x y -> (x, y)) (* Generate a record type *) type person = { name: string; age: int } let person_gen : person gen = map [bytes; range 100] (fun name age -> { name; age }) (* Generate a sum type *) type shape = | Circle of float | Rectangle of float * float let shape_gen : shape gen = choose [ map [float] (fun r -> Circle r); map [float; float] (fun w h -> Rectangle (w, h)); ] ``` -------------------------------- ### Define Recursive Generators with Alcobar Source: https://context7.com/samoht/alcobar/llms.txt Use `fix` or `unlazy` to define generators for recursive data types, handling circular dependencies. `fix` takes a function that returns the generator, while `unlazy` uses OCaml's lazy evaluation. ```ocaml open Alcobar (* Using fix for recursive generators *) type json = | Null | Bool of bool | Int of int | Array of json list | Object of (string * json) list let json_gen : json gen = fix (fun json_gen -> choose [ const Null; map [bool] (fun b -> Bool b); map [int] (fun n -> Int n); map [list json_gen] (fun arr -> Array arr); map [list (pair bytes json_gen)] (fun obj -> Object obj); ]) (* Alternative using unlazy *) type 'a tree = Leaf of 'a | Branch of 'a tree * 'a tree let rec tree_gen = lazy ( choose [ map [int] (fun x -> Leaf x); map [unlazy tree_gen; unlazy tree_gen] (fun l r -> Branch (l, r)); ]) let tree_gen = Lazy.force tree_gen ``` -------------------------------- ### OCaml const - Constant Generator Source: https://context7.com/samoht/alcobar/llms.txt Creates a generator that always produces the same value. Useful for base cases in recursive generators or fixed values in choices. ```ocaml open Alcobar (* Always generate the same value *) let zero_gen : int gen = const 0 let empty_list : string list gen = const [] (* Use in recursive generator base cases *) type tree = Leaf | Node of int * tree * tree let tree_gen : tree gen = fix (fun tree_gen -> choose [ const Leaf; (* Base case: always returns Leaf *) map [int; tree_gen; tree_gen] (fun v l r -> Node (v, l, r)); ]) ``` -------------------------------- ### Explicitly Aborting Tests with `bad_test` Source: https://context7.com/samoht/alcobar/llms.txt Use `bad_test` to explicitly mark a test as invalid and abort its execution. This is useful when encountering unrecoverable errors or invalid states, such as unparseable input. ```ocaml open Alcobar (* bad_test: explicitly abort a test as invalid *) let test_parse s = let parsed = try Some (int_of_string s) with Failure _ -> bad_test () (* Skip unparseable inputs *) in check (Option.get parsed >= min_int) ``` ```ocaml (* Combined example: testing a parser *) let test_json_roundtrip s = let json = try Yojson.Safe.from_string s with _ -> bad_test () (* Invalid JSON, skip *) in let s' = Yojson.Safe.to_string json in let json' = nonetheless (Yojson.Safe.from_string_opt s') in check_eq json json' ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.