The tests in this repository are implemented using the doctest framework. If you want to just build and run the tests skip to the section on Building and running the tests.
The doctest code is contained within a single header: doctest.h.
A simple doctest test case is created by adding code such as
TEST_CASE("<test case name>")
{
<test code>
CHECK(<condition that is true if test passes and false if test fail>);
}
In practice, due to device kernel linking issues with HIP and SYCL we have instead created each test case as function declared in a header and defined in a cpp file:
void run_my_test_case()
{
<test code>
CHECK(<condition that is true if test passes and false if test fail>);
}
The header is included in TestCases.hpp and this function is
called inside a TEST_CASE
there:
TEST_CASE("<test case name>")
{
run_my_test_case();
}
Instead of a CHECK()
clause which will report failure in the output and return
value but not abort the application (thereby allowing later tests to run), one
can instead use a REQUIRE()
clause which will immediately abort the
application if the relevant test fails (i.e. if the condition is false).
Unless, there is a good reason, one should default to using CHECK()
clauses.
A common scenario is that one wishes to compare a floating point value produced
by the code to a known correct value. In this case, one can test equality with
the a doctest::Approx
(see this docs
page)
object, for example
double tol = 1e-10;
CHECK(computed_value == doctest::Approx(correct_value).epsilon(tol));
The doctest documentation can be found in the doctest repository here.
You will need the usual AMReX prerequisites:
- Git
- GNU Make >= 3.81
- Python >= 2.7
- A Unix-like environment with perl and sed commands
- C compiler with C99 support
- C++ compiler with C++17 support
Additionally, you will need to make sure you have cloned the AMReX
repository locally. The makefile assumes
you have cloned it into the same directory you cloned this repository (i.e.
../../amrex relative to where this README.md
file is located)
but you can instead clone it elsewhere and set the AMREX_HOME
environment
variable appropriately:
export AMREX_HOME=/path/to/amrex
The tests are all contained in one AMReX application with its main()
defined
in Tests.cpp
. To build this application, simply run
make -j <number of build jobs>
Like any other AMReX GNU Make application, one can pass AMReX configuration
options
such as USE_OMP=TRUE
on the command line e.g.
make -j 4 USE_OMP=TRUE
or modify these directly in the GNUmakefile. Alternatively if
one wishes to use the same configuration options for all AMReX
applications, one can set configuration options in
${AMREX_HOME}/Tools/GNUMake/Make.local-pre
(this file will need to be created if it doesn't exist).
One can run all the tests by simply executing the created executable (e.g.
Tests3d.gnu.ex
) without any arguments. To run a specific test, pass its name
as an argument to the -dt-tc
flag:
./Tests3d.gnu.ex -dt-tc="CCZ4 RHS"
and multiple tests can be run by passing their names in a comma separated list e.g.
./Tests3d.gnu.ex -dt-tc="CCZ4 RHS,Derivative*"
doctest provides a plethora of command line flags to customize the output which
can be found by passing the -dt-h
flag e.g.
./Tests3d.gnu.ex -dt-h
Some particularly useful ones include
-dt-s, --dt-success include successful tests in output
-dt-aa, --dt-abort-after=<int> abort after <int> failed assertions
-dt-ltc, --dt-list-test-cases list all/matching test cases
All doctest flags are prefixed with -dt-
or --dt-
. Any unprefixed arguments
may be passed as command line arguments to test cases so that one can pass
arguments to AMReX e.g.
./Tests3d.gnu.ex amrex.verbose=1 -dt-tc="CCZ4 RHS"
See the CCZ4 RHS test as an example. Here is an outline of the basic steps to adding a new test to the Tests application.
- Create a new test directory with an appropriate name (e.g.
NewGRTeclynTest
). Make sure that the directory name ends withTest
orTests
(so that Make can find it). - In that directory, create a cpp file with the appropriate name (e.g.
NewGRTeclynTest.cpp
). In that file make sure you include the doctest and base AMReX headers (if you are using any AMReX classes).// Doctest header #include "doctest.h" // Provides doctest::cli_args #include "doctestCLIArgs.hpp" // AMReX includes #include "AMReX.H"
- In the cpp file, create a new
run_my_new_grteclyn_test()
as described above. Make sure to initialize and finalize AMReX if using any AMReX data structures (otherwise no memory will be allocated):void run_my_new_grteclyn_test() { // doctest::cli_args stores the non -dt- command line args int amrex_argc = doctest::cli_args.argc(); char **amrex_argv = doctest::cli_args.argv(); // MPI_COMM_WORLD defined in AMReX_ccse-mpi.H even when compiling // without MPI amrex::Initialize(amrex_argc, amrex_argv, true, MPI_COMM_WORLD); { bool test_passes = true; // This code should set test_passes = false if some failure happens <test code> CHECK(test_passes); } amrex::Finalize(); }
- Create a hpp header file with the same filename stem (e.g.
NewGRTeclynTest.hpp
). In that file, declare the test function:Don't forget to include a header guard!void run_my_new_grteclyn_test();
- Create a
Make.package
file in the same directory with the following content:GRTECLYN_CEXE_headers += NewGRTeclynTest.hpp <any other headers> GRTECLYN_CEXE_sources += NewGRTeclynTest.cpp <any other cpp files>
- Include the header file in TestCases.hpp, create the test
case and call the test function:
#include "NewGRTeclynTest.hpp" ... TEST_CASE("New GRTeclyn") { run_my_new_grteclyn_test(); }
- In the GNUmakefile, one may need to uncomment some lines of the form
depending on which AMReX subcomponents are required.
# include $(AMREX_HOME)/Src/<component>/Make.package
- Build and run the test as described above.