mirror of
https://github.com/armbian/linux-cix.git
synced 2026-01-06 12:30:45 -08:00
Merge tag 'linux-kselftest-kunit-next-6.2-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/shuah/linux-kselftest
Pull KUnit updates from Shuah Khan:
"Several enhancements, fixes, clean-ups, documentation updates,
improvements to logging and KTAP compliance of KUnit test output:
- log numbers in decimal and hex
- parse KTAP compliant test output
- allow conditionally exposing static symbols to tests when KUNIT is
enabled
- make static symbols visible during kunit testing
- clean-ups to remove unused structure definition"
* tag 'linux-kselftest-kunit-next-6.2-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/shuah/linux-kselftest: (29 commits)
Documentation: dev-tools: Clarify requirements for result description
apparmor: test: make static symbols visible during kunit testing
kunit: add macro to allow conditionally exposing static symbols to tests
kunit: tool: make parser preserve whitespace when printing test log
Documentation: kunit: Fix "How Do I Use This" / "Next Steps" sections
kunit: tool: don't include KTAP headers and the like in the test log
kunit: improve KTAP compliance of KUnit test output
kunit: tool: parse KTAP compliant test output
mm: slub: test: Use the kunit_get_current_test() function
kunit: Use the static key when retrieving the current test
kunit: Provide a static key to check if KUnit is actively running tests
kunit: tool: make --json do nothing if --raw_ouput is set
kunit: tool: tweak error message when no KTAP found
kunit: remove KUNIT_INIT_MEM_ASSERTION macro
Documentation: kunit: Remove redundant 'tips.rst' page
Documentation: KUnit: reword description of assertions
Documentation: KUnit: make usage.rst a superset of tips.rst, remove duplication
kunit: eliminate KUNIT_INIT_*_ASSERT_STRUCT macros
kunit: tool: remove redundant file.close() call in unit test
kunit: tool: unit tests all check parser errors, standardize formatting a bit
...
This commit is contained in:
@@ -80,8 +80,8 @@ have the number 1 and the number then must increase by 1 for each additional
|
||||
subtest within the same test at the same nesting level.
|
||||
|
||||
The description is a description of the test, generally the name of
|
||||
the test, and can be any string of words (can't include #). The
|
||||
description is optional, but recommended.
|
||||
the test, and can be any string of characters other than # or a
|
||||
newline. The description is optional, but recommended.
|
||||
|
||||
The directive and any diagnostic data is optional. If either are present, they
|
||||
must follow a hash sign, "#".
|
||||
|
||||
@@ -4,16 +4,17 @@
|
||||
KUnit Architecture
|
||||
==================
|
||||
|
||||
The KUnit architecture can be divided into two parts:
|
||||
The KUnit architecture is divided into two parts:
|
||||
|
||||
- `In-Kernel Testing Framework`_
|
||||
- `kunit_tool (Command Line Test Harness)`_
|
||||
- `kunit_tool (Command-line Test Harness)`_
|
||||
|
||||
In-Kernel Testing Framework
|
||||
===========================
|
||||
|
||||
The kernel testing library supports KUnit tests written in C using
|
||||
KUnit. KUnit tests are kernel code. KUnit does several things:
|
||||
KUnit. These KUnit tests are kernel code. KUnit performs the following
|
||||
tasks:
|
||||
|
||||
- Organizes tests
|
||||
- Reports test results
|
||||
@@ -22,19 +23,17 @@ KUnit. KUnit tests are kernel code. KUnit does several things:
|
||||
Test Cases
|
||||
----------
|
||||
|
||||
The fundamental unit in KUnit is the test case. The KUnit test cases are
|
||||
grouped into KUnit suites. A KUnit test case is a function with type
|
||||
signature ``void (*)(struct kunit *test)``.
|
||||
These test case functions are wrapped in a struct called
|
||||
struct kunit_case.
|
||||
The test case is the fundamental unit in KUnit. KUnit test cases are organised
|
||||
into suites. A KUnit test case is a function with type signature
|
||||
``void (*)(struct kunit *test)``. These test case functions are wrapped in a
|
||||
struct called struct kunit_case.
|
||||
|
||||
.. note:
|
||||
``generate_params`` is optional for non-parameterized tests.
|
||||
|
||||
Each KUnit test case gets a ``struct kunit`` context
|
||||
object passed to it that tracks a running test. The KUnit assertion
|
||||
macros and other KUnit utilities use the ``struct kunit`` context
|
||||
object. As an exception, there are two fields:
|
||||
Each KUnit test case receives a ``struct kunit`` context object that tracks a
|
||||
running test. The KUnit assertion macros and other KUnit utilities use the
|
||||
``struct kunit`` context object. As an exception, there are two fields:
|
||||
|
||||
- ``->priv``: The setup functions can use it to store arbitrary test
|
||||
user data.
|
||||
@@ -77,12 +76,13 @@ Executor
|
||||
|
||||
The KUnit executor can list and run built-in KUnit tests on boot.
|
||||
The Test suites are stored in a linker section
|
||||
called ``.kunit_test_suites``. For code, see:
|
||||
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/include/asm-generic/vmlinux.lds.h?h=v5.15#n945.
|
||||
called ``.kunit_test_suites``. For the code, see ``KUNIT_TABLE()`` macro
|
||||
definition in
|
||||
`include/asm-generic/vmlinux.lds.h <https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/include/asm-generic/vmlinux.lds.h?h=v6.0#n950>`_.
|
||||
The linker section consists of an array of pointers to
|
||||
``struct kunit_suite``, and is populated by the ``kunit_test_suites()``
|
||||
macro. To run all tests compiled into the kernel, the KUnit executor
|
||||
iterates over the linker section array.
|
||||
macro. The KUnit executor iterates over the linker section array in order to
|
||||
run all the tests that are compiled into the kernel.
|
||||
|
||||
.. kernel-figure:: kunit_suitememorydiagram.svg
|
||||
:alt: KUnit Suite Memory
|
||||
@@ -90,17 +90,17 @@ iterates over the linker section array.
|
||||
KUnit Suite Memory Diagram
|
||||
|
||||
On the kernel boot, the KUnit executor uses the start and end addresses
|
||||
of this section to iterate over and run all tests. For code, see:
|
||||
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/lib/kunit/executor.c
|
||||
|
||||
of this section to iterate over and run all tests. For the implementation of the
|
||||
executor, see
|
||||
`lib/kunit/executor.c <https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/lib/kunit/executor.c>`_.
|
||||
When built as a module, the ``kunit_test_suites()`` macro defines a
|
||||
``module_init()`` function, which runs all the tests in the compilation
|
||||
unit instead of utilizing the executor.
|
||||
|
||||
In KUnit tests, some error classes do not affect other tests
|
||||
or parts of the kernel, each KUnit case executes in a separate thread
|
||||
context. For code, see:
|
||||
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/lib/kunit/try-catch.c?h=v5.15#n58
|
||||
context. See the ``kunit_try_catch_run()`` function in
|
||||
`lib/kunit/try-catch.c <https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/lib/kunit/try-catch.c?h=v5.15#n58>`_.
|
||||
|
||||
Assertion Macros
|
||||
----------------
|
||||
@@ -111,37 +111,36 @@ All expectations/assertions are formatted as:
|
||||
|
||||
- ``{EXPECT|ASSERT}`` determines whether the check is an assertion or an
|
||||
expectation.
|
||||
In the event of a failure, the testing flow differs as follows:
|
||||
|
||||
- For an expectation, if the check fails, marks the test as failed
|
||||
and logs the failure.
|
||||
- For expectations, the test is marked as failed and the failure is logged.
|
||||
|
||||
- An assertion, on failure, causes the test case to terminate
|
||||
immediately.
|
||||
- Failing assertions, on the other hand, result in the test case being
|
||||
terminated immediately.
|
||||
|
||||
- Assertions call function:
|
||||
- Assertions call the function:
|
||||
``void __noreturn kunit_abort(struct kunit *)``.
|
||||
|
||||
- ``kunit_abort`` calls function:
|
||||
- ``kunit_abort`` calls the function:
|
||||
``void __noreturn kunit_try_catch_throw(struct kunit_try_catch *try_catch)``.
|
||||
|
||||
- ``kunit_try_catch_throw`` calls function:
|
||||
- ``kunit_try_catch_throw`` calls the function:
|
||||
``void kthread_complete_and_exit(struct completion *, long) __noreturn;``
|
||||
and terminates the special thread context.
|
||||
|
||||
- ``<op>`` denotes a check with options: ``TRUE`` (supplied property
|
||||
has the boolean value “true”), ``EQ`` (two supplied properties are
|
||||
has the boolean value "true"), ``EQ`` (two supplied properties are
|
||||
equal), ``NOT_ERR_OR_NULL`` (supplied pointer is not null and does not
|
||||
contain an “err” value).
|
||||
contain an "err" value).
|
||||
|
||||
- ``[_MSG]`` prints a custom message on failure.
|
||||
|
||||
Test Result Reporting
|
||||
---------------------
|
||||
KUnit prints test results in KTAP format. KTAP is based on TAP14, see:
|
||||
https://github.com/isaacs/testanything.github.io/blob/tap14/tap-version-14-specification.md.
|
||||
KTAP (yet to be standardized format) works with KUnit and Kselftest.
|
||||
The KUnit executor prints KTAP results to dmesg, and debugfs
|
||||
(if configured).
|
||||
KUnit prints the test results in KTAP format. KTAP is based on TAP14, see
|
||||
Documentation/dev-tools/ktap.rst.
|
||||
KTAP works with KUnit and Kselftest. The KUnit executor prints KTAP results to
|
||||
dmesg, and debugfs (if configured).
|
||||
|
||||
Parameterized Tests
|
||||
-------------------
|
||||
@@ -150,33 +149,35 @@ Each KUnit parameterized test is associated with a collection of
|
||||
parameters. The test is invoked multiple times, once for each parameter
|
||||
value and the parameter is stored in the ``param_value`` field.
|
||||
The test case includes a KUNIT_CASE_PARAM() macro that accepts a
|
||||
generator function.
|
||||
The generator function is passed the previous parameter and returns the next
|
||||
parameter. It also provides a macro to generate common-case generators based on
|
||||
arrays.
|
||||
generator function. The generator function is passed the previous parameter
|
||||
and returns the next parameter. It also includes a macro for generating
|
||||
array-based common-case generators.
|
||||
|
||||
kunit_tool (Command Line Test Harness)
|
||||
kunit_tool (Command-line Test Harness)
|
||||
======================================
|
||||
|
||||
kunit_tool is a Python script ``(tools/testing/kunit/kunit.py)``
|
||||
that can be used to configure, build, exec, parse and run (runs other
|
||||
commands in order) test results. You can either run KUnit tests using
|
||||
kunit_tool or can include KUnit in kernel and parse manually.
|
||||
``kunit_tool`` is a Python script, found in ``tools/testing/kunit/kunit.py``. It
|
||||
is used to configure, build, execute, parse test results and run all of the
|
||||
previous commands in correct order (i.e., configure, build, execute and parse).
|
||||
You have two options for running KUnit tests: either build the kernel with KUnit
|
||||
enabled and manually parse the results (see
|
||||
Documentation/dev-tools/kunit/run_manual.rst) or use ``kunit_tool``
|
||||
(see Documentation/dev-tools/kunit/run_wrapper.rst).
|
||||
|
||||
- ``configure`` command generates the kernel ``.config`` from a
|
||||
``.kunitconfig`` file (and any architecture-specific options).
|
||||
For some architectures, additional config options are specified in the
|
||||
``qemu_config`` Python script
|
||||
(For example: ``tools/testing/kunit/qemu_configs/powerpc.py``).
|
||||
The Python scripts available in ``qemu_configs`` folder
|
||||
(for example, ``tools/testing/kunit/qemu configs/powerpc.py``) contains
|
||||
additional configuration options for specific architectures.
|
||||
It parses both the existing ``.config`` and the ``.kunitconfig`` files
|
||||
and ensures that ``.config`` is a superset of ``.kunitconfig``.
|
||||
If this is not the case, it will combine the two and run
|
||||
``make olddefconfig`` to regenerate the ``.config`` file. It then
|
||||
verifies that ``.config`` is now a superset. This checks if all
|
||||
Kconfig dependencies are correctly specified in ``.kunitconfig``.
|
||||
``kunit_config.py`` includes the parsing Kconfigs code. The code which
|
||||
runs ``make olddefconfig`` is a part of ``kunit_kernel.py``. You can
|
||||
invoke this command via: ``./tools/testing/kunit/kunit.py config`` and
|
||||
to ensure that ``.config`` is a superset of ``.kunitconfig``.
|
||||
If not, it will combine the two and run ``make olddefconfig`` to regenerate
|
||||
the ``.config`` file. It then checks to see if ``.config`` has become a superset.
|
||||
This verifies that all the Kconfig dependencies are correctly specified in the
|
||||
file ``.kunitconfig``. The ``kunit_config.py`` script contains the code for parsing
|
||||
Kconfigs. The code which runs ``make olddefconfig`` is part of the
|
||||
``kunit_kernel.py`` script. You can invoke this command through:
|
||||
``./tools/testing/kunit/kunit.py config`` and
|
||||
generate a ``.config`` file.
|
||||
- ``build`` runs ``make`` on the kernel tree with required options
|
||||
(depends on the architecture and some options, for example: build_dir)
|
||||
@@ -184,8 +185,8 @@ kunit_tool or can include KUnit in kernel and parse manually.
|
||||
To build a KUnit kernel from the current ``.config``, you can use the
|
||||
``build`` argument: ``./tools/testing/kunit/kunit.py build``.
|
||||
- ``exec`` command executes kernel results either directly (using
|
||||
User-mode Linux configuration), or via an emulator such
|
||||
as QEMU. It reads results from the log via standard
|
||||
User-mode Linux configuration), or through an emulator such
|
||||
as QEMU. It reads results from the log using standard
|
||||
output (stdout), and passes them to ``parse`` to be parsed.
|
||||
If you already have built a kernel with built-in KUnit tests,
|
||||
you can run the kernel and display the test results with the ``exec``
|
||||
|
||||
@@ -16,7 +16,6 @@ KUnit - Linux Kernel Unit Testing
|
||||
api/index
|
||||
style
|
||||
faq
|
||||
tips
|
||||
running_tips
|
||||
|
||||
This section details the kernel unit testing framework.
|
||||
@@ -100,14 +99,11 @@ Read also :ref:`kinds-of-tests`.
|
||||
How do I use it?
|
||||
================
|
||||
|
||||
* Documentation/dev-tools/kunit/start.rst - for KUnit new users.
|
||||
* Documentation/dev-tools/kunit/architecture.rst - KUnit architecture.
|
||||
* Documentation/dev-tools/kunit/run_wrapper.rst - run kunit_tool.
|
||||
* Documentation/dev-tools/kunit/run_manual.rst - run tests without kunit_tool.
|
||||
* Documentation/dev-tools/kunit/usage.rst - write tests.
|
||||
* Documentation/dev-tools/kunit/tips.rst - best practices with
|
||||
examples.
|
||||
* Documentation/dev-tools/kunit/api/index.rst - KUnit APIs
|
||||
used for testing.
|
||||
* Documentation/dev-tools/kunit/faq.rst - KUnit common questions and
|
||||
answers.
|
||||
You can find a step-by-step guide to writing and running KUnit tests in
|
||||
Documentation/dev-tools/kunit/start.rst
|
||||
|
||||
Alternatively, feel free to look through the rest of the KUnit documentation,
|
||||
or to experiment with tools/testing/kunit/kunit.py and the example test under
|
||||
lib/kunit/kunit-example-test.c
|
||||
|
||||
Happy testing!
|
||||
|
||||
@@ -294,13 +294,11 @@ Congrats! You just wrote your first KUnit test.
|
||||
Next Steps
|
||||
==========
|
||||
|
||||
* Documentation/dev-tools/kunit/architecture.rst - KUnit architecture.
|
||||
* Documentation/dev-tools/kunit/run_wrapper.rst - run kunit_tool.
|
||||
* Documentation/dev-tools/kunit/run_manual.rst - run tests without kunit_tool.
|
||||
* Documentation/dev-tools/kunit/usage.rst - write tests.
|
||||
* Documentation/dev-tools/kunit/tips.rst - best practices with
|
||||
examples.
|
||||
* Documentation/dev-tools/kunit/api/index.rst - KUnit APIs
|
||||
used for testing.
|
||||
* Documentation/dev-tools/kunit/faq.rst - KUnit common questions and
|
||||
answers.
|
||||
If you're interested in using some of the more advanced features of kunit.py,
|
||||
take a look at Documentation/dev-tools/kunit/run_wrapper.rst
|
||||
|
||||
If you'd like to run tests without using kunit.py, check out
|
||||
Documentation/dev-tools/kunit/run_manual.rst
|
||||
|
||||
For more information on writing KUnit tests (including some common techniques
|
||||
for testing different things), see Documentation/dev-tools/kunit/usage.rst
|
||||
|
||||
@@ -1,190 +0,0 @@
|
||||
.. SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
============================
|
||||
Tips For Writing KUnit Tests
|
||||
============================
|
||||
|
||||
Exiting early on failed expectations
|
||||
------------------------------------
|
||||
|
||||
``KUNIT_EXPECT_EQ`` and friends will mark the test as failed and continue
|
||||
execution. In some cases, it's unsafe to continue and you can use the
|
||||
``KUNIT_ASSERT`` variant to exit on failure.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
void example_test_user_alloc_function(struct kunit *test)
|
||||
{
|
||||
void *object = alloc_some_object_for_me();
|
||||
|
||||
/* Make sure we got a valid pointer back. */
|
||||
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, object);
|
||||
do_something_with_object(object);
|
||||
}
|
||||
|
||||
Allocating memory
|
||||
-----------------
|
||||
|
||||
Where you would use ``kzalloc``, you should prefer ``kunit_kzalloc`` instead.
|
||||
KUnit will ensure the memory is freed once the test completes.
|
||||
|
||||
This is particularly useful since it lets you use the ``KUNIT_ASSERT_EQ``
|
||||
macros to exit early from a test without having to worry about remembering to
|
||||
call ``kfree``.
|
||||
|
||||
Example:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
void example_test_allocation(struct kunit *test)
|
||||
{
|
||||
char *buffer = kunit_kzalloc(test, 16, GFP_KERNEL);
|
||||
/* Ensure allocation succeeded. */
|
||||
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, buffer);
|
||||
|
||||
KUNIT_ASSERT_STREQ(test, buffer, "");
|
||||
}
|
||||
|
||||
|
||||
Testing static functions
|
||||
------------------------
|
||||
|
||||
If you don't want to expose functions or variables just for testing, one option
|
||||
is to conditionally ``#include`` the test file at the end of your .c file, e.g.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
/* In my_file.c */
|
||||
|
||||
static int do_interesting_thing();
|
||||
|
||||
#ifdef CONFIG_MY_KUNIT_TEST
|
||||
#include "my_kunit_test.c"
|
||||
#endif
|
||||
|
||||
Injecting test-only code
|
||||
------------------------
|
||||
|
||||
Similarly to the above, it can be useful to add test-specific logic.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
/* In my_file.h */
|
||||
|
||||
#ifdef CONFIG_MY_KUNIT_TEST
|
||||
/* Defined in my_kunit_test.c */
|
||||
void test_only_hook(void);
|
||||
#else
|
||||
void test_only_hook(void) { }
|
||||
#endif
|
||||
|
||||
This test-only code can be made more useful by accessing the current kunit
|
||||
test, see below.
|
||||
|
||||
Accessing the current test
|
||||
--------------------------
|
||||
|
||||
In some cases, you need to call test-only code from outside the test file, e.g.
|
||||
like in the example above or if you're providing a fake implementation of an
|
||||
ops struct.
|
||||
There is a ``kunit_test`` field in ``task_struct``, so you can access it via
|
||||
``current->kunit_test``.
|
||||
|
||||
Here's a slightly in-depth example of how one could implement "mocking":
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
#include <linux/sched.h> /* for current */
|
||||
|
||||
struct test_data {
|
||||
int foo_result;
|
||||
int want_foo_called_with;
|
||||
};
|
||||
|
||||
static int fake_foo(int arg)
|
||||
{
|
||||
struct kunit *test = current->kunit_test;
|
||||
struct test_data *test_data = test->priv;
|
||||
|
||||
KUNIT_EXPECT_EQ(test, test_data->want_foo_called_with, arg);
|
||||
return test_data->foo_result;
|
||||
}
|
||||
|
||||
static void example_simple_test(struct kunit *test)
|
||||
{
|
||||
/* Assume priv is allocated in the suite's .init */
|
||||
struct test_data *test_data = test->priv;
|
||||
|
||||
test_data->foo_result = 42;
|
||||
test_data->want_foo_called_with = 1;
|
||||
|
||||
/* In a real test, we'd probably pass a pointer to fake_foo somewhere
|
||||
* like an ops struct, etc. instead of calling it directly. */
|
||||
KUNIT_EXPECT_EQ(test, fake_foo(1), 42);
|
||||
}
|
||||
|
||||
|
||||
Note: here we're able to get away with using ``test->priv``, but if you wanted
|
||||
something more flexible you could use a named ``kunit_resource``, see
|
||||
Documentation/dev-tools/kunit/api/test.rst.
|
||||
|
||||
Failing the current test
|
||||
------------------------
|
||||
|
||||
But sometimes, you might just want to fail the current test. In that case, we
|
||||
have ``kunit_fail_current_test(fmt, args...)`` which is defined in ``<kunit/test-bug.h>`` and
|
||||
doesn't require pulling in ``<kunit/test.h>``.
|
||||
|
||||
E.g. say we had an option to enable some extra debug checks on some data structure:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
#include <kunit/test-bug.h>
|
||||
|
||||
#ifdef CONFIG_EXTRA_DEBUG_CHECKS
|
||||
static void validate_my_data(struct data *data)
|
||||
{
|
||||
if (is_valid(data))
|
||||
return;
|
||||
|
||||
kunit_fail_current_test("data %p is invalid", data);
|
||||
|
||||
/* Normal, non-KUnit, error reporting code here. */
|
||||
}
|
||||
#else
|
||||
static void my_debug_function(void) { }
|
||||
#endif
|
||||
|
||||
|
||||
Customizing error messages
|
||||
--------------------------
|
||||
|
||||
Each of the ``KUNIT_EXPECT`` and ``KUNIT_ASSERT`` macros have a ``_MSG`` variant.
|
||||
These take a format string and arguments to provide additional context to the automatically generated error messages.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
char some_str[41];
|
||||
generate_sha1_hex_string(some_str);
|
||||
|
||||
/* Before. Not easy to tell why the test failed. */
|
||||
KUNIT_EXPECT_EQ(test, strlen(some_str), 40);
|
||||
|
||||
/* After. Now we see the offending string. */
|
||||
KUNIT_EXPECT_EQ_MSG(test, strlen(some_str), 40, "some_str='%s'", some_str);
|
||||
|
||||
Alternatively, one can take full control over the error message by using ``KUNIT_FAIL()``, e.g.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
/* Before */
|
||||
KUNIT_EXPECT_EQ(test, some_setup_function(), 0);
|
||||
|
||||
/* After: full control over the failure message. */
|
||||
if (some_setup_function())
|
||||
KUNIT_FAIL(test, "Failed to setup thing for testing");
|
||||
|
||||
Next Steps
|
||||
==========
|
||||
* Optional: see the Documentation/dev-tools/kunit/usage.rst page for a more
|
||||
in-depth explanation of KUnit.
|
||||
@@ -112,11 +112,45 @@ terminates the test case if the condition is not satisfied. For example:
|
||||
KUNIT_EXPECT_LE(test, a[i], a[i + 1]);
|
||||
}
|
||||
|
||||
In this example, the method under test should return pointer to a value. If the
|
||||
pointer returns null or an errno, we want to stop the test since the following
|
||||
expectation could crash the test case. `ASSERT_NOT_ERR_OR_NULL(...)` allows us
|
||||
to bail out of the test case if the appropriate conditions are not satisfied to
|
||||
complete the test.
|
||||
In this example, we need to be able to allocate an array to test the ``sort()``
|
||||
function. So we use ``KUNIT_ASSERT_NOT_ERR_OR_NULL()`` to abort the test if
|
||||
there's an allocation error.
|
||||
|
||||
.. note::
|
||||
In other test frameworks, ``ASSERT`` macros are often implemented by calling
|
||||
``return`` so they only work from the test function. In KUnit, we stop the
|
||||
current kthread on failure, so you can call them from anywhere.
|
||||
|
||||
Customizing error messages
|
||||
--------------------------
|
||||
|
||||
Each of the ``KUNIT_EXPECT`` and ``KUNIT_ASSERT`` macros have a ``_MSG``
|
||||
variant. These take a format string and arguments to provide additional
|
||||
context to the automatically generated error messages.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
char some_str[41];
|
||||
generate_sha1_hex_string(some_str);
|
||||
|
||||
/* Before. Not easy to tell why the test failed. */
|
||||
KUNIT_EXPECT_EQ(test, strlen(some_str), 40);
|
||||
|
||||
/* After. Now we see the offending string. */
|
||||
KUNIT_EXPECT_EQ_MSG(test, strlen(some_str), 40, "some_str='%s'", some_str);
|
||||
|
||||
Alternatively, one can take full control over the error message by using
|
||||
``KUNIT_FAIL()``, e.g.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
/* Before */
|
||||
KUNIT_EXPECT_EQ(test, some_setup_function(), 0);
|
||||
|
||||
/* After: full control over the failure message. */
|
||||
if (some_setup_function())
|
||||
KUNIT_FAIL(test, "Failed to setup thing for testing");
|
||||
|
||||
|
||||
Test Suites
|
||||
~~~~~~~~~~~
|
||||
@@ -546,24 +580,6 @@ By reusing the same ``cases`` array from above, we can write the test as a
|
||||
{}
|
||||
};
|
||||
|
||||
Exiting Early on Failed Expectations
|
||||
------------------------------------
|
||||
|
||||
We can use ``KUNIT_EXPECT_EQ`` to mark the test as failed and continue
|
||||
execution. In some cases, it is unsafe to continue. We can use the
|
||||
``KUNIT_ASSERT`` variant to exit on failure.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
void example_test_user_alloc_function(struct kunit *test)
|
||||
{
|
||||
void *object = alloc_some_object_for_me();
|
||||
|
||||
/* Make sure we got a valid pointer back. */
|
||||
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, object);
|
||||
do_something_with_object(object);
|
||||
}
|
||||
|
||||
Allocating Memory
|
||||
-----------------
|
||||
|
||||
@@ -625,17 +641,23 @@ as shown in next section: *Accessing The Current Test*.
|
||||
Accessing The Current Test
|
||||
--------------------------
|
||||
|
||||
In some cases, we need to call test-only code from outside the test file.
|
||||
For example, see example in section *Injecting Test-Only Code* or if
|
||||
we are providing a fake implementation of an ops struct. Using
|
||||
``kunit_test`` field in ``task_struct``, we can access it via
|
||||
``current->kunit_test``.
|
||||
In some cases, we need to call test-only code from outside the test file. This
|
||||
is helpful, for example, when providing a fake implementation of a function, or
|
||||
to fail any current test from within an error handler.
|
||||
We can do this via the ``kunit_test`` field in ``task_struct``, which we can
|
||||
access using the ``kunit_get_current_test()`` function in ``kunit/test-bug.h``.
|
||||
|
||||
The example below includes how to implement "mocking":
|
||||
``kunit_get_current_test()`` is safe to call even if KUnit is not enabled. If
|
||||
KUnit is not enabled, was built as a module (``CONFIG_KUNIT=m``), or no test is
|
||||
running in the current task, it will return ``NULL``. This compiles down to
|
||||
either a no-op or a static key check, so will have a negligible performance
|
||||
impact when no test is running.
|
||||
|
||||
The example below uses this to implement a "mock" implementation of a function, ``foo``:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
#include <linux/sched.h> /* for current */
|
||||
#include <kunit/test-bug.h> /* for kunit_get_current_test */
|
||||
|
||||
struct test_data {
|
||||
int foo_result;
|
||||
@@ -644,7 +666,7 @@ The example below includes how to implement "mocking":
|
||||
|
||||
static int fake_foo(int arg)
|
||||
{
|
||||
struct kunit *test = current->kunit_test;
|
||||
struct kunit *test = kunit_get_current_test();
|
||||
struct test_data *test_data = test->priv;
|
||||
|
||||
KUNIT_EXPECT_EQ(test, test_data->want_foo_called_with, arg);
|
||||
@@ -675,7 +697,7 @@ Each test can have multiple resources which have string names providing the same
|
||||
flexibility as a ``priv`` member, but also, for example, allowing helper
|
||||
functions to create resources without conflicting with each other. It is also
|
||||
possible to define a clean up function for each resource, making it easy to
|
||||
avoid resource leaks. For more information, see Documentation/dev-tools/kunit/api/test.rst.
|
||||
avoid resource leaks. For more information, see Documentation/dev-tools/kunit/api/resource.rst.
|
||||
|
||||
Failing The Current Test
|
||||
------------------------
|
||||
@@ -703,3 +725,9 @@ structures as shown below:
|
||||
static void my_debug_function(void) { }
|
||||
#endif
|
||||
|
||||
``kunit_fail_current_test()`` is safe to call even if KUnit is not enabled. If
|
||||
KUnit is not enabled, was built as a module (``CONFIG_KUNIT=m``), or no test is
|
||||
running in the current task, it will do nothing. This compiles down to either a
|
||||
no-op or a static key check, so will have a negligible performance impact when
|
||||
no test is running.
|
||||
|
||||
|
||||
@@ -315,7 +315,7 @@ static void drm_test_fb_xrgb8888_to_gray8(struct kunit *test)
|
||||
iosys_map_set_vaddr(&src, xrgb8888);
|
||||
|
||||
drm_fb_xrgb8888_to_gray8(&dst, &result->dst_pitch, &src, &fb, ¶ms->clip);
|
||||
KUNIT_EXPECT_EQ(test, memcmp(buf, result->expected, dst_size), 0);
|
||||
KUNIT_EXPECT_MEMEQ(test, buf, result->expected, dst_size);
|
||||
}
|
||||
|
||||
static void drm_test_fb_xrgb8888_to_rgb332(struct kunit *test)
|
||||
@@ -345,7 +345,7 @@ static void drm_test_fb_xrgb8888_to_rgb332(struct kunit *test)
|
||||
iosys_map_set_vaddr(&src, xrgb8888);
|
||||
|
||||
drm_fb_xrgb8888_to_rgb332(&dst, &result->dst_pitch, &src, &fb, ¶ms->clip);
|
||||
KUNIT_EXPECT_EQ(test, memcmp(buf, result->expected, dst_size), 0);
|
||||
KUNIT_EXPECT_MEMEQ(test, buf, result->expected, dst_size);
|
||||
}
|
||||
|
||||
static void drm_test_fb_xrgb8888_to_rgb565(struct kunit *test)
|
||||
@@ -375,10 +375,10 @@ static void drm_test_fb_xrgb8888_to_rgb565(struct kunit *test)
|
||||
iosys_map_set_vaddr(&src, xrgb8888);
|
||||
|
||||
drm_fb_xrgb8888_to_rgb565(&dst, &result->dst_pitch, &src, &fb, ¶ms->clip, false);
|
||||
KUNIT_EXPECT_EQ(test, memcmp(buf, result->expected, dst_size), 0);
|
||||
KUNIT_EXPECT_MEMEQ(test, buf, result->expected, dst_size);
|
||||
|
||||
drm_fb_xrgb8888_to_rgb565(&dst, &result->dst_pitch, &src, &fb, ¶ms->clip, true);
|
||||
KUNIT_EXPECT_EQ(test, memcmp(buf, result->expected_swab, dst_size), 0);
|
||||
KUNIT_EXPECT_MEMEQ(test, buf, result->expected_swab, dst_size);
|
||||
}
|
||||
|
||||
static void drm_test_fb_xrgb8888_to_rgb888(struct kunit *test)
|
||||
@@ -408,7 +408,7 @@ static void drm_test_fb_xrgb8888_to_rgb888(struct kunit *test)
|
||||
iosys_map_set_vaddr(&src, xrgb8888);
|
||||
|
||||
drm_fb_xrgb8888_to_rgb888(&dst, &result->dst_pitch, &src, &fb, ¶ms->clip);
|
||||
KUNIT_EXPECT_EQ(test, memcmp(buf, result->expected, dst_size), 0);
|
||||
KUNIT_EXPECT_MEMEQ(test, buf, result->expected, dst_size);
|
||||
}
|
||||
|
||||
static void drm_test_fb_xrgb8888_to_xrgb2101010(struct kunit *test)
|
||||
@@ -439,7 +439,7 @@ static void drm_test_fb_xrgb8888_to_xrgb2101010(struct kunit *test)
|
||||
|
||||
drm_fb_xrgb8888_to_xrgb2101010(&dst, &result->dst_pitch, &src, &fb, ¶ms->clip);
|
||||
buf = le32buf_to_cpu(test, buf, dst_size / sizeof(u32));
|
||||
KUNIT_EXPECT_EQ(test, memcmp(buf, result->expected, dst_size), 0);
|
||||
KUNIT_EXPECT_MEMEQ(test, buf, result->expected, dst_size);
|
||||
}
|
||||
|
||||
static struct kunit_case drm_format_helper_test_cases[] = {
|
||||
|
||||
@@ -90,19 +90,6 @@ void kunit_unary_assert_format(const struct kunit_assert *assert,
|
||||
const struct va_format *message,
|
||||
struct string_stream *stream);
|
||||
|
||||
/**
|
||||
* KUNIT_INIT_UNARY_ASSERT_STRUCT() - Initializes &struct kunit_unary_assert.
|
||||
* @cond: A string representation of the expression asserted true or false.
|
||||
* @expect_true: True if of type KUNIT_{EXPECT|ASSERT}_TRUE, false otherwise.
|
||||
*
|
||||
* Initializes a &struct kunit_unary_assert. Intended to be used in
|
||||
* KUNIT_EXPECT_* and KUNIT_ASSERT_* macros.
|
||||
*/
|
||||
#define KUNIT_INIT_UNARY_ASSERT_STRUCT(cond, expect_true) { \
|
||||
.condition = cond, \
|
||||
.expected_true = expect_true \
|
||||
}
|
||||
|
||||
/**
|
||||
* struct kunit_ptr_not_err_assert - An expectation/assertion that a pointer is
|
||||
* not NULL and not a -errno.
|
||||
@@ -123,20 +110,6 @@ void kunit_ptr_not_err_assert_format(const struct kunit_assert *assert,
|
||||
const struct va_format *message,
|
||||
struct string_stream *stream);
|
||||
|
||||
/**
|
||||
* KUNIT_INIT_PTR_NOT_ERR_ASSERT_STRUCT() - Initializes a
|
||||
* &struct kunit_ptr_not_err_assert.
|
||||
* @txt: A string representation of the expression passed to the expectation.
|
||||
* @val: The actual evaluated pointer value of the expression.
|
||||
*
|
||||
* Initializes a &struct kunit_ptr_not_err_assert. Intended to be used in
|
||||
* KUNIT_EXPECT_* and KUNIT_ASSERT_* macros.
|
||||
*/
|
||||
#define KUNIT_INIT_PTR_NOT_ERR_STRUCT(txt, val) { \
|
||||
.text = txt, \
|
||||
.value = val \
|
||||
}
|
||||
|
||||
/**
|
||||
* struct kunit_binary_assert_text - holds strings for &struct
|
||||
* kunit_binary_assert and friends to try and make the structs smaller.
|
||||
@@ -173,27 +146,6 @@ void kunit_binary_assert_format(const struct kunit_assert *assert,
|
||||
const struct va_format *message,
|
||||
struct string_stream *stream);
|
||||
|
||||
/**
|
||||
* KUNIT_INIT_BINARY_ASSERT_STRUCT() - Initializes a binary assert like
|
||||
* kunit_binary_assert, kunit_binary_ptr_assert, etc.
|
||||
*
|
||||
* @text_: Pointer to a kunit_binary_assert_text.
|
||||
* @left_val: The actual evaluated value of the expression in the left slot.
|
||||
* @right_val: The actual evaluated value of the expression in the right slot.
|
||||
*
|
||||
* Initializes a binary assert like kunit_binary_assert,
|
||||
* kunit_binary_ptr_assert, etc. This relies on these structs having the same
|
||||
* fields but with different types for left_val/right_val.
|
||||
* This is ultimately used by binary assertion macros like KUNIT_EXPECT_EQ, etc.
|
||||
*/
|
||||
#define KUNIT_INIT_BINARY_ASSERT_STRUCT(text_, \
|
||||
left_val, \
|
||||
right_val) { \
|
||||
.text = text_, \
|
||||
.left_value = left_val, \
|
||||
.right_value = right_val \
|
||||
}
|
||||
|
||||
/**
|
||||
* struct kunit_binary_ptr_assert - An expectation/assertion that compares two
|
||||
* pointer values (for example, KUNIT_EXPECT_PTR_EQ(test, foo, bar)).
|
||||
@@ -240,4 +192,30 @@ void kunit_binary_str_assert_format(const struct kunit_assert *assert,
|
||||
const struct va_format *message,
|
||||
struct string_stream *stream);
|
||||
|
||||
/**
|
||||
* struct kunit_mem_assert - An expectation/assertion that compares two
|
||||
* memory blocks.
|
||||
* @assert: The parent of this type.
|
||||
* @text: Holds the textual representations of the operands and comparator.
|
||||
* @left_value: The actual evaluated value of the expression in the left slot.
|
||||
* @right_value: The actual evaluated value of the expression in the right slot.
|
||||
* @size: Size of the memory block analysed in bytes.
|
||||
*
|
||||
* Represents an expectation/assertion that compares two memory blocks. For
|
||||
* example, to expect that the first three bytes of foo is equal to the
|
||||
* first three bytes of bar, you can use the expectation
|
||||
* KUNIT_EXPECT_MEMEQ(test, foo, bar, 3);
|
||||
*/
|
||||
struct kunit_mem_assert {
|
||||
struct kunit_assert assert;
|
||||
const struct kunit_binary_assert_text *text;
|
||||
const void *left_value;
|
||||
const void *right_value;
|
||||
const size_t size;
|
||||
};
|
||||
|
||||
void kunit_mem_assert_format(const struct kunit_assert *assert,
|
||||
const struct va_format *message,
|
||||
struct string_stream *stream);
|
||||
|
||||
#endif /* _KUNIT_ASSERT_H */
|
||||
|
||||
@@ -9,16 +9,63 @@
|
||||
#ifndef _KUNIT_TEST_BUG_H
|
||||
#define _KUNIT_TEST_BUG_H
|
||||
|
||||
#define kunit_fail_current_test(fmt, ...) \
|
||||
__kunit_fail_current_test(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
|
||||
|
||||
#if IS_BUILTIN(CONFIG_KUNIT)
|
||||
|
||||
#include <linux/jump_label.h> /* For static branch */
|
||||
#include <linux/sched.h>
|
||||
|
||||
/* Static key if KUnit is running any tests. */
|
||||
DECLARE_STATIC_KEY_FALSE(kunit_running);
|
||||
|
||||
/**
|
||||
* kunit_get_current_test() - Return a pointer to the currently running
|
||||
* KUnit test.
|
||||
*
|
||||
* If a KUnit test is running in the current task, returns a pointer to its
|
||||
* associated struct kunit. This pointer can then be passed to any KUnit
|
||||
* function or assertion. If no test is running (or a test is running in a
|
||||
* different task), returns NULL.
|
||||
*
|
||||
* This function is safe to call even when KUnit is disabled. If CONFIG_KUNIT
|
||||
* is not enabled, it will compile down to nothing and will return quickly no
|
||||
* test is running.
|
||||
*/
|
||||
static inline struct kunit *kunit_get_current_test(void)
|
||||
{
|
||||
if (!static_branch_unlikely(&kunit_running))
|
||||
return NULL;
|
||||
|
||||
return current->kunit_test;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* kunit_fail_current_test() - If a KUnit test is running, fail it.
|
||||
*
|
||||
* If a KUnit test is running in the current task, mark that test as failed.
|
||||
*
|
||||
* This macro will only work if KUnit is built-in (though the tests
|
||||
* themselves can be modules). Otherwise, it compiles down to nothing.
|
||||
*/
|
||||
#define kunit_fail_current_test(fmt, ...) do { \
|
||||
if (static_branch_unlikely(&kunit_running)) { \
|
||||
__kunit_fail_current_test(__FILE__, __LINE__, \
|
||||
fmt, ##__VA_ARGS__); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
|
||||
extern __printf(3, 4) void __kunit_fail_current_test(const char *file, int line,
|
||||
const char *fmt, ...);
|
||||
|
||||
#else
|
||||
|
||||
static inline struct kunit *kunit_get_current_test(void) { return NULL; }
|
||||
|
||||
/* We define this with an empty helper function so format string warnings work */
|
||||
#define kunit_fail_current_test(fmt, ...) \
|
||||
__kunit_fail_current_test(__FILE__, __LINE__, fmt, ##__VA_ARGS__)
|
||||
|
||||
static inline __printf(3, 4) void __kunit_fail_current_test(const char *file, int line,
|
||||
const char *fmt, ...)
|
||||
{
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include <linux/container_of.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/jump_label.h>
|
||||
#include <linux/kconfig.h>
|
||||
#include <linux/kref.h>
|
||||
#include <linux/list.h>
|
||||
@@ -27,6 +28,9 @@
|
||||
|
||||
#include <asm/rwonce.h>
|
||||
|
||||
/* Static key: true if any KUnit tests are currently running */
|
||||
DECLARE_STATIC_KEY_FALSE(kunit_running);
|
||||
|
||||
struct kunit;
|
||||
|
||||
/* Size of log associated with test. */
|
||||
@@ -515,22 +519,25 @@ void kunit_do_failed_assertion(struct kunit *test,
|
||||
fmt, \
|
||||
##__VA_ARGS__)
|
||||
|
||||
/* Helper to safely pass around an initializer list to other macros. */
|
||||
#define KUNIT_INIT_ASSERT(initializers...) { initializers }
|
||||
|
||||
#define KUNIT_UNARY_ASSERTION(test, \
|
||||
assert_type, \
|
||||
condition, \
|
||||
expected_true, \
|
||||
condition_, \
|
||||
expected_true_, \
|
||||
fmt, \
|
||||
...) \
|
||||
do { \
|
||||
if (likely(!!(condition) == !!expected_true)) \
|
||||
if (likely(!!(condition_) == !!expected_true_)) \
|
||||
break; \
|
||||
\
|
||||
_KUNIT_FAILED(test, \
|
||||
assert_type, \
|
||||
kunit_unary_assert, \
|
||||
kunit_unary_assert_format, \
|
||||
KUNIT_INIT_UNARY_ASSERT_STRUCT(#condition, \
|
||||
expected_true), \
|
||||
KUNIT_INIT_ASSERT(.condition = #condition_, \
|
||||
.expected_true = expected_true_), \
|
||||
fmt, \
|
||||
##__VA_ARGS__); \
|
||||
} while (0)
|
||||
@@ -590,9 +597,9 @@ do { \
|
||||
assert_type, \
|
||||
assert_class, \
|
||||
format_func, \
|
||||
KUNIT_INIT_BINARY_ASSERT_STRUCT(&__text, \
|
||||
__left, \
|
||||
__right), \
|
||||
KUNIT_INIT_ASSERT(.text = &__text, \
|
||||
.left_value = __left, \
|
||||
.right_value = __right), \
|
||||
fmt, \
|
||||
##__VA_ARGS__); \
|
||||
} while (0)
|
||||
@@ -651,9 +658,42 @@ do { \
|
||||
assert_type, \
|
||||
kunit_binary_str_assert, \
|
||||
kunit_binary_str_assert_format, \
|
||||
KUNIT_INIT_BINARY_ASSERT_STRUCT(&__text, \
|
||||
__left, \
|
||||
__right), \
|
||||
KUNIT_INIT_ASSERT(.text = &__text, \
|
||||
.left_value = __left, \
|
||||
.right_value = __right), \
|
||||
fmt, \
|
||||
##__VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
#define KUNIT_MEM_ASSERTION(test, \
|
||||
assert_type, \
|
||||
left, \
|
||||
op, \
|
||||
right, \
|
||||
size_, \
|
||||
fmt, \
|
||||
...) \
|
||||
do { \
|
||||
const void *__left = (left); \
|
||||
const void *__right = (right); \
|
||||
const size_t __size = (size_); \
|
||||
static const struct kunit_binary_assert_text __text = { \
|
||||
.operation = #op, \
|
||||
.left_text = #left, \
|
||||
.right_text = #right, \
|
||||
}; \
|
||||
\
|
||||
if (likely(memcmp(__left, __right, __size) op 0)) \
|
||||
break; \
|
||||
\
|
||||
_KUNIT_FAILED(test, \
|
||||
assert_type, \
|
||||
kunit_mem_assert, \
|
||||
kunit_mem_assert_format, \
|
||||
KUNIT_INIT_ASSERT(.text = &__text, \
|
||||
.left_value = __left, \
|
||||
.right_value = __right, \
|
||||
.size = __size), \
|
||||
fmt, \
|
||||
##__VA_ARGS__); \
|
||||
} while (0)
|
||||
@@ -673,7 +713,7 @@ do { \
|
||||
assert_type, \
|
||||
kunit_ptr_not_err_assert, \
|
||||
kunit_ptr_not_err_assert_format, \
|
||||
KUNIT_INIT_PTR_NOT_ERR_STRUCT(#ptr, __ptr), \
|
||||
KUNIT_INIT_ASSERT(.text = #ptr, .value = __ptr), \
|
||||
fmt, \
|
||||
##__VA_ARGS__); \
|
||||
} while (0)
|
||||
@@ -928,6 +968,60 @@ do { \
|
||||
fmt, \
|
||||
##__VA_ARGS__)
|
||||
|
||||
/**
|
||||
* KUNIT_EXPECT_MEMEQ() - Expects that the first @size bytes of @left and @right are equal.
|
||||
* @test: The test context object.
|
||||
* @left: An arbitrary expression that evaluates to the specified size.
|
||||
* @right: An arbitrary expression that evaluates to the specified size.
|
||||
* @size: Number of bytes compared.
|
||||
*
|
||||
* Sets an expectation that the values that @left and @right evaluate to are
|
||||
* equal. This is semantically equivalent to
|
||||
* KUNIT_EXPECT_TRUE(@test, !memcmp((@left), (@right), (@size))). See
|
||||
* KUNIT_EXPECT_TRUE() for more information.
|
||||
*
|
||||
* Although this expectation works for any memory block, it is not recommended
|
||||
* for comparing more structured data, such as structs. This expectation is
|
||||
* recommended for comparing, for example, data arrays.
|
||||
*/
|
||||
#define KUNIT_EXPECT_MEMEQ(test, left, right, size) \
|
||||
KUNIT_EXPECT_MEMEQ_MSG(test, left, right, size, NULL)
|
||||
|
||||
#define KUNIT_EXPECT_MEMEQ_MSG(test, left, right, size, fmt, ...) \
|
||||
KUNIT_MEM_ASSERTION(test, \
|
||||
KUNIT_EXPECTATION, \
|
||||
left, ==, right, \
|
||||
size, \
|
||||
fmt, \
|
||||
##__VA_ARGS__)
|
||||
|
||||
/**
|
||||
* KUNIT_EXPECT_MEMNEQ() - Expects that the first @size bytes of @left and @right are not equal.
|
||||
* @test: The test context object.
|
||||
* @left: An arbitrary expression that evaluates to the specified size.
|
||||
* @right: An arbitrary expression that evaluates to the specified size.
|
||||
* @size: Number of bytes compared.
|
||||
*
|
||||
* Sets an expectation that the values that @left and @right evaluate to are
|
||||
* not equal. This is semantically equivalent to
|
||||
* KUNIT_EXPECT_TRUE(@test, memcmp((@left), (@right), (@size))). See
|
||||
* KUNIT_EXPECT_TRUE() for more information.
|
||||
*
|
||||
* Although this expectation works for any memory block, it is not recommended
|
||||
* for comparing more structured data, such as structs. This expectation is
|
||||
* recommended for comparing, for example, data arrays.
|
||||
*/
|
||||
#define KUNIT_EXPECT_MEMNEQ(test, left, right, size) \
|
||||
KUNIT_EXPECT_MEMNEQ_MSG(test, left, right, size, NULL)
|
||||
|
||||
#define KUNIT_EXPECT_MEMNEQ_MSG(test, left, right, size, fmt, ...) \
|
||||
KUNIT_MEM_ASSERTION(test, \
|
||||
KUNIT_EXPECTATION, \
|
||||
left, !=, right, \
|
||||
size, \
|
||||
fmt, \
|
||||
##__VA_ARGS__)
|
||||
|
||||
/**
|
||||
* KUNIT_EXPECT_NULL() - Expects that @ptr is null.
|
||||
* @test: The test context object.
|
||||
|
||||
33
include/kunit/visibility.h
Normal file
33
include/kunit/visibility.h
Normal file
@@ -0,0 +1,33 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* KUnit API to allow symbols to be conditionally visible during KUnit
|
||||
* testing
|
||||
*
|
||||
* Copyright (C) 2022, Google LLC.
|
||||
* Author: Rae Moar <rmoar@google.com>
|
||||
*/
|
||||
|
||||
#ifndef _KUNIT_VISIBILITY_H
|
||||
#define _KUNIT_VISIBILITY_H
|
||||
|
||||
#if IS_ENABLED(CONFIG_KUNIT)
|
||||
/**
|
||||
* VISIBLE_IF_KUNIT - A macro that sets symbols to be static if
|
||||
* CONFIG_KUNIT is not enabled. Otherwise if CONFIG_KUNIT is enabled
|
||||
* there is no change to the symbol definition.
|
||||
*/
|
||||
#define VISIBLE_IF_KUNIT
|
||||
/**
|
||||
* EXPORT_SYMBOL_IF_KUNIT(symbol) - Exports symbol into
|
||||
* EXPORTED_FOR_KUNIT_TESTING namespace only if CONFIG_KUNIT is
|
||||
* enabled. Must use MODULE_IMPORT_NS(EXPORTED_FOR_KUNIT_TESTING)
|
||||
* in test file in order to use symbols.
|
||||
*/
|
||||
#define EXPORT_SYMBOL_IF_KUNIT(symbol) EXPORT_SYMBOL_NS(symbol, \
|
||||
EXPORTED_FOR_KUNIT_TESTING)
|
||||
#else
|
||||
#define VISIBLE_IF_KUNIT static
|
||||
#define EXPORT_SYMBOL_IF_KUNIT(symbol)
|
||||
#endif
|
||||
|
||||
#endif /* _KUNIT_VISIBILITY_H */
|
||||
@@ -127,13 +127,15 @@ void kunit_binary_assert_format(const struct kunit_assert *assert,
|
||||
binary_assert->text->right_text);
|
||||
if (!is_literal(stream->test, binary_assert->text->left_text,
|
||||
binary_assert->left_value, stream->gfp))
|
||||
string_stream_add(stream, KUNIT_SUBSUBTEST_INDENT "%s == %lld\n",
|
||||
string_stream_add(stream, KUNIT_SUBSUBTEST_INDENT "%s == %lld (0x%llx)\n",
|
||||
binary_assert->text->left_text,
|
||||
binary_assert->left_value,
|
||||
binary_assert->left_value);
|
||||
if (!is_literal(stream->test, binary_assert->text->right_text,
|
||||
binary_assert->right_value, stream->gfp))
|
||||
string_stream_add(stream, KUNIT_SUBSUBTEST_INDENT "%s == %lld",
|
||||
string_stream_add(stream, KUNIT_SUBSUBTEST_INDENT "%s == %lld (0x%llx)",
|
||||
binary_assert->text->right_text,
|
||||
binary_assert->right_value,
|
||||
binary_assert->right_value);
|
||||
kunit_assert_print_msg(message, stream);
|
||||
}
|
||||
@@ -204,3 +206,59 @@ void kunit_binary_str_assert_format(const struct kunit_assert *assert,
|
||||
kunit_assert_print_msg(message, stream);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(kunit_binary_str_assert_format);
|
||||
|
||||
/* Adds a hexdump of a buffer to a string_stream comparing it with
|
||||
* a second buffer. The different bytes are marked with <>.
|
||||
*/
|
||||
static void kunit_assert_hexdump(struct string_stream *stream,
|
||||
const void *buf,
|
||||
const void *compared_buf,
|
||||
const size_t len)
|
||||
{
|
||||
size_t i;
|
||||
const u8 *buf1 = buf;
|
||||
const u8 *buf2 = compared_buf;
|
||||
|
||||
string_stream_add(stream, KUNIT_SUBSUBTEST_INDENT);
|
||||
|
||||
for (i = 0; i < len; ++i) {
|
||||
if (!(i % 16) && i)
|
||||
string_stream_add(stream, "\n" KUNIT_SUBSUBTEST_INDENT);
|
||||
|
||||
if (buf1[i] != buf2[i])
|
||||
string_stream_add(stream, "<%02x>", buf1[i]);
|
||||
else
|
||||
string_stream_add(stream, " %02x ", buf1[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void kunit_mem_assert_format(const struct kunit_assert *assert,
|
||||
const struct va_format *message,
|
||||
struct string_stream *stream)
|
||||
{
|
||||
struct kunit_mem_assert *mem_assert;
|
||||
|
||||
mem_assert = container_of(assert, struct kunit_mem_assert,
|
||||
assert);
|
||||
|
||||
string_stream_add(stream,
|
||||
KUNIT_SUBTEST_INDENT "Expected %s %s %s, but\n",
|
||||
mem_assert->text->left_text,
|
||||
mem_assert->text->operation,
|
||||
mem_assert->text->right_text);
|
||||
|
||||
string_stream_add(stream, KUNIT_SUBSUBTEST_INDENT "%s ==\n",
|
||||
mem_assert->text->left_text);
|
||||
kunit_assert_hexdump(stream, mem_assert->left_value,
|
||||
mem_assert->right_value, mem_assert->size);
|
||||
|
||||
string_stream_add(stream, "\n");
|
||||
|
||||
string_stream_add(stream, KUNIT_SUBSUBTEST_INDENT "%s ==\n",
|
||||
mem_assert->text->right_text);
|
||||
kunit_assert_hexdump(stream, mem_assert->right_value,
|
||||
mem_assert->left_value, mem_assert->size);
|
||||
|
||||
kunit_assert_print_msg(message, stream);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(kunit_mem_assert_format);
|
||||
|
||||
@@ -63,7 +63,7 @@ static int debugfs_print_results(struct seq_file *seq, void *v)
|
||||
kunit_suite_for_each_test_case(suite, test_case)
|
||||
debugfs_print_result(seq, suite, test_case);
|
||||
|
||||
seq_printf(seq, "%s %d - %s\n",
|
||||
seq_printf(seq, "%s %d %s\n",
|
||||
kunit_status_to_ok_not_ok(success), 1, suite->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -166,7 +166,7 @@ static void kunit_exec_run_tests(struct suite_set *suite_set)
|
||||
{
|
||||
size_t num_suites = suite_set->end - suite_set->start;
|
||||
|
||||
pr_info("TAP version 14\n");
|
||||
pr_info("KTAP version 1\n");
|
||||
pr_info("1..%zu\n", num_suites);
|
||||
|
||||
__kunit_test_suites_init(suite_set->start, num_suites);
|
||||
@@ -177,8 +177,8 @@ static void kunit_exec_list_tests(struct suite_set *suite_set)
|
||||
struct kunit_suite * const *suites;
|
||||
struct kunit_case *test_case;
|
||||
|
||||
/* Hack: print a tap header so kunit.py can find the start of KUnit output. */
|
||||
pr_info("TAP version 14\n");
|
||||
/* Hack: print a ktap header so kunit.py can find the start of KUnit output. */
|
||||
pr_info("KTAP version 1\n");
|
||||
|
||||
for (suites = suite_set->start; suites < suite_set->end; suites++)
|
||||
kunit_suite_for_each_test_case((*suites), test_case) {
|
||||
|
||||
@@ -86,6 +86,9 @@ static void example_mark_skipped_test(struct kunit *test)
|
||||
*/
|
||||
static void example_all_expect_macros_test(struct kunit *test)
|
||||
{
|
||||
const u32 array1[] = { 0x0F, 0xFF };
|
||||
const u32 array2[] = { 0x1F, 0xFF };
|
||||
|
||||
/* Boolean assertions */
|
||||
KUNIT_EXPECT_TRUE(test, true);
|
||||
KUNIT_EXPECT_FALSE(test, false);
|
||||
@@ -109,6 +112,10 @@ static void example_all_expect_macros_test(struct kunit *test)
|
||||
KUNIT_EXPECT_STREQ(test, "hi", "hi");
|
||||
KUNIT_EXPECT_STRNEQ(test, "hi", "bye");
|
||||
|
||||
/* Memory block assertions */
|
||||
KUNIT_EXPECT_MEMEQ(test, array1, array1, sizeof(array1));
|
||||
KUNIT_EXPECT_MEMNEQ(test, array1, array2, sizeof(array1));
|
||||
|
||||
/*
|
||||
* There are also ASSERT variants of all of the above that abort test
|
||||
* execution if they fail. Useful for memory allocations, etc.
|
||||
|
||||
@@ -131,11 +131,6 @@ bool string_stream_is_empty(struct string_stream *stream)
|
||||
return list_empty(&stream->fragments);
|
||||
}
|
||||
|
||||
struct string_stream_alloc_context {
|
||||
struct kunit *test;
|
||||
gfp_t gfp;
|
||||
};
|
||||
|
||||
struct string_stream *alloc_string_stream(struct kunit *test, gfp_t gfp)
|
||||
{
|
||||
struct string_stream *stream;
|
||||
|
||||
@@ -20,6 +20,8 @@
|
||||
#include "string-stream.h"
|
||||
#include "try-catch-impl.h"
|
||||
|
||||
DEFINE_STATIC_KEY_FALSE(kunit_running);
|
||||
|
||||
#if IS_BUILTIN(CONFIG_KUNIT)
|
||||
/*
|
||||
* Fail the current test and print an error message to the log.
|
||||
@@ -149,6 +151,7 @@ EXPORT_SYMBOL_GPL(kunit_suite_num_test_cases);
|
||||
|
||||
static void kunit_print_suite_start(struct kunit_suite *suite)
|
||||
{
|
||||
kunit_log(KERN_INFO, suite, KUNIT_SUBTEST_INDENT "KTAP version 1\n");
|
||||
kunit_log(KERN_INFO, suite, KUNIT_SUBTEST_INDENT "# Subtest: %s",
|
||||
suite->name);
|
||||
kunit_log(KERN_INFO, suite, KUNIT_SUBTEST_INDENT "1..%zd",
|
||||
@@ -175,13 +178,13 @@ static void kunit_print_ok_not_ok(void *test_or_suite,
|
||||
* representation.
|
||||
*/
|
||||
if (suite)
|
||||
pr_info("%s %zd - %s%s%s\n",
|
||||
pr_info("%s %zd %s%s%s\n",
|
||||
kunit_status_to_ok_not_ok(status),
|
||||
test_number, description, directive_header,
|
||||
(status == KUNIT_SKIPPED) ? directive : "");
|
||||
else
|
||||
kunit_log(KERN_INFO, test,
|
||||
KUNIT_SUBTEST_INDENT "%s %zd - %s%s%s",
|
||||
KUNIT_SUBTEST_INDENT "%s %zd %s%s%s",
|
||||
kunit_status_to_ok_not_ok(status),
|
||||
test_number, description, directive_header,
|
||||
(status == KUNIT_SKIPPED) ? directive : "");
|
||||
@@ -542,6 +545,8 @@ int kunit_run_tests(struct kunit_suite *suite)
|
||||
/* Get initial param. */
|
||||
param_desc[0] = '\0';
|
||||
test.param_value = test_case->generate_params(NULL, param_desc);
|
||||
kunit_log(KERN_INFO, &test, KUNIT_SUBTEST_INDENT KUNIT_SUBTEST_INDENT
|
||||
"KTAP version 1\n");
|
||||
kunit_log(KERN_INFO, &test, KUNIT_SUBTEST_INDENT KUNIT_SUBTEST_INDENT
|
||||
"# Subtest: %s", test_case->name);
|
||||
|
||||
@@ -555,7 +560,7 @@ int kunit_run_tests(struct kunit_suite *suite)
|
||||
|
||||
kunit_log(KERN_INFO, &test,
|
||||
KUNIT_SUBTEST_INDENT KUNIT_SUBTEST_INDENT
|
||||
"%s %d - %s",
|
||||
"%s %d %s",
|
||||
kunit_status_to_ok_not_ok(test.status),
|
||||
test.param_index + 1, param_desc);
|
||||
|
||||
@@ -612,10 +617,14 @@ int __kunit_test_suites_init(struct kunit_suite * const * const suites, int num_
|
||||
return 0;
|
||||
}
|
||||
|
||||
static_branch_inc(&kunit_running);
|
||||
|
||||
for (i = 0; i < num_suites; i++) {
|
||||
kunit_init_suite(suites[i]);
|
||||
kunit_run_tests(suites[i]);
|
||||
}
|
||||
|
||||
static_branch_dec(&kunit_running);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__kunit_test_suites_init);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
#include <kunit/test.h>
|
||||
#include <kunit/test-bug.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
@@ -39,6 +39,7 @@
|
||||
#include <linux/memcontrol.h>
|
||||
#include <linux/random.h>
|
||||
#include <kunit/test.h>
|
||||
#include <kunit/test-bug.h>
|
||||
#include <linux/sort.h>
|
||||
|
||||
#include <linux/debugfs.h>
|
||||
@@ -618,7 +619,7 @@ static bool slab_add_kunit_errors(void)
|
||||
{
|
||||
struct kunit_resource *resource;
|
||||
|
||||
if (likely(!current->kunit_test))
|
||||
if (!kunit_get_current_test())
|
||||
return false;
|
||||
|
||||
resource = kunit_find_named_resource(current->kunit_test, "slab_errors");
|
||||
|
||||
@@ -71,11 +71,11 @@ static void dev_addr_test_basic(struct kunit *test)
|
||||
|
||||
memset(addr, 2, sizeof(addr));
|
||||
eth_hw_addr_set(netdev, addr);
|
||||
KUNIT_EXPECT_EQ(test, 0, memcmp(netdev->dev_addr, addr, sizeof(addr)));
|
||||
KUNIT_EXPECT_MEMEQ(test, netdev->dev_addr, addr, sizeof(addr));
|
||||
|
||||
memset(addr, 3, sizeof(addr));
|
||||
dev_addr_set(netdev, addr);
|
||||
KUNIT_EXPECT_EQ(test, 0, memcmp(netdev->dev_addr, addr, sizeof(addr)));
|
||||
KUNIT_EXPECT_MEMEQ(test, netdev->dev_addr, addr, sizeof(addr));
|
||||
}
|
||||
|
||||
static void dev_addr_test_sync_one(struct kunit *test)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user