This documents how to run the OCaml compiler test suite. To learn how to write tests using ocamltest, read OCAMLTEST.org.
The testsuite of the OCaml compiler consists of a series of programs that are compiled and executed. The output of their compilation and execution is compared to expected outputs.
Before the introduction of ocamltest, the tests were driven by a set of makefiles which were responsible for compiling and running the test programs, and verifying that the compilation and execution outputs were matching the expected ones.
In this set-up, the precise information about how exactly one test should be compiled was separated from the test itself. It was stored somewhere in the makefiles, interleaved with the recipes to actually compile and run the test. Thus, given one test, it was not easy to determine exactly how this test was supposed to be compiled and run.
The ocamltest tool has been introduced to replace most of the makefiles logic. It takes a test program as its input and derives from annotations stored as a special comment at the beginning of the program the exact way to compile and run it. Thus the test-specific metadata are stored in the test file itself and clearly separated from the machinery required to perform the actual tasks, which is centralized in the ocamltest tool.
It may look odd at first glance to write the tool used to test the compiler in its target language. There are, however, parts of the compiler and the standard library that are already tested in a way, namely those used to compile the compiler itself. Therefore, these components can be considered more trustworthy than those that have not yet been used and that's why ocamltest relies only on the part of the standard library that has been used to develop the compiler itself.
This excludes for instance the use of the Unix and Str libraries.
ocamltest needs to know two things:
-
Where the sources of the OCaml compiler to test are located. This is determined while OCaml is built. The default location can be overridden by defining the
OCAMLSRCDIR
environment variable. -
Which directory to use to build tests. The default value for this is
"ocamltest"
underFilename.get_temp_dir_name()
. This value can be overridden by defining theOCAMLTESTDIR
environment variable.
(all the commands below are assumed to be run from
OCAMLSRCDIR/testsuite
)
From here, one can:
This runs the complete testsuite. This includes the "legacy" tests that still use the makefile-based infrastructure and the "new" tests that have been migrated to use ocamltest.
It is convenient to have the following ocamltest script in a directory
appearing in PATH
, like ~/bin
:
#!/bin/sh
TERM=dumb OCAMLRUNPARAM= /path/to/ocaml/sources/ocamltest/ocamltest $*
Once this file has been made executable, one can for instance run:
ocamltest tests/basic-io/wc.ml
As can be seen, ocamltest's output looks similar to the legacy format.
This is to make the transition between the makefile-based infrastructure and ocamltest as smooth as possible. Once all the tests will have been migrated to ocamltest, it will become possible to change this output format.
The details of what exactly has been tested can be found in
${OCAMLTESTDIR}/tests/basic-io/wc/wc.log
One can then examine tests/basic-io/wc.ml
to see how the file had to
be annotated to produce such a result.
Many other tests have already been migrated and it may be useful to see how the test files have been annotated. the command
find tests -name '*ocamltests*' | xargs cat
gives a list of tests that have been modified and can therefore be used as starting points to understand what ocamltest can do.
It may be a good idea to run make new
from the testsuite
directory
before starting to migrate tests. This will show how many "new" tests
there already are.
Then, when running make new
after migrating n tests, the number of
new tests reported by make new
should have increased by n.
OCaml's testsuite is divided into directories, each of them containing one or several tests, which can each consist of one or several files.
Thus, the directory is the smallest unit that can be migrated.
To see which directories still need to be migrated, do:
find tests -name 'Makefile'
In other words, the directories that still need to be migrated are the
subdirectories of testsuite/tests
that still contain a Makefile.
Once you know which directory you want to migrate, say foo
, here is
what you should do:
Read foo/Makefile
to see how many tests the directory contains and how
they are compiled. If the makefile only includes other makefiles and
does not define any variable, then it means that nothing special has to
be done to compile or run the tests.
You can also run the tests of this directory with the legacy framework, to see exactly how they are compiled and executed. To do so, use the following command from the testsuite directory:
make --trace DIR=tests/foo
(You may want to log the output of this command for future reference.)
For each test, annotate its main file with a test block, i.e. a comment that looks like this:
(* TEST
Optional variable assignments and tests
*)
In particular, if the test's main file is foo.ml and the test uses
modules m1.ml
and m2.ml
, the test block will look like this:
(* TEST
modules = "m1.ml m2.ml";
*)
And if the test consists of a single file foo.ml
that needs to be run
under the top-level, then its test block will look like this:
(* TEST
toplevel;
*)
Or, if there are two reference files for that test and the name of one
of them contains "principal", then it means the file should be tested
with the top-level, without and with the -principal
option. This is
expressed as follows:
(* TEST
toplevel;
include principal;
toplevel;
*)
Lines starting with stars indicate which tests to run. If no test is specified, then the tests that are enabled by default are used, namely to compile and run the test program in both bytecode and native code (roughly speaking).
Once your test has been annotated, run ocamltest
on it and see whether
it passes or fails. If it fails, see the log file to understand why and
make the necessary adjustments until all the tests pass.
The adjustments will mostly consist in renaming reference files and updating their content.
Note that there are different types of reference files, those for compiler output and those for program output.
To make sure the migration has been done correctly, you can compare the
commands used to compile the programs in ocamltest's log file to those
obtained with make --trace
. Beware that the commands used to compare
an obtained result to an expected one will not show up in ocamltest's
log file.
Once this has been done for all tests, create a file called ocamltests
(mark the final s!) with the names of all the files that have been
annotated for ocamltest, one per line.
Finally, git rm
the Makefile and run make new
from the testsuite
directory to make sure the number of new tests has increased as
expected.