Skip to content

Commit b820b90

Browse files
Marie Zhussupovashuahkh
authored andcommitted
kunit: Enable direct registration of parameter arrays to a KUnit test
KUnit parameterized tests currently support two primary methods f or getting parameters: 1. Defining custom logic within a generate_params() function. 2. Using the KUNIT_ARRAY_PARAM() and KUNIT_ARRAY_PARAM_DESC() macros with a pre-defined static array and passing the created *_gen_params() to KUNIT_CASE_PARAM(). These methods present limitations when dealing with dynamically generated parameter arrays, or in scenarios where populating parameters sequentially via generate_params() is inefficient or overly complex. This patch addresses these limitations by adding a new `params_array` field to `struct kunit`, of the type `kunit_params`. The `struct kunit_params` is designed to store the parameter array itself, along with essential metadata including the parameter count, parameter size, and a get_description() function for providing custom descriptions for individual parameters. The `params_array` field can be populated by calling the new kunit_register_params_array() macro from within a param_init() function. This will register the array as part of the parameterized test context. The user will then need to pass kunit_array_gen_params() to the KUNIT_CASE_PARAM_WITH_INIT() macro as the generator function, if not providing their own. kunit_array_gen_params() is a KUnit helper that will use the registered array to generate parameters. The arrays passed to KUNIT_ARRAY_PARAM(,DESC) will also be registered to the parameterized test context for consistency as well as for higher availability of the parameter count that will be used for outputting a KTAP test plan for a parameterized test. This modification provides greater flexibility to the KUnit framework, allowing testers to easily register and utilize both dynamic and static parameter arrays. Link: https://lore.kernel.org/r/20250826091341.1427123-5-davidgow@google.com Reviewed-by: David Gow <davidgow@google.com> Reviewed-by: Rae Moar <rmoar@google.com> Signed-off-by: Marie Zhussupova <marievic@google.com> [Only output the test plan if using kunit_array_gen_params --David] Signed-off-by: David Gow <davidgow@google.com> Signed-off-by: Shuah Khan <skhan@linuxfoundation.org>
1 parent b9a214b commit b820b90

2 files changed

Lines changed: 91 additions & 6 deletions

File tree

include/kunit/test.h

