cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

tips.rst (5080B)


      1.. SPDX-License-Identifier: GPL-2.0
      2
      3============================
      4Tips For Writing KUnit Tests
      5============================
      6
      7Exiting early on failed expectations
      8------------------------------------
      9
     10``KUNIT_EXPECT_EQ`` and friends will mark the test as failed and continue
     11execution.  In some cases, it's unsafe to continue and you can use the
     12``KUNIT_ASSERT`` variant to exit on failure.
     13
     14.. code-block:: c
     15
     16	void example_test_user_alloc_function(struct kunit *test)
     17	{
     18		void *object = alloc_some_object_for_me();
     19
     20		/* Make sure we got a valid pointer back. */
     21		KUNIT_ASSERT_NOT_ERR_OR_NULL(test, object);
     22		do_something_with_object(object);
     23	}
     24
     25Allocating memory
     26-----------------
     27
     28Where you would use ``kzalloc``, you should prefer ``kunit_kzalloc`` instead.
     29KUnit will ensure the memory is freed once the test completes.
     30
     31This is particularly useful since it lets you use the ``KUNIT_ASSERT_EQ``
     32macros to exit early from a test without having to worry about remembering to
     33call ``kfree``.
     34
     35Example:
     36
     37.. code-block:: c
     38
     39	void example_test_allocation(struct kunit *test)
     40	{
     41		char *buffer = kunit_kzalloc(test, 16, GFP_KERNEL);
     42		/* Ensure allocation succeeded. */
     43		KUNIT_ASSERT_NOT_ERR_OR_NULL(test, buffer);
     44
     45		KUNIT_ASSERT_STREQ(test, buffer, "");
     46	}
     47
     48
     49Testing static functions
     50------------------------
     51
     52If you don't want to expose functions or variables just for testing, one option
     53is to conditionally ``#include`` the test file at the end of your .c file, e.g.
     54
     55.. code-block:: c
     56
     57	/* In my_file.c */
     58
     59	static int do_interesting_thing();
     60
     61	#ifdef CONFIG_MY_KUNIT_TEST
     62	#include "my_kunit_test.c"
     63	#endif
     64
     65Injecting test-only code
     66------------------------
     67
     68Similarly to the above, it can be useful to add test-specific logic.
     69
     70.. code-block:: c
     71
     72	/* In my_file.h */
     73
     74	#ifdef CONFIG_MY_KUNIT_TEST
     75	/* Defined in my_kunit_test.c */
     76	void test_only_hook(void);
     77	#else
     78	void test_only_hook(void) { }
     79	#endif
     80
     81This test-only code can be made more useful by accessing the current kunit
     82test, see below.
     83
     84Accessing the current test
     85--------------------------
     86
     87In some cases, you need to call test-only code from outside the test file, e.g.
     88like in the example above or if you're providing a fake implementation of an
     89ops struct.
     90There is a ``kunit_test`` field in ``task_struct``, so you can access it via
     91``current->kunit_test``.
     92
     93Here's a slightly in-depth example of how one could implement "mocking":
     94
     95.. code-block:: c
     96
     97	#include <linux/sched.h> /* for current */
     98
     99	struct test_data {
    100		int foo_result;
    101		int want_foo_called_with;
    102	};
    103
    104	static int fake_foo(int arg)
    105	{
    106		struct kunit *test = current->kunit_test;
    107		struct test_data *test_data = test->priv;
    108
    109		KUNIT_EXPECT_EQ(test, test_data->want_foo_called_with, arg);
    110		return test_data->foo_result;
    111	}
    112
    113	static void example_simple_test(struct kunit *test)
    114	{
    115		/* Assume priv is allocated in the suite's .init */
    116		struct test_data *test_data = test->priv;
    117
    118		test_data->foo_result = 42;
    119		test_data->want_foo_called_with = 1;
    120
    121		/* In a real test, we'd probably pass a pointer to fake_foo somewhere
    122		 * like an ops struct, etc. instead of calling it directly. */
    123		KUNIT_EXPECT_EQ(test, fake_foo(1), 42);
    124	}
    125
    126
    127Note: here we're able to get away with using ``test->priv``, but if you wanted
    128something more flexible you could use a named ``kunit_resource``, see
    129Documentation/dev-tools/kunit/api/test.rst.
    130
    131Failing the current test
    132------------------------
    133
    134But sometimes, you might just want to fail the current test. In that case, we
    135have ``kunit_fail_current_test(fmt, args...)`` which is defined in ``<kunit/test-bug.h>`` and
    136doesn't require pulling in ``<kunit/test.h>``.
    137
    138E.g. say we had an option to enable some extra debug checks on some data structure:
    139
    140.. code-block:: c
    141
    142	#include <kunit/test-bug.h>
    143
    144	#ifdef CONFIG_EXTRA_DEBUG_CHECKS
    145	static void validate_my_data(struct data *data)
    146	{
    147		if (is_valid(data))
    148			return;
    149
    150		kunit_fail_current_test("data %p is invalid", data);
    151
    152		/* Normal, non-KUnit, error reporting code here. */
    153	}
    154	#else
    155	static void my_debug_function(void) { }
    156	#endif
    157
    158
    159Customizing error messages
    160--------------------------
    161
    162Each of the ``KUNIT_EXPECT`` and ``KUNIT_ASSERT`` macros have a ``_MSG`` variant.
    163These take a format string and arguments to provide additional context to the automatically generated error messages.
    164
    165.. code-block:: c
    166
    167	char some_str[41];
    168	generate_sha1_hex_string(some_str);
    169
    170	/* Before. Not easy to tell why the test failed. */
    171	KUNIT_EXPECT_EQ(test, strlen(some_str), 40);
    172
    173	/* After. Now we see the offending string. */
    174	KUNIT_EXPECT_EQ_MSG(test, strlen(some_str), 40, "some_str='%s'", some_str);
    175
    176Alternatively, one can take full control over the error message by using ``KUNIT_FAIL()``, e.g.
    177
    178.. code-block:: c
    179
    180	/* Before */
    181	KUNIT_EXPECT_EQ(test, some_setup_function(), 0);
    182
    183	/* After: full control over the failure message. */
    184	if (some_setup_function())
    185		KUNIT_FAIL(test, "Failed to setup thing for testing");
    186
    187Next Steps
    188==========
    189*   Optional: see the Documentation/dev-tools/kunit/usage.rst page for a more
    190    in-depth explanation of KUnit.