Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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>

authored by

Marie Zhussupova and committed by
Shuah Khan
b820b907 b9a214b5

+91 -6
+59 -6
include/kunit/test.h
··· 234 234 * Provides the option to register param_init() and param_exit() functions. 235 235 * param_init/exit will be passed the parameterized test context and run once 236 236 * 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. 240 244 */ 241 245 #define KUNIT_CASE_PARAM_WITH_INIT(test_name, gen_params, init, exit) \ 242 246 { .run_case = test_name, .name = #test_name, \ ··· 293 289 struct kunit_suite * const *end; 294 290 }; 295 291 292 + /* Stores the pointer to the parameter array and its metadata. */ 293 + struct kunit_params { 294 + /* 295 + * Reference to the parameter array for a parameterized test. This 296 + * is NULL if a parameter array wasn't directly passed to the 297 + * parameterized test context struct kunit via kunit_register_params_array(). 298 + */ 299 + const void *params; 300 + /* Reference to a function that gets the description of a parameter. */ 301 + void (*get_description)(struct kunit *test, const void *param, char *desc); 302 + size_t num_params; 303 + size_t elem_size; 304 + }; 305 + 296 306 /** 297 307 * struct kunit - represents a running instance of a test. 298 308 * ··· 314 296 * created in the init function (see &struct kunit_suite). 315 297 * @parent: reference to the parent context of type struct kunit that can 316 298 * be used for storing shared resources. 299 + * @params_array: for storing the parameter array. 317 300 * 318 301 * Used to store information about the current context under which the test 319 302 * is running. Most of this data is private and should only be accessed 320 - * indirectly via public functions; the two exceptions are @priv and @parent 321 - * which can be used by the test writer to store arbitrary data and access the 322 - * parent context, respectively. 303 + * indirectly via public functions; the exceptions are @priv, @parent and 304 + * @params_array which can be used by the test writer to store arbitrary data, 305 + * access the parent context, and to store the parameter array, respectively. 323 306 */ 324 307 struct kunit { 325 308 void *priv; 326 309 struct kunit *parent; 310 + struct kunit_params params_array; 327 311 328 312 /* private: internal use only. */ 329 313 const char *name; /* Read only after initialization! */ ··· 395 375 396 376 struct kunit_suite_set kunit_merge_suite_sets(struct kunit_suite_set init_suite_set, 397 377 struct kunit_suite_set suite_set); 378 + 379 + const void *kunit_array_gen_params(struct kunit *test, const void *prev, char *desc); 398 380 399 381 #if IS_BUILTIN(CONFIG_KUNIT) 400 382 int kunit_run_all_tests(void); ··· 1730 1708 const void *prev, char *desc) \ 1731 1709 { \ 1732 1710 typeof((array)[0]) *__next = prev ? ((typeof(__next)) prev) + 1 : (array); \ 1711 + if (!prev) \ 1712 + kunit_register_params_array(test, array, ARRAY_SIZE(array), NULL); \ 1733 1713 if (__next - (array) < ARRAY_SIZE((array))) { \ 1734 1714 void (*__get_desc)(typeof(__next), char *) = get_desc; \ 1735 1715 if (__get_desc) \ ··· 1754 1730 const void *prev, char *desc) \ 1755 1731 { \ 1756 1732 typeof((array)[0]) *__next = prev ? ((typeof(__next)) prev) + 1 : (array); \ 1733 + if (!prev) \ 1734 + kunit_register_params_array(test, array, ARRAY_SIZE(array), NULL); \ 1757 1735 if (__next - (array) < ARRAY_SIZE((array))) { \ 1758 1736 strscpy(desc, __next->desc_member, KUNIT_PARAM_DESC_SIZE); \ 1759 1737 return __next; \ 1760 1738 } \ 1761 1739 return NULL; \ 1762 1740 } 1741 + 1742 + /** 1743 + * kunit_register_params_array() - Register parameter array for a KUnit test. 1744 + * @test: The KUnit test structure to which parameters will be added. 1745 + * @array: An array of test parameters. 1746 + * @param_count: Number of parameters. 1747 + * @get_desc: Function that generates a string description for a given parameter 1748 + * element. 1749 + * 1750 + * This macro initializes the @test's parameter array data, storing information 1751 + * including the parameter array, its count, the element size, and the parameter 1752 + * description function within `test->params_array`. 1753 + * 1754 + * Note: If using this macro in param_init(), kunit_array_gen_params() 1755 + * will then need to be manually provided as the parameter generator function to 1756 + * KUNIT_CASE_PARAM_WITH_INIT(). kunit_array_gen_params() is a KUnit 1757 + * function that uses the registered array to generate parameters 1758 + */ 1759 + #define kunit_register_params_array(test, array, param_count, get_desc) \ 1760 + do { \ 1761 + struct kunit *_test = (test); \ 1762 + const typeof((array)[0]) * _params_ptr = &(array)[0]; \ 1763 + _test->params_array.params = _params_ptr; \ 1764 + _test->params_array.num_params = (param_count); \ 1765 + _test->params_array.elem_size = sizeof(*_params_ptr); \ 1766 + _test->params_array.get_description = (get_desc); \ 1767 + } while (0) 1763 1768 1764 1769 // TODO(dlatypov@google.com): consider eventually migrating users to explicitly 1765 1770 // include resource.h themselves if they need it.
+32
lib/kunit/test.c
··· 337 337 } 338 338 EXPORT_SYMBOL_GPL(__kunit_do_failed_assertion); 339 339 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 + 340 348 void kunit_init_test(struct kunit *test, const char *name, struct string_stream *log) 341 349 { 342 350 spin_lock_init(&test->lock); ··· 355 347 string_stream_clear(log); 356 348 test->status = KUNIT_SUCCESS; 357 349 test->status_comment[0] = '\0'; 350 + kunit_init_params(test); 358 351 } 359 352 EXPORT_SYMBOL_GPL(kunit_init_test); 360 353 ··· 650 641 total->total += add.total; 651 642 } 652 643 644 + const void *kunit_array_gen_params(struct kunit *test, const void *prev, char *desc) 645 + { 646 + struct kunit_params *params_arr = &test->params_array; 647 + const void *param; 648 + 649 + if (test->param_index < params_arr->num_params) { 650 + param = (char *)params_arr->params 651 + + test->param_index * params_arr->elem_size; 652 + 653 + if (params_arr->get_description) 654 + params_arr->get_description(test, param, desc); 655 + return param; 656 + } 657 + return NULL; 658 + } 659 + EXPORT_SYMBOL_GPL(kunit_array_gen_params); 660 + 653 661 static void kunit_init_parent_param_test(struct kunit_case *test_case, struct kunit *test) 654 662 { 655 663 if (test_case->param_init) { ··· 732 706 "KTAP version 1\n"); 733 707 kunit_log(KERN_INFO, &test, KUNIT_SUBTEST_INDENT KUNIT_SUBTEST_INDENT 734 708 "# Subtest: %s", test_case->name); 709 + if (test.params_array.params && 710 + test_case->generate_params == kunit_array_gen_params) { 711 + kunit_log(KERN_INFO, &test, KUNIT_SUBTEST_INDENT 712 + KUNIT_SUBTEST_INDENT "1..%zd\n", 713 + test.params_array.num_params); 714 + } 735 715 736 716 while (curr_param) { 737 717 struct kunit param_test = {