OCaml Dune Cram Example
I have Dune version 3.21.0. I want to create a simple OCaml executable and test it with dune’s built in cram tests.
I write in bin/main.ml (see the full source code for this example on GitHub):
let () = print_endline "Hello world!"
and in bin/dune:
(executable
(public_name hello_world_public)
(name hello_world))
and run dune build in the project root:
$ dune build
$ tree _build/install/
_build/install/
└── default
├── bin
│ └── hello_world_public -> ../../../default/bin/hello_world.exe
...
Now, to test it I put in test/cram.t:
$ hello_world_public
Note the leading whitespace, which is significant in cram tests. It serves to distinguish commands to be executed from comments and expected output.
The test works as expected:
$ dune runtest
File "test/test.t", line 1, characters 0-0:
diff --git 1/_build/default/test/test.t 2/_build/default/test/test.t.corrected
index 7d73fcf..446aa8d 100644
--- 1/_build/default/test/test.t
+++ 2/_build/default/test/test.t.corrected
@@ -1,2 +1,3 @@
$ hello_world_public
+ Hello world!
However, I now change public name from hello_world_public to
hello_world_public_oups. Now, dune runtest runs with the same
result – I expected that it would fail at this point, since the
public name of the binary changed. If I change hello_world.ml to
output something else than Hello world! then dune runtest will not
rebuild the binary. So the test still runs successfully, which is
unexpected!
Cram tests run in an isolated environment and do not automatically
depend on executables defined elsewhere in the project. Unless
explicitly declared, Dune will not rebuild or track those binaries
when running dune runtest. The above works because dune makes all
public binaries available in the $PATH of cram tests – not because
dune knows that the test uses hello_world_public.
A simple solution is to create a dune file in same directory as the cram test (here, test/dune), and add the following stanza:
(cram (deps %{bin:hello_world_public}))
This makes the test’s dependency on the public binary explicit, and
running dune runtest will ensure that the binary is rebuilt. If
the binary’s public name changes, the build will fail, as is expected.
The full source code of this example is available on GitHub.