Bisect_ppx advanced usage
November 27, 2021 · View on GitHub
Table of contents
Exhaustiveness checking
It is easy to accidentally fail to preprocess part of your project, by leaving
out (preprocess (pps bisect_ppx)) in one of its subdirectories. If this
happens, and goes unnoticed, you may see misleading coverage statistics, because
Bisect_ppx will simply not be aware of the missing files at all. It will not
report them as either covered or not covered — they will just not be
present in the report.
To sanity-check this, you can pass the --expect option to bisect-ppx-report.
For example,
bisect-ppx-report html --expect src/
bisect-ppx-report will then recursively scan src/ for any .ml and .re
files, and check that all of them were included in the report.
You may have a subdirectory of src/ that should not be included. You can
exclude it from the recursive scan with --do-not-expect:
bisect-ppx-report html --expect src/ --do-not-expect src/build_tool/
You can also specify individual files with --expect and --do-not-expect by
omitting the trailing path separator:
bisect-ppx-report html --expect src/ --do-not-expect src/build_tool.ml
Excluding generated files from coverage
Whole files can be excluded by placing [@@@coverage exclude_file] anywhere in
their top-level module.
If you have generated code that you cannot easily place an attribute into, nor
is it easy to avoid preprocessing it, you can pass the --exclusions option to
the Bisect_ppx preprocessor:
(instrumentation
(backend bisect_ppx --exclusions bisect.exclude)
(deps bisect.exclude))
This requires Dune 2.9 or later.
Note that the paths to bisect.exclude might be different between the
preprocess and preprocessor_deps stanzas, because pps bisect_ppx looks for
the file relative to the root directory of your project, while
preprocessor_deps looks in the same directory that the dune file is in.
Here is what the bisect.exclude file can look like:
(* OCaml-style comments are okay. *)
(* Exclude the file "foo.ml": *)
file "foo.ml"
(* Exclude all files whose names start with "test_": *)
file regexp "test_.*"
(* Exclude the top-level values "foo" and "bar" in "baz.ml": *)
file "baz.ml" [
name "foo"
name "bar"
]
(* Exclude all top-level values whose names begin with "dbg_" in all
files in "src/": *)
file regexp "src/.*" [ regexp "dbg_.*" ]
All regular expressions are in the syntax of the Str module.
Environment variables
A program instrumented by Bisect_ppx writes .coverage files, which contain the
numbers of times various points in the program's code were visited during
execution. Two environment variables are available to control the writing of
these files.
Naming the output files
By default, the counts files are called bisect0001.coverage,
bisect0002.coverage, etc. The prefix bisect can be changed by setting the
environment variable BISECT_FILE. In particular, you can set it to something
like _coverage/bisect to put the counts files in a different directory, in
this example _coverage/.
BISECT_FILE can also be used to control the prefix programmatically. For
example, the following code bases the prefix on the program name, and puts the
.coverage files into the system temporary directory:
let () =
let (//) = Filename.concat in
let tmpdir = Filename.get_temp_dir_name () in
Unix.putenv "BISECT_FILE"
(tmpdir // Printf.sprintf "bisect-%s-" Sys.executable_name)
Logging
If the instrumented program fails to write an .coverage file, it will log a
message. By default, these messages go to a file bisect.log. BISECT_SILENT
can be set to YES to turn off logging completely. Alternatively, it can be set
to another filename, or to ERR in order to log to STDERR.
SIGTERM handling
If BISECT_SIGTERM is set to yes, the Bisect runtime will install a SIGTERM
handler that will write .coverage files and exit. This is useful if you have a
large number of test programs, and they can be killed by another process.
Setting at compile time
If your testing environment doesn't allow you to easily specify these
environment variables at testing time, you can specify default values for them
at compile time by passing the --bisect-file, --bisect-silent, and/or
--bisect-sigterm options to the Bisect_ppx instrumenter:
(instrumentation
(backend bisect_ppx
--bisect-file /tmp/mycoverage
--bisect-silent /tmp/coverage.log
--bisect-sigterm))
If different values are specified in different dune files for code that is
then linked into one binary, one set of values is chosen arbitrarily.
Passing arguments to Bisect in this way requires Dune version 2.8.0 or higher.