Lines changed: 59 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -234,9 +234,13 @@ static inline char *kunit_status_to_ok_not_ok(enum kunit_status status)
234234
* Provides the option to register param_init() and param_exit() functions.
235235
* param_init/exit will be passed the parameterized test context and run once
236236
* before and once after the parameterized test. The init function can be used
237-
* to add resources to share between parameter runs, and any other setup logic.
238-
* The exit function can be used to clean up resources that were not managed by
239-
* the parameterized test, and any other teardown logic.
237+
* to add resources to share between parameter runs, pass parameter arrays,
238+
* and any other setup logic. The exit function can be used to clean up resources
239+
* that were not managed by the parameterized test, and any other teardown logic.
240+
*
241+
* Note: If you are registering a parameter array in param_init() with
242+
* kunit_register_param_array() then you need to pass kunit_array_gen_params()
243+
* to this as the generator function.
240244
*/
241245
#define KUNIT_CASE_PARAM_WITH_INIT(test_name, gen_params, init, exit) \
242246
{ .run_case = test_name, .name = #test_name, \
@@ -289,23 +293,39 @@ struct kunit_suite_set {
289293
struct kunit_suite * const *end;
290294
};
291295

296+
/* Stores the pointer to the parameter array and its metadata. */
297+
struct kunit_params {
298+
/*
299+
* Reference to the parameter array for a parameterized test. This
300+
* is NULL if a parameter array wasn't directly passed to the
301+
* parameterized test context struct kunit via kunit_register_params_array().
302+
*/
303+
const void *params;
304+
/* Reference to a function that gets the description of a parameter. */
305+
void (*get_description)(struct kunit *test, const void *param, char *desc);
306+
size_t num_params;
307+
size_t elem_size;
308+
};
309+
292310
/**
293311
* struct kunit - represents a running instance of a test.
294312
*
295313
* @priv: for user to store arbitrary data. Commonly used to pass data
296314
* created in the init function (see &struct kunit_suite).
297315
* @parent: reference to the parent context of type struct kunit that can
298316
* be used for storing shared resources.
317+
* @params_array: for storing the parameter array.
299318
*
300319
* Used to store information about the current context under which the test
301320
* is running. Most of this data is private and should only be accessed
302-
* indirectly via public functions; the two exceptions are @priv and @parent
303-
* which can be used by the test writer to store arbitrary data and access the
304-
* parent context, respectively.
321+
* indirectly via public functions; the exceptions are @priv, @parent and
322+
* @params_array which can be used by the test writer to store arbitrary data,
323+
* access the parent context, and to store the parameter array, respectively.
305324
*/
306325
struct kunit {
307326
void *priv;
308327
struct kunit *parent;
328+
struct kunit_params params_array;
309329

310330
/* private: internal use only. */
311331
const char *name; /* Read only after initialization! */
@@ -376,6 +396,8 @@ void kunit_exec_list_tests(struct kunit_suite_set *suite_set, bool include_attr)
376396
struct kunit_suite_set kunit_merge_suite_sets(struct kunit_suite_set init_suite_set,
377397
struct kunit_suite_set suite_set);
378398

399+
const void *kunit_array_gen_params(struct kunit *test, const void *prev, char *desc);
400+
379401
#if IS_BUILTIN(CONFIG_KUNIT)
380402
int kunit_run_all_tests(void);
381403
#else
@@ -1708,6 +1730,8 @@ do { \
17081730
const void *prev, char *desc) \
17091731
{ \
17101732
typeof((array)[0]) *__next = prev ? ((typeof(__next)) prev) + 1 : (array); \
1733+
if (!prev) \
1734+
kunit_register_params_array(test, array, ARRAY_SIZE(array), NULL); \
17111735
if (__next - (array) < ARRAY_SIZE((array))) { \
17121736
void (*__get_desc)(typeof(__next), char *) = get_desc; \
17131737
if (__get_desc) \
@@ -1730,13 +1754,42 @@ do { \
17301754
const void *prev, char *desc) \
17311755
{ \
17321756
typeof((array)[0]) *__next = prev ? ((typeof(__next)) prev) + 1 : (array); \
1757+
if (!prev) \
1758+
kunit_register_params_array(test, array, ARRAY_SIZE(array), NULL); \
17331759
if (__next - (array) < ARRAY_SIZE((array))) { \
17341760
strscpy(desc, __next->desc_member, KUNIT_PARAM_DESC_SIZE); \
17351761
return __next; \
17361762
} \
17371763
return NULL; \
17381764
}
17391765

1766+
/**
1767+
* kunit_register_params_array() - Register parameter array for a KUnit test.
1768+
* @test: The KUnit test structure to which parameters will be added.
1769+
* @array: An array of test parameters.
1770+
* @param_count: Number of parameters.
1771+
* @get_desc: Function that generates a string description for a given parameter
1772+
* element.
1773+
*
1774+
* This macro initializes the @test's parameter array data, storing information
1775+
* including the parameter array, its count, the element size, and the parameter
1776+
* description function within `test->params_array`.
1777+
*
1778+
* Note: If using this macro in param_init(), kunit_array_gen_params()
1779+
* will then need to be manually provided as the parameter generator function to
1780+
* KUNIT_CASE_PARAM_WITH_INIT(). kunit_array_gen_params() is a KUnit
1781+
* function that uses the registered array to generate parameters
1782+
*/
1783+
#define kunit_register_params_array(test, array, param_count, get_desc) \
1784+
do { \
1785+
struct kunit *_test = (test); \
1786+
const typeof((array)[0]) * _params_ptr = &(array)[0]; \
1787+
_test->params_array.params = _params_ptr; \
1788+
_test->params_array.num_params = (param_count); \
1789+
_test->params_array.elem_size = sizeof(*_params_ptr); \
1790+
_test->params_array.get_description = (get_desc); \
1791+
} while (0)
1792+
17401793
// TODO(dlatypov@google.com): consider eventually migrating users to explicitly
17411794
// include resource.h themselves if they need it.
17421795
#include <kunit/resource.h>

lib/kunit/test.c

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -337,6 +337,14 @@ void __kunit_do_failed_assertion(struct kunit *test,
337337
}
338338
EXPORT_SYMBOL_GPL(__kunit_do_failed_assertion);
339339

340+
static void kunit_init_params(struct kunit *test)
341+
{
342+
test->params_array.params = NULL;
343+
test->params_array.get_description = NULL;
344+
test->params_array.num_params = 0;
345+
test->params_array.elem_size = 0;
346+
}
347+
340348
void kunit_init_test(struct kunit *test, const char *name, struct string_stream *log)
341349
{
342350
spin_lock_init(&test->lock);
@@ -347,6 +355,7 @@ void kunit_init_test(struct kunit *test, const char *name, struct string_stream
347355
string_stream_clear(log);
348356
test->status = KUNIT_SUCCESS;
349357
test->status_comment[0] = '\0';
358+
kunit_init_params(test);
350359
}
351360
EXPORT_SYMBOL_GPL(kunit_init_test);
352361

@@ -641,6 +650,23 @@ static void kunit_accumulate_stats(struct kunit_result_stats *total,
641650
total->total += add.total;
642651
}
643652

653+
const void *kunit_array_gen_params(struct kunit *test, const void *prev, char *desc)
654+
{
655+
struct kunit_params *params_arr = &test->params_array;
656+
const void *param;
657+
658+
if (test->param_index < params_arr->num_params) {
659+
param = (char *)params_arr->params
660+
+ test->param_index * params_arr->elem_size;
661+
662+
if (params_arr->get_description)
663+
params_arr->get_description(test, param, desc);
664+
return param;
665+
}
666+
return NULL;
667+
}
668+
EXPORT_SYMBOL_GPL(kunit_array_gen_params);
669+
644670
static void kunit_init_parent_param_test(struct kunit_case *test_case, struct kunit *test)
645671
{
646672
if (test_case->param_init) {
@@ -706,6 +732,12 @@ int kunit_run_tests(struct kunit_suite *suite)
706732
"KTAP version 1\n");
707733
kunit_log(KERN_INFO, &test, KUNIT_SUBTEST_INDENT KUNIT_SUBTEST_INDENT
708734
"# Subtest: %s", test_case->name);
735+
if (test.params_array.params &&
736+
test_case->generate_params == kunit_array_gen_params) {
737+
kunit_log(KERN_INFO, &test, KUNIT_SUBTEST_INDENT
738+
KUNIT_SUBTEST_INDENT "1..%zd\n",
739+
test.params_array.num_params);
740+
}
709741

710742
while (curr_param) {
711743
struct kunit param_test = {

0 commit comments

Comments
 (0)