package ppx_hegel_test
Install
dune-project
Dependency
Authors
Maintainers
Sources
md5=fb39892b688e9ca1ae8c2066ea9e3580
sha512=f3dcc0c8508a56773a2d6df33a3eb32733f19f2030b112b3a8fce504f020ff32c3d4d96e90b4d68af4e9dda1182182939c503139a661311c887cc08fc11284c0
doc/ppx_hegel_test/Ppx_hegel_test/index.html
Module Ppx_hegel_testSource
PPX expander for let%hegel_test ....
Rewrites:
let%hegel_test my_test tc = body
[@@settings expr]
[@@failure_blobs [ "<base64>"; ... ]]into:
let my_test () =
Hegel.run_hegel_test
~settings:expr
~test_location:{ function_name; file; begin_line }
~failure_blobs:[ "<base64>"; ... ]
(fun tc -> body)
;;
let () =
Hegel_test_runtime.register
~name:"my_test"
~file:"…"
~line:…
my_testThe generated function remains directly callable, but is also auto-registered with Hegel_test_runtime so that dune runtest (via the ppx_hegel_test inline-tests backend) discovers and runs it.
The @@settings ... and @@failure_blobs ... attributes are both optional.
extract_settings_attr attrs returns the expression carried by [@@settings expr] if present, else None.
parse_string_list e returns the list of literal strings carried by e when e has the shape [ "..."; "..."; ... ], else raises a located error pointing at the offending sub-expression.
extract_failure_blobs_attr attrs returns the parsed string list if a [@@failure_blobs ...] attribute is present, else None.
extract_function_name pat returns the name bound by pat if pat is a simple variable, else raises.
build_location_record ~loc ~function_name returns an expression of type Hegel.test_location populated from the binding's source location.
val build_items :
loc:Ppxlib.location ->
function_name:string ->
settings_expr:Ppxlib_ast.Ast.expression option ->
failure_blobs:string list option ->
body_fn:Ppxlib_ast.Ast.expression ->
Ppxlib.structure_item listbuild_items ~loc ~function_name ~settings_expr ~body_fn returns the pair of structure items the expander splices in:
let function_name () =
Hegel.run_hegel_test [?settings] location body_fn
;;
let () =
Hegel_test_runtime.register ~name:.. ~file:.. ~line:.. function_nameis_draw_lident lid is true when lid's final component is draw, whether unqualified (draw) or qualified (Hegel.draw, Generators.draw, a module alias G.draw, …). Precision comes from the receiver check in draw_binding_name (the draw must be applied to the test's own tc), so this only needs to recognize the name; draw_silent is a different name and is excluded.
draw_named_lident lid is lid with its final draw component replaced by draw_named, preserving the module prefix the user wrote, so the rewrite targets the same module's internal entry point (e.g. Hegel.draw becomes Hegel.draw_named).
has_label_arg args is true when an application already passes ~label (or ?label) explicitly, in which case the hand-written label wins.
param_name pat is the variable bound by pat, if it is a simple variable (possibly type-annotated), else None.
test_case_name e is the name of the test function's first parameter (its tc), used as the receiver the rewrite keys off. None when the binding is not a function or its parameter is not a simple variable.
tc_arg_is ~tc_name args is true when the first positional argument of an application is exactly the identifier tc_name.
draw_binding_name ~tc_name vb returns Some name when vb is let <name> = draw tc … — a simple-variable binding whose right-hand side is a draw application on the test's own tc — and None otherwise.
collect_repeatable body maps each draw-bound name to whether its draws should be numbered. A name is repeatable if it is drawn more than once, or drawn anywhere at block depth > 0 (inside a function, for, or while body, where it may run repeatedly).
val inject_draw :
tc_name:String.t ->
(string, bool) Hashtbl.t ->
Ppxlib.value_binding ->
Ppxlib.value_bindinginject_draw ~tc_name flags vb rewrites let x = M.draw tc gen into let x = M.draw_named ~label:"x" ~repeatable:b tc gen, so the drawn value prints as x = value (numbered when x is flagged repeatable in flags — reused name or drawn in a loop). It targets the internal draw_named rather than the public draw (so repeatable stays off the public API), keeping the module prefix M the user wrote. It fires only for a simple-variable binding whose right-hand side is a draw application on tc with no explicit ~label; every other binding is unchanged.
A traversal that applies inject_draw to every let-binding in an expression, threading the precomputed flags, so labels are injected throughout the test body (nested lets, helper functions, match arms, …). Draws nested inside a generation span are still suppressed at runtime by the depth gate, so labeling them is harmless.
val expand_value_binding :
loc:Ppxlib.location ->
Ppxlib.value_binding ->
Ppxlib.structure_item listExpander for a single let%hegel_test ... structure item.
The hegel_test extension is attached to structure_item (top-level let%hegel_test). It supports only the non-recursive single-binding form. The expander splices in two top-level items: the test function itself and a Hegel_test_runtime.register side effect so that dune runtest (via the ppx_hegel_test inline-tests backend) discovers and runs the test.