@@ -542,11 +542,31 @@ There is more boilerplate code involved, but it can:
542542Parameterized Testing
543543~~~~~~~~~~~~~~~~~~~~~
544544
545- The table-driven testing pattern is common enough that KUnit has special
546- support for it.
545+ To run a test case against multiple inputs, KUnit provides a parameterized
546+ testing framework. This feature formalizes and extends the concept of
547+ table-driven tests discussed previously.
547548
548- By reusing the same ``cases `` array from above, we can write the test as a
549- "parameterized test" with the following.
549+ A KUnit test is determined to be parameterized if a parameter generator function
550+ is provided when registering the test case. A test user can either write their
551+ own generator function or use one that is provided by KUnit. The generator
552+ function is stored in ``kunit_case->generate_params `` and can be set using the
553+ macros described in the section below.
554+
555+ To establish the terminology, a "parameterized test" is a test which is run
556+ multiple times (once per "parameter" or "parameter run"). Each parameter run has
557+ both its own independent ``struct kunit `` (the "parameter run context") and
558+ access to a shared parent ``struct kunit `` (the "parameterized test context").
559+
560+ Passing Parameters to a Test
561+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
562+ There are three ways to provide the parameters to a test:
563+
564+ Array Parameter Macros:
565+
566+ KUnit provides special support for the common table-driven testing pattern.
567+ By applying either ``KUNIT_ARRAY_PARAM `` or ``KUNIT_ARRAY_PARAM_DESC `` to the
568+ ``cases `` array from the previous section, we can create a parameterized test
569+ as shown below:
550570
551571.. code-block :: c
552572
@@ -555,7 +575,7 @@ By reusing the same ``cases`` array from above, we can write the test as a
555575 const char *str;
556576 const char *sha1;
557577 };
558- const struct sha1_test_case cases[] = {
578+ static const struct sha1_test_case cases[] = {
559579 {
560580 .str = "hello world",
561581 .sha1 = "2aae6c35c94fcfb415dbe95f408b9ce91ee846ed",
@@ -590,6 +610,318 @@ By reusing the same ``cases`` array from above, we can write the test as a
590610 {}
591611 };
592612
613+ Custom Parameter Generator Function:
614+
615+ The generator function is responsible for generating parameters one-by-one
616+ and has the following signature:
617+ ``const void* (*)(struct kunit *test, const void *prev, char *desc) ``.
618+ You can pass the generator function to the ``KUNIT_CASE_PARAM ``
619+ or ``KUNIT_CASE_PARAM_WITH_INIT `` macros.
620+
621+ The function receives the previously generated parameter as the ``prev `` argument
622+ (which is ``NULL `` on the first call) and can also access the parameterized
623+ test context passed as the ``test `` argument. KUnit calls this function
624+ repeatedly until it returns ``NULL ``, which signifies that a parameterized
625+ test ended.
626+
627+ Below is an example of how it works:
628+
629+ .. code-block :: c
630+
631+ #define MAX_TEST_BUFFER_SIZE 8
632+
633+ // Example generator function. It produces a sequence of buffer sizes that
634+ // are powers of two, starting at 1 (e.g., 1, 2, 4, 8).
635+ static const void *buffer_size_gen_params(struct kunit *test, const void *prev, char *desc)
636+ {
637+ long prev_buffer_size = (long)prev;
638+ long next_buffer_size = 1; // Start with an initial size of 1.
639+
640+ // Stop generating parameters if the limit is reached or exceeded.
641+ if (prev_buffer_size >= MAX_TEST_BUFFER_SIZE)
642+ return NULL;
643+
644+ // For subsequent calls, calculate the next size by doubling the previous one.
645+ if (prev)
646+ next_buffer_size = prev_buffer_size << 1;
647+
648+ return (void *)next_buffer_size;
649+ }
650+
651+ // Simple test to validate that kunit_kzalloc provides zeroed memory.
652+ static void buffer_zero_test(struct kunit *test)
653+ {
654+ long buffer_size = (long)test->param_value;
655+ // Use kunit_kzalloc to allocate a zero-initialized buffer. This makes the
656+ // memory "parameter run managed," meaning it's automatically cleaned up at
657+ // the end of each parameter run.
658+ int *buf = kunit_kzalloc(test, buffer_size * sizeof(int), GFP_KERNEL);
659+
660+ // Ensure the allocation was successful.
661+ KUNIT_ASSERT_NOT_NULL(test, buf);
662+
663+ // Loop through the buffer and confirm every element is zero.
664+ for (int i = 0; i < buffer_size; i++)
665+ KUNIT_EXPECT_EQ(test, buf[i], 0);
666+ }
667+
668+ static struct kunit_case buffer_test_cases[] = {
669+ KUNIT_CASE_PARAM(buffer_zero_test, buffer_size_gen_params),
670+ {}
671+ };
672+
673+ Runtime Parameter Array Registration in the Init Function:
674+
675+ For scenarios where you might need to initialize a parameterized test, you
676+ can directly register a parameter array to the parameterized test context.
677+
678+ To do this, you must pass the parameterized test context, the array itself,
679+ the array size, and a ``get_description() `` function to the
680+ ``kunit_register_params_array() `` macro. This macro populates
681+ ``struct kunit_params `` within the parameterized test context, effectively
682+ storing a parameter array object. The ``get_description() `` function will
683+ be used for populating parameter descriptions and has the following signature:
684+ ``void (*)(struct kunit *test, const void *param, char *desc) ``. Note that it
685+ also has access to the parameterized test context.
686+
687+ .. important ::
688+ When using this way to register a parameter array, you will need to
689+ manually pass ``kunit_array_gen_params() `` as the generator function to
690+ ``KUNIT_CASE_PARAM_WITH_INIT ``. ``kunit_array_gen_params() `` is a KUnit
691+ helper that will use the registered array to generate the parameters.
692+
693+ If needed, instead of passing the KUnit helper, you can also pass your
694+ own custom generator function that utilizes the parameter array. To
695+ access the parameter array from within the parameter generator
696+ function use ``test->params_array.params ``.
697+
698+ The ``kunit_register_params_array() `` macro should be called within a
699+ ``param_init() `` function that initializes the parameterized test and has
700+ the following signature ``int (*)(struct kunit *test) ``. For a detailed
701+ explanation of this mechanism please refer to the "Adding Shared Resources"
702+ section that is after this one. This method supports registering both
703+ dynamically built and static parameter arrays.
704+
705+ The code snippet below shows the ``example_param_init_dynamic_arr `` test that
706+ utilizes ``make_fibonacci_params() `` to create a dynamic array, which is then
707+ registered using ``kunit_register_params_array() ``. To see the full code
708+ please refer to lib/kunit/kunit-example-test.c.
709+
710+ .. code-block :: c
711+
712+ /*
713+ * Example of a parameterized test param_init() function that registers a dynamic
714+ * array of parameters.
715+ */
716+ static int example_param_init_dynamic_arr(struct kunit *test)
717+ {
718+ size_t seq_size;
719+ int *fibonacci_params;
720+
721+ kunit_info(test, "initializing parameterized test\n");
722+
723+ seq_size = 6;
724+ fibonacci_params = make_fibonacci_params(test, seq_size);
725+ if (!fibonacci_params)
726+ return -ENOMEM;
727+ /*
728+ * Passes the dynamic parameter array information to the parameterized test
729+ * context struct kunit. The array and its metadata will be stored in
730+ * test->parent->params_array. The array itself will be located in
731+ * params_data.params.
732+ */
733+ kunit_register_params_array(test, fibonacci_params, seq_size,
734+ example_param_dynamic_arr_get_desc);
735+ return 0;
736+ }
737+
738+ static struct kunit_case example_test_cases[] = {
739+ /*
740+ * Note how we pass kunit_array_gen_params() to use the array we
741+ * registered in example_param_init_dynamic_arr() to generate
742+ * parameters.
743+ */
744+ KUNIT_CASE_PARAM_WITH_INIT(example_params_test_with_init_dynamic_arr,
745+ kunit_array_gen_params,
746+ example_param_init_dynamic_arr,
747+ example_param_exit_dynamic_arr),
748+ {}
749+ };
750+
751+ Adding Shared Resources
752+ ^^^^^^^^^^^^^^^^^^^^^^^
753+ All parameter runs in this framework hold a reference to the parameterized test
754+ context, which can be accessed using the parent ``struct kunit `` pointer. The
755+ parameterized test context is not used to execute any test logic itself; instead,
756+ it serves as a container for shared resources.
757+
758+ It's possible to add resources to share between parameter runs within a
759+ parameterized test by using ``KUNIT_CASE_PARAM_WITH_INIT ``, to which you pass
760+ custom ``param_init() `` and ``param_exit() `` functions. These functions run once
761+ before and once after the parameterized test, respectively.
762+
763+ The ``param_init() `` function, with the signature ``int (*)(struct kunit *test) ``,
764+ can be used for adding resources to the ``resources `` or ``priv `` fields of
765+ the parameterized test context, registering the parameter array, and any other
766+ initialization logic.
767+
768+ The ``param_exit() `` function, with the signature ``void (*)(struct kunit *test) ``,
769+ can be used to release any resources that were not parameterized test managed (i.e.
770+ not automatically cleaned up after the parameterized test ends) and for any other
771+ exit logic.
772+
773+ Both ``param_init() `` and ``param_exit() `` are passed the parameterized test
774+ context behind the scenes. However, the test case function receives the parameter
775+ run context. Therefore, to manage and access shared resources from within a test
776+ case function, you must use ``test->parent ``.
777+
778+ For instance, finding a shared resource allocated by the Resource API requires
779+ passing ``test->parent `` to ``kunit_find_resource() ``. This principle extends to
780+ all other APIs that might be used in the test case function, including
781+ ``kunit_kzalloc() ``, ``kunit_kmalloc_array() ``, and others (see
782+ Documentation/dev-tools/kunit/api/test.rst and the
783+ Documentation/dev-tools/kunit/api/resource.rst).
784+
785+ .. note ::
786+ The ``suite->init() `` function, which executes before each parameter run,
787+ receives the parameter run context. Therefore, any resources set up in
788+ ``suite->init() `` are cleaned up after each parameter run.
789+
790+ The code below shows how you can add the shared resources. Note that this code
791+ utilizes the Resource API, which you can read more about here:
792+ Documentation/dev-tools/kunit/api/resource.rst. To see the full version of this
793+ code please refer to lib/kunit/kunit-example-test.c.
794+
795+ .. code-block :: c
796+
797+ static int example_resource_init(struct kunit_resource *res, void *context)
798+ {
799+ ... /* Code that allocates memory and stores context in res->data. */
800+ }
801+
802+ /* This function deallocates memory for the kunit_resource->data field. */
803+ static void example_resource_free(struct kunit_resource *res)
804+ {
805+ kfree(res->data);
806+ }
807+
808+ /* This match function locates a test resource based on defined criteria. */
809+ static bool example_resource_alloc_match(struct kunit *test, struct kunit_resource *res,
810+ void *match_data)
811+ {
812+ return res->data && res->free == example_resource_free;
813+ }
814+
815+ /* Function to initialize the parameterized test. */
816+ static int example_param_init(struct kunit *test)
817+ {
818+ int ctx = 3; /* Data to be stored. */
819+ void *data = kunit_alloc_resource(test, example_resource_init,
820+ example_resource_free,
821+ GFP_KERNEL, &ctx);
822+ if (!data)
823+ return -ENOMEM;
824+ kunit_register_params_array(test, example_params_array,
825+ ARRAY_SIZE(example_params_array));
826+ return 0;
827+ }
828+
829+ /* Example test that uses shared resources in test->resources. */
830+ static void example_params_test_with_init(struct kunit *test)
831+ {
832+ int threshold;
833+ const struct example_param *param = test->param_value;
834+ /* Here we pass test->parent to access the parameterized test context. */
835+ struct kunit_resource *res = kunit_find_resource(test->parent,
836+ example_resource_alloc_match,
837+ NULL);
838+
839+ threshold = *((int *)res->data);
840+ KUNIT_ASSERT_LE(test, param->value, threshold);
841+ kunit_put_resource(res);
842+ }
843+
844+ static struct kunit_case example_test_cases[] = {
845+ KUNIT_CASE_PARAM_WITH_INIT(example_params_test_with_init, kunit_array_gen_params,
846+ example_param_init, NULL),
847+ {}
848+ };
849+
850+ As an alternative to using the KUnit Resource API for sharing resources, you can
851+ place them in ``test->parent->priv ``. This serves as a more lightweight method
852+ for resource storage, best for scenarios where complex resource management is
853+ not required.
854+
855+ As stated previously ``param_init() `` and ``param_exit() `` get the parameterized
856+ test context. So, you can directly use ``test->priv `` within ``param_init/exit ``
857+ to manage shared resources. However, from within the test case function, you must
858+ navigate up to the parent ``struct kunit `` i.e. the parameterized test context.
859+ Therefore, you need to use ``test->parent->priv `` to access those same
860+ resources.
861+
862+ The resources placed in ``test->parent->priv `` will need to be allocated in
863+ memory to persist across the parameter runs. If memory is allocated using the
864+ KUnit memory allocation APIs (described more in the "Allocating Memory" section
865+ below), you won't need to worry about deallocation. The APIs will make the memory
866+ parameterized test 'managed', ensuring that it will automatically get cleaned up
867+ after the parameterized test concludes.
868+
869+ The code below demonstrates example usage of the ``priv `` field for shared
870+ resources:
871+
872+ .. code-block :: c
873+
874+ static const struct example_param {
875+ int value;
876+ } example_params_array[] = {
877+ { .value = 3, },
878+ { .value = 2, },
879+ { .value = 1, },
880+ { .value = 0, },
881+ };
882+
883+ /* Initialize the parameterized test context. */
884+ static int example_param_init_priv(struct kunit *test)
885+ {
886+ int ctx = 3; /* Data to be stored. */
887+ int arr_size = ARRAY_SIZE(example_params_array);
888+
889+ /*
890+ * Allocate memory using kunit_kzalloc(). Since the `param_init`
891+ * function receives the parameterized test context, this memory
892+ * allocation will be scoped to the lifetime of the parameterized test.
893+ */
894+ test->priv = kunit_kzalloc(test, sizeof(int), GFP_KERNEL);
895+
896+ /* Assign the context value to test->priv.*/
897+ *((int *)test->priv) = ctx;
898+
899+ /* Register the parameter array. */
900+ kunit_register_params_array(test, example_params_array, arr_size, NULL);
901+ return 0;
902+ }
903+
904+ static void example_params_test_with_init_priv(struct kunit *test)
905+ {
906+ int threshold;
907+ const struct example_param *param = test->param_value;
908+
909+ /* By design, test->parent will not be NULL. */
910+ KUNIT_ASSERT_NOT_NULL(test, test->parent);
911+
912+ /* Here we use test->parent->priv to access the shared resource. */
913+ threshold = *(int *)test->parent->priv;
914+
915+ KUNIT_ASSERT_LE(test, param->value, threshold);
916+ }
917+
918+ static struct kunit_case example_tests[] = {
919+ KUNIT_CASE_PARAM_WITH_INIT(example_params_test_with_init_priv,
920+ kunit_array_gen_params,
921+ example_param_init_priv, NULL),
922+ {}
923+ };
924+
593925 Allocating Memory
594926-----------------
595927
0 commit comments