2015-09-20 13:53:33 +02:00
|
|
|
Using parameterized tests
|
|
|
|
=========================
|
|
|
|
|
|
|
|
Parameterized tests are useful to repeat a specific test logic over a finite
|
|
|
|
set of parameters.
|
|
|
|
|
|
|
|
Due to limitations on how generated parameters are passed, parameterized tests
|
|
|
|
can only accept one pointer parameter; however, this is not that much of a
|
|
|
|
problem since you can just pass a structure containing the context you need.
|
|
|
|
|
|
|
|
Adding parameterized tests
|
|
|
|
--------------------------
|
|
|
|
|
|
|
|
Adding parameterized tests is done by defining the parameterized test function,
|
|
|
|
and the parameter generator function:
|
|
|
|
|
2016-04-10 16:27:07 +02:00
|
|
|
.. doxygengroup:: ParameterizedBase
|
|
|
|
|
2015-09-20 13:53:33 +02:00
|
|
|
.. code-block:: c
|
|
|
|
|
|
|
|
#include <criterion/parameterized.h>
|
|
|
|
|
2015-09-23 21:54:42 +02:00
|
|
|
ParameterizedTestParameters(suite_name, test_name) {
|
2015-09-20 13:53:33 +02:00
|
|
|
void *params;
|
|
|
|
size_t nb_params;
|
|
|
|
|
|
|
|
// generate parameter set
|
|
|
|
return cr_make_param_array(Type, params, nb_params);
|
|
|
|
}
|
|
|
|
|
|
|
|
ParameterizedTest(Type *param, suite_name, test_name) {
|
|
|
|
// contents of the test
|
|
|
|
}
|
|
|
|
|
|
|
|
``suite_name`` and ``test_name`` are the identifiers of the test suite and
|
|
|
|
the test, respectively. These identifiers must follow the language
|
|
|
|
identifier format.
|
|
|
|
|
|
|
|
``Type`` is the compound type of the generated array. ``params`` and ``nb_params``
|
|
|
|
are the pointer and the length of the generated array, respectively.
|
|
|
|
|
2016-09-27 18:52:48 +02:00
|
|
|
.. note::
|
|
|
|
The parameter array must be reachable after the function returns -- as
|
|
|
|
such, local arrays must be declared with `static` or dynamically allocated.
|
|
|
|
|
2015-09-20 13:53:33 +02:00
|
|
|
Passing multiple parameters
|
|
|
|
---------------------------
|
|
|
|
|
|
|
|
As said earlier, parameterized tests only take one parameter, so passing
|
|
|
|
multiple parameters is, in the strict sense, not possible. However, one can
|
|
|
|
easily use a struct to hold the context as a workaround:
|
|
|
|
|
|
|
|
.. code-block:: c
|
|
|
|
|
|
|
|
#include <criterion/parameterized.h>
|
|
|
|
|
|
|
|
struct my_params {
|
|
|
|
int param0;
|
|
|
|
double param1;
|
|
|
|
...
|
|
|
|
};
|
|
|
|
|
2015-09-23 21:54:42 +02:00
|
|
|
ParameterizedTestParameters(suite_name, test_name) {
|
2016-09-27 18:52:48 +02:00
|
|
|
static struct my_params params[] = {
|
2015-09-23 21:54:42 +02:00
|
|
|
// parameter set
|
|
|
|
};
|
2015-09-20 13:53:33 +02:00
|
|
|
|
2015-09-23 21:54:42 +02:00
|
|
|
size_t nb_params = sizeof (params) / sizeof (struct my_params);
|
2015-09-20 13:53:33 +02:00
|
|
|
return cr_make_param_array(struct my_params, params, nb_params);
|
|
|
|
}
|
|
|
|
|
|
|
|
ParameterizedTest(struct my_params *param, suite_name, test_name) {
|
|
|
|
// access param.param0, param.param1, ...
|
|
|
|
}
|
|
|
|
|
2015-09-23 21:54:42 +02:00
|
|
|
C++ users can also use a simpler syntax before returning an array of parameters:
|
|
|
|
|
|
|
|
.. code-block:: c++
|
|
|
|
|
|
|
|
ParameterizedTestParameters(suite_name, test_name) {
|
2016-09-27 18:52:48 +02:00
|
|
|
static struct my_params params[] = {
|
2015-09-23 21:54:42 +02:00
|
|
|
// parameter set
|
|
|
|
};
|
|
|
|
|
|
|
|
return criterion_test_params(params);
|
|
|
|
}
|
|
|
|
|
|
|
|
Dynamically allocating parameters
|
|
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
2015-09-20 13:53:33 +02:00
|
|
|
|
2015-09-21 18:06:26 +02:00
|
|
|
Any dynamic memory allocation done from a ParameterizedTestParameter function
|
|
|
|
**must** be done with ``cr_malloc``, ``cr_calloc``, or ``cr_realloc``.
|
|
|
|
|
|
|
|
Any pointer returned by those 3 functions must be passed to ``cr_free`` after
|
|
|
|
you have no more use of it.
|
|
|
|
|
|
|
|
It is undefined behaviour to use any other allocation function (such as ``malloc``)
|
|
|
|
from the scope of a ParameterizedTestParameter function.
|
|
|
|
|
|
|
|
In C++, these methods should not be called explicitely -- instead, you should
|
|
|
|
use:
|
|
|
|
|
|
|
|
* ``criterion::new_obj<Type>(params...)`` to allocate an object of type ``Type``
|
|
|
|
and call its constructor taking ``params...``.
|
|
|
|
The function possess the exact same semantics as ``new Type(params...)``.
|
|
|
|
* ``criterion::delete_obj(obj)`` to destroy an object previously allocated by
|
|
|
|
``criterion::new_obj``.
|
|
|
|
The function possess the exact same semantics as ``delete obj``.
|
|
|
|
* ``criterion::new_arr<Type>(size)`` to allocate an array of objects of type ``Type``
|
|
|
|
and length ``size``. ``Type`` is initialized by calling its default constructor.
|
|
|
|
The function possess the exact same semantics as ``new Type[size]``.
|
|
|
|
* ``criterion::delete_arr(array)`` to destroy an array previously allocated by
|
|
|
|
``criterion::new_arr``.
|
|
|
|
The function possess the exact same semantics as ``delete[] array``.
|
|
|
|
|
2015-09-23 21:54:42 +02:00
|
|
|
Furthermore, the ``criterion::allocator<T>`` allocator can be used with STL
|
|
|
|
containers to allocate memory with the functions above.
|
|
|
|
|
2015-09-21 18:06:26 +02:00
|
|
|
Freeing dynamically allocated parameter fields
|
|
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
|
|
|
|
One can pass an extra parameter to ``cr_make_param_array`` to specify
|
|
|
|
the cleanup function that should be called on the generated parameter context:
|
2015-09-20 13:53:33 +02:00
|
|
|
|
|
|
|
.. code-block:: c
|
|
|
|
|
|
|
|
#include <criterion/parameterized.h>
|
|
|
|
|
|
|
|
struct my_params {
|
|
|
|
int *some_int_ptr;
|
|
|
|
};
|
|
|
|
|
2015-09-21 18:06:26 +02:00
|
|
|
void cleanup_params(struct criterion_test_params *ctp) {
|
|
|
|
cr_free(((struct my_params *) ctp->params)->some_int_ptr);
|
|
|
|
}
|
|
|
|
|
2015-09-23 21:54:42 +02:00
|
|
|
ParameterizedTestParameters(suite_name, test_name) {
|
|
|
|
static my_params params[] = {{
|
2015-09-21 18:06:26 +02:00
|
|
|
.some_int_ptr = cr_malloc(sizeof (int));
|
2015-09-23 21:54:42 +02:00
|
|
|
}};
|
|
|
|
param[0].some_int_ptr = 42;
|
2015-09-20 13:53:33 +02:00
|
|
|
|
2015-09-23 21:54:42 +02:00
|
|
|
return cr_make_param_array(struct my_params, params, 1, cleanup_params);
|
2015-09-20 13:53:33 +02:00
|
|
|
}
|
|
|
|
|
2015-09-23 21:54:42 +02:00
|
|
|
C++ users can use a more convenient approach:
|
|
|
|
|
|
|
|
.. code-block:: c++
|
|
|
|
|
|
|
|
#include <criterion/parameterized.h>
|
|
|
|
|
|
|
|
struct my_params {
|
|
|
|
std::unique_ptr<int, decltype(criterion::free)> some_int_ptr;
|
|
|
|
|
|
|
|
my_params(int *ptr) : some_int_ptr(ptr, criterion::free) {}
|
|
|
|
};
|
|
|
|
|
|
|
|
ParameterizedTestParameters(suite_name, test_name) {
|
|
|
|
static criterion::parameters<my_params> params;
|
|
|
|
params.push_back(my_params(criterion::new_obj<int>(42)));
|
|
|
|
|
|
|
|
return params;
|
|
|
|
}
|
|
|
|
|
|
|
|
``criterion::parameters<T>`` is typedef'd as ``std::vector<T, criterion::allocator<T>>``.
|
|
|
|
|
2015-09-20 13:53:33 +02:00
|
|
|
Configuring parameterized tests
|
|
|
|
-------------------------------
|
|
|
|
|
|
|
|
Parameterized tests can optionally recieve configuration parameters to alter
|
|
|
|
their own behaviour, and are applied to each iteration of the parameterized
|
|
|
|
test individually (this means that the initialization and finalization runs once
|
|
|
|
per iteration).
|
|
|
|
Those parameters are the same ones as the ones of the ``Test`` macro function
|
|
|
|
(c.f. :ref:`test-config-ref`).
|
|
|
|
|
|
|
|
|