diff options
Diffstat (limited to 'include/kunit')
| -rw-r--r-- | include/kunit/assert.h | 232 | ||||
| -rw-r--r-- | include/kunit/attributes.h | 50 | ||||
| -rw-r--r-- | include/kunit/clk.h | 33 | ||||
| -rw-r--r-- | include/kunit/device.h | 80 | ||||
| -rw-r--r-- | include/kunit/fwnode.h | 29 | ||||
| -rw-r--r-- | include/kunit/of.h | 121 | ||||
| -rw-r--r-- | include/kunit/platform_device.h | 27 | ||||
| -rw-r--r-- | include/kunit/resource.h | 503 | ||||
| -rw-r--r-- | include/kunit/run-in-irq-context.h | 158 | ||||
| -rw-r--r-- | include/kunit/skbuff.h | 57 | ||||
| -rw-r--r-- | include/kunit/static_stub.h | 113 | ||||
| -rw-r--r-- | include/kunit/test-bug.h | 97 | ||||
| -rw-r--r-- | include/kunit/test.h | 1898 | ||||
| -rw-r--r-- | include/kunit/try-catch.h | 63 | ||||
| -rw-r--r-- | include/kunit/visibility.h | 33 |
15 files changed, 3494 insertions, 0 deletions
diff --git a/include/kunit/assert.h b/include/kunit/assert.h new file mode 100644 index 000000000..bb879389f --- /dev/null +++ b/include/kunit/assert.h @@ -0,0 +1,232 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Assertion and expectation serialization API. + * + * Copyright (C) 2019, Google LLC. + * Author: Brendan Higgins <brendanhiggins@google.com> + */ + +#ifndef _KUNIT_ASSERT_H +#define _KUNIT_ASSERT_H + +#include <linux/err.h> +#include <linux/printk.h> + +struct kunit; +struct string_stream; + +/** + * enum kunit_assert_type - Type of expectation/assertion. + * @KUNIT_ASSERTION: Used to denote that a kunit_assert represents an assertion. + * @KUNIT_EXPECTATION: Denotes that a kunit_assert represents an expectation. + * + * Used in conjunction with a &struct kunit_assert to denote whether it + * represents an expectation or an assertion. + */ +enum kunit_assert_type { + KUNIT_ASSERTION, + KUNIT_EXPECTATION, +}; + +/** + * struct kunit_loc - Identifies the source location of a line of code. + * @line: the line number in the file. + * @file: the file name. + */ +struct kunit_loc { + int line; + const char *file; +}; + +#define KUNIT_CURRENT_LOC { .file = __FILE__, .line = __LINE__ } + +/** + * struct kunit_assert - Data for printing a failed assertion or expectation. + * + * Represents a failed expectation/assertion. Contains all the data necessary to + * format a string to a user reporting the failure. + */ +struct kunit_assert {}; + +typedef void (*assert_format_t)(const struct kunit_assert *assert, + const struct va_format *message, + struct string_stream *stream); + +void kunit_assert_prologue(const struct kunit_loc *loc, + enum kunit_assert_type type, + struct string_stream *stream); + +/** + * struct kunit_fail_assert - Represents a plain fail expectation/assertion. + * @assert: The parent of this type. + * + * Represents a simple KUNIT_FAIL/KUNIT_FAIL_AND_ABORT that always fails. + */ +struct kunit_fail_assert { + struct kunit_assert assert; +}; + +void kunit_fail_assert_format(const struct kunit_assert *assert, + const struct va_format *message, + struct string_stream *stream); + +/** + * struct kunit_unary_assert - Represents a KUNIT_{EXPECT|ASSERT}_{TRUE|FALSE} + * @assert: The parent of this type. + * @condition: A string representation of a conditional expression. + * @expected_true: True if of type KUNIT_{EXPECT|ASSERT}_TRUE, false otherwise. + * + * Represents a simple expectation or assertion that simply asserts something is + * true or false. In other words, represents the expectations: + * KUNIT_{EXPECT|ASSERT}_{TRUE|FALSE} + */ +struct kunit_unary_assert { + struct kunit_assert assert; + const char *condition; + bool expected_true; +}; + +void kunit_unary_assert_format(const struct kunit_assert *assert, + const struct va_format *message, + struct string_stream *stream); + +/** + * struct kunit_ptr_not_err_assert - An expectation/assertion that a pointer is + * not NULL and not a -errno. + * @assert: The parent of this type. + * @text: A string representation of the expression passed to the expectation. + * @value: The actual evaluated pointer value of the expression. + * + * Represents an expectation/assertion that a pointer is not null and is does + * not contain a -errno. (See IS_ERR_OR_NULL().) + */ +struct kunit_ptr_not_err_assert { + struct kunit_assert assert; + const char *text; + const void *value; +}; + +void kunit_ptr_not_err_assert_format(const struct kunit_assert *assert, + const struct va_format *message, + struct string_stream *stream); + +/** + * struct kunit_binary_assert_text - holds strings for &struct + * kunit_binary_assert and friends to try and make the structs smaller. + * @operation: A string representation of the comparison operator (e.g. "=="). + * @left_text: A string representation of the left expression (e.g. "2+2"). + * @right_text: A string representation of the right expression (e.g. "2+2"). + */ +struct kunit_binary_assert_text { + const char *operation; + const char *left_text; + const char *right_text; +}; + +/** + * struct kunit_binary_assert - An expectation/assertion that compares two + * non-pointer values (for example, KUNIT_EXPECT_EQ(test, 1 + 1, 2)). + * @assert: The parent of this type. + * @text: Holds the textual representations of the operands and op (e.g. "=="). + * @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. + * + * Represents an expectation/assertion that compares two non-pointer values. For + * example, to expect that 1 + 1 == 2, you can use the expectation + * KUNIT_EXPECT_EQ(test, 1 + 1, 2); + */ +struct kunit_binary_assert { + struct kunit_assert assert; + const struct kunit_binary_assert_text *text; + long long left_value; + long long right_value; +}; + +void kunit_binary_assert_format(const struct kunit_assert *assert, + const struct va_format *message, + struct string_stream *stream); + +/** + * struct kunit_binary_ptr_assert - An expectation/assertion that compares two + * pointer values (for example, KUNIT_EXPECT_PTR_EQ(test, foo, bar)). + * @assert: The parent of this type. + * @text: Holds the textual representations of the operands and op (e.g. "=="). + * @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. + * + * Represents an expectation/assertion that compares two pointer values. For + * example, to expect that foo and bar point to the same thing, you can use the + * expectation KUNIT_EXPECT_PTR_EQ(test, foo, bar); + */ +struct kunit_binary_ptr_assert { + struct kunit_assert assert; + const struct kunit_binary_assert_text *text; + const void *left_value; + const void *right_value; +}; + +void kunit_binary_ptr_assert_format(const struct kunit_assert *assert, + const struct va_format *message, + struct string_stream *stream); + +/** + * struct kunit_binary_str_assert - An expectation/assertion that compares two + * string values (for example, KUNIT_EXPECT_STREQ(test, foo, "bar")). + * @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. + * + * Represents an expectation/assertion that compares two string values. For + * example, to expect that the string in foo is equal to "bar", you can use the + * expectation KUNIT_EXPECT_STREQ(test, foo, "bar"); + */ +struct kunit_binary_str_assert { + struct kunit_assert assert; + const struct kunit_binary_assert_text *text; + const char *left_value; + const char *right_value; +}; + +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); + +#if IS_ENABLED(CONFIG_KUNIT) +void kunit_assert_print_msg(const struct va_format *message, + struct string_stream *stream); +bool is_literal(const char *text, long long value); +bool is_str_literal(const char *text, const char *value); +void kunit_assert_hexdump(struct string_stream *stream, + const void *buf, + const void *compared_buf, + const size_t len); +#endif + +#endif /* _KUNIT_ASSERT_H */ diff --git a/include/kunit/attributes.h b/include/kunit/attributes.h new file mode 100644 index 000000000..bc76a0b78 --- /dev/null +++ b/include/kunit/attributes.h @@ -0,0 +1,50 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * KUnit API to save and access test attributes + * + * Copyright (C) 2023, Google LLC. + * Author: Rae Moar <rmoar@google.com> + */ + +#ifndef _KUNIT_ATTRIBUTES_H +#define _KUNIT_ATTRIBUTES_H + +/* + * struct kunit_attr_filter - representation of attributes filter with the + * attribute object and string input + */ +struct kunit_attr_filter { + struct kunit_attr *attr; + char *input; +}; + +/* + * Returns the name of the filter's attribute. + */ +const char *kunit_attr_filter_name(struct kunit_attr_filter filter); + +/* + * Print all test attributes for a test case or suite. + * Output format for test cases: "# <test_name>.<attribute>: <value>" + * Output format for test suites: "# <attribute>: <value>" + */ +void kunit_print_attr(void *test_or_suite, bool is_test, unsigned int test_level); + +/* + * Returns the number of fitlers in input. + */ +int kunit_get_filter_count(char *input); + +/* + * Parse attributes filter input and return an objects containing the + * attribute object and the string input of the next filter. + */ +struct kunit_attr_filter kunit_next_attr_filter(char **filters, int *err); + +/* + * Returns a copy of the suite containing only tests that pass the filter. + */ +struct kunit_suite *kunit_filter_attr_tests(const struct kunit_suite *const suite, + struct kunit_attr_filter filter, char *action, int *err); + +#endif /* _KUNIT_ATTRIBUTES_H */ diff --git a/include/kunit/clk.h b/include/kunit/clk.h new file mode 100644 index 000000000..f226044cc --- /dev/null +++ b/include/kunit/clk.h @@ -0,0 +1,33 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _CLK_KUNIT_H +#define _CLK_KUNIT_H + +struct clk; +struct clk_hw; +struct device; +struct device_node; +struct of_phandle_args; +struct kunit; + +struct clk * +clk_get_kunit(struct kunit *test, struct device *dev, const char *con_id); +struct clk * +of_clk_get_kunit(struct kunit *test, struct device_node *np, int index); + +struct clk * +clk_hw_get_clk_kunit(struct kunit *test, struct clk_hw *hw, const char *con_id); +struct clk * +clk_hw_get_clk_prepared_enabled_kunit(struct kunit *test, struct clk_hw *hw, + const char *con_id); + +int clk_prepare_enable_kunit(struct kunit *test, struct clk *clk); + +int clk_hw_register_kunit(struct kunit *test, struct device *dev, struct clk_hw *hw); +int of_clk_hw_register_kunit(struct kunit *test, struct device_node *node, + struct clk_hw *hw); + +int of_clk_add_hw_provider_kunit(struct kunit *test, struct device_node *np, + struct clk_hw *(*get)(struct of_phandle_args *clkspec, void *data), + void *data); + +#endif diff --git a/include/kunit/device.h b/include/kunit/device.h new file mode 100644 index 000000000..2450110ad --- /dev/null +++ b/include/kunit/device.h @@ -0,0 +1,80 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * KUnit basic device implementation + * + * Helpers for creating and managing fake devices for KUnit tests. + * + * Copyright (C) 2023, Google LLC. + * Author: David Gow <davidgow@google.com> + */ + +#ifndef _KUNIT_DEVICE_H +#define _KUNIT_DEVICE_H + +#if IS_ENABLED(CONFIG_KUNIT) + +#include <kunit/test.h> + +struct device; +struct device_driver; + +/** + * kunit_driver_create() - Create a struct device_driver attached to the kunit_bus + * @test: The test context object. + * @name: The name to give the created driver. + * + * Creates a struct device_driver attached to the kunit_bus, with the name @name. + * This driver will automatically be cleaned up on test exit. + * + * Return: a stub struct device_driver, managed by KUnit, with the name @name. + */ +struct device_driver *kunit_driver_create(struct kunit *test, const char *name); + +/** + * kunit_device_register() - Create a struct device for use in KUnit tests + * @test: The test context object. + * @name: The name to give the created device. + * + * Creates a struct kunit_device (which is a struct device) with the given name, + * and a corresponding driver. The device and driver will be cleaned up on test + * exit, or when kunit_device_unregister is called. See also + * kunit_device_register_with_driver, if you wish to provide your own + * struct device_driver. + * + * Return: a pointer to a struct device which will be cleaned up when the test + * exits, or an error pointer if the device could not be allocated or registered. + */ +struct device *kunit_device_register(struct kunit *test, const char *name); + +/** + * kunit_device_register_with_driver() - Create a struct device for use in KUnit tests + * @test: The test context object. + * @name: The name to give the created device. + * @drv: The struct device_driver to associate with the device. + * + * Creates a struct kunit_device (which is a struct device) with the given + * name, and driver. The device will be cleaned up on test exit, or when + * kunit_device_unregister is called. See also kunit_device_register, if you + * wish KUnit to create and manage a driver for you. + * + * Return: a pointer to a struct device which will be cleaned up when the test + * exits, or an error pointer if the device could not be allocated or registered. + */ +struct device *kunit_device_register_with_driver(struct kunit *test, + const char *name, + const struct device_driver *drv); + +/** + * kunit_device_unregister() - Unregister a KUnit-managed device + * @test: The test context object which created the device + * @dev: The device. + * + * Unregisters and destroys a struct device which was created with + * kunit_device_register or kunit_device_register_with_driver. If KUnit created + * a driver, cleans it up as well. + */ +void kunit_device_unregister(struct kunit *test, struct device *dev); + +#endif + +#endif diff --git a/include/kunit/fwnode.h b/include/kunit/fwnode.h new file mode 100644 index 000000000..e250bb87e --- /dev/null +++ b/include/kunit/fwnode.h @@ -0,0 +1,29 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * KUnit resource management helpers for firmware nodes. + * + * Copyright (C) Qualcomm Technologies, Inc. and/or its subsidiaries + */ + +#ifndef _KUNIT_FWNODE_H +#define _KUNIT_FWNODE_H + +struct device; +struct fwnode_handle; +struct kunit; +struct property_entry; +struct software_node; + +struct fwnode_handle * +kunit_fwnode_create_software_node(struct kunit *test, + const struct property_entry *properties, + const struct fwnode_handle *parent); +struct fwnode_handle * +kunit_software_node_register(struct kunit *test, + const struct software_node *node); +int kunit_software_node_register_node_group(struct kunit *test, + const struct software_node *const *nodes); +int kunit_device_add_software_node(struct kunit *test, struct device *dev, + const struct software_node *node); + +#endif /* _KUNIT_FWNODE_H */ diff --git a/include/kunit/of.h b/include/kunit/of.h new file mode 100644 index 000000000..75a760a4e --- /dev/null +++ b/include/kunit/of.h @@ -0,0 +1,121 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _KUNIT_OF_H +#define _KUNIT_OF_H + +#include <kunit/test.h> + +struct device_node; + +#ifdef CONFIG_OF + +void of_node_put_kunit(struct kunit *test, struct device_node *node); + +#else + +static inline +void of_node_put_kunit(struct kunit *test, struct device_node *node) +{ + kunit_skip(test, "requires CONFIG_OF"); +} + +#endif /* !CONFIG_OF */ + +#if defined(CONFIG_OF) && defined(CONFIG_OF_OVERLAY) && defined(CONFIG_OF_EARLY_FLATTREE) + +int of_overlay_fdt_apply_kunit(struct kunit *test, void *overlay_fdt, + u32 overlay_fdt_size, int *ovcs_id); +#else + +static inline int +of_overlay_fdt_apply_kunit(struct kunit *test, void *overlay_fdt, + u32 overlay_fdt_size, int *ovcs_id) +{ + kunit_skip(test, "requires CONFIG_OF and CONFIG_OF_OVERLAY and CONFIG_OF_EARLY_FLATTREE for root node"); + return -EINVAL; +} + +#endif + +/** + * __of_overlay_apply_kunit() - Test managed of_overlay_fdt_apply() variant + * @test: test context + * @overlay_begin: start address of overlay to apply + * @overlay_end: end address of overlay to apply + * + * This is mostly internal API. See of_overlay_apply_kunit() for the wrapper + * that makes this easier to use. + * + * Similar to of_overlay_fdt_apply(), except the overlay is managed by the test + * case and is automatically removed with of_overlay_remove() after the test + * case concludes. + * + * Return: 0 on success, negative errno on failure + */ +static inline int __of_overlay_apply_kunit(struct kunit *test, + u8 *overlay_begin, + const u8 *overlay_end) +{ + int unused; + + return of_overlay_fdt_apply_kunit(test, overlay_begin, + overlay_end - overlay_begin, + &unused); +} + +#define of_overlay_begin(overlay_name) __dtbo_##overlay_name##_begin +#define of_overlay_end(overlay_name) __dtbo_##overlay_name##_end + +#define OF_OVERLAY_DECLARE(overlay_name) \ + extern uint8_t of_overlay_begin(overlay_name)[]; \ + extern uint8_t of_overlay_end(overlay_name)[] \ + +/** + * of_overlay_apply_kunit() - Test managed of_overlay_fdt_apply() for built-in overlays + * @test: test context + * @overlay_name: name of overlay to apply + * + * This macro is used to apply a device tree overlay built with the + * cmd_dt_S_dtbo rule in scripts/Makefile.lib that has been compiled into the + * kernel image or KUnit test module. The overlay is automatically removed when + * the test is finished. + * + * Unit tests that need device tree nodes should compile an overlay file with + * @overlay_name\.dtbo.o in their Makefile along with their unit test and then + * load the overlay during their test. The @overlay_name matches the filename + * of the overlay without the dtbo filename extension. If CONFIG_OF_OVERLAY is + * not enabled, the @test will be skipped. + * + * In the Makefile + * + * .. code-block:: none + * + * obj-$(CONFIG_OF_OVERLAY_KUNIT_TEST) += overlay_test.o kunit_overlay_test.dtbo.o + * + * In the test + * + * .. code-block:: c + * + * static void of_overlay_kunit_of_overlay_apply(struct kunit *test) + * { + * struct device_node *np; + * + * KUNIT_ASSERT_EQ(test, 0, + * of_overlay_apply_kunit(test, kunit_overlay_test)); + * + * np = of_find_node_by_name(NULL, "test-kunit"); + * KUNIT_EXPECT_NOT_ERR_OR_NULL(test, np); + * of_node_put(np); + * } + * + * Return: 0 on success, negative errno on failure. + */ +#define of_overlay_apply_kunit(test, overlay_name) \ +({ \ + OF_OVERLAY_DECLARE(overlay_name); \ + \ + __of_overlay_apply_kunit((test), \ + of_overlay_begin(overlay_name), \ + of_overlay_end(overlay_name)); \ +}) + +#endif diff --git a/include/kunit/platform_device.h b/include/kunit/platform_device.h new file mode 100644 index 000000000..eee565d5d --- /dev/null +++ b/include/kunit/platform_device.h @@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _KUNIT_PLATFORM_DRIVER_H +#define _KUNIT_PLATFORM_DRIVER_H + +struct completion; +struct kunit; +struct platform_device; +struct platform_driver; +struct platform_device_info; + +struct platform_device * +kunit_platform_device_alloc(struct kunit *test, const char *name, int id); +int kunit_platform_device_add(struct kunit *test, struct platform_device *pdev); +struct platform_device * +kunit_platform_device_register_full(struct kunit *test, + const struct platform_device_info *pdevinfo); +void kunit_platform_device_unregister(struct kunit *test, + struct platform_device *pdev); + +int kunit_platform_device_prepare_wait_for_probe(struct kunit *test, + struct platform_device *pdev, + struct completion *x); + +int kunit_platform_driver_register(struct kunit *test, + struct platform_driver *drv); + +#endif diff --git a/include/kunit/resource.h b/include/kunit/resource.h new file mode 100644 index 000000000..c330ed3e7 --- /dev/null +++ b/include/kunit/resource.h @@ -0,0 +1,503 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * KUnit resource API for test managed resources (allocations, etc.). + * + * Copyright (C) 2022, Google LLC. + * Author: Daniel Latypov <dlatypov@google.com> + */ + +#ifndef _KUNIT_RESOURCE_H +#define _KUNIT_RESOURCE_H + +#include <kunit/test.h> + +#include <linux/kref.h> +#include <linux/list.h> +#include <linux/slab.h> +#include <linux/spinlock.h> + +struct kunit_resource; + +typedef int (*kunit_resource_init_t)(struct kunit_resource *, void *); +typedef void (*kunit_resource_free_t)(struct kunit_resource *); + +/** + * struct kunit_resource - represents a *test managed resource* + * @data: for the user to store arbitrary data. + * @name: optional name + * @free: a user supplied function to free the resource. + * + * Represents a *test managed resource*, a resource which will automatically be + * cleaned up at the end of a test case. This cleanup is performed by the 'free' + * function. The struct kunit_resource itself is freed automatically with + * kfree() if it was allocated by KUnit (e.g., by kunit_alloc_resource()), but + * must be freed by the user otherwise. + * + * Resources are reference counted so if a resource is retrieved via + * kunit_alloc_and_get_resource() or kunit_find_resource(), we need + * to call kunit_put_resource() to reduce the resource reference count + * when finished with it. Note that kunit_alloc_resource() does not require a + * kunit_resource_put() because it does not retrieve the resource itself. + * + * Example: + * + * .. code-block:: c + * + * struct kunit_kmalloc_params { + * size_t size; + * gfp_t gfp; + * }; + * + * static int kunit_kmalloc_init(struct kunit_resource *res, void *context) + * { + * struct kunit_kmalloc_params *params = context; + * res->data = kmalloc(params->size, params->gfp); + * + * if (!res->data) + * return -ENOMEM; + * + * return 0; + * } + * + * static void kunit_kmalloc_free(struct kunit_resource *res) + * { + * kfree(res->data); + * } + * + * void *kunit_kmalloc(struct kunit *test, size_t size, gfp_t gfp) + * { + * struct kunit_kmalloc_params params; + * + * params.size = size; + * params.gfp = gfp; + * + * return kunit_alloc_resource(test, kunit_kmalloc_init, + * kunit_kmalloc_free, gfp, ¶ms); + * } + * + * Resources can also be named, with lookup/removal done on a name + * basis also. kunit_add_named_resource(), kunit_find_named_resource() + * and kunit_destroy_named_resource(). Resource names must be + * unique within the test instance. + */ +struct kunit_resource { + void *data; + const char *name; + kunit_resource_free_t free; + + /* private: internal use only. */ + struct kref refcount; + struct list_head node; + bool should_kfree; +}; + +/** + * kunit_get_resource() - Hold resource for use. Should not need to be used + * by most users as we automatically get resources + * retrieved by kunit_find_resource*(). + * @res: resource + */ +static inline void kunit_get_resource(struct kunit_resource *res) +{ + kref_get(&res->refcount); +} + +/* + * Called when refcount reaches zero via kunit_put_resource(); + * should not be called directly. + */ +static inline void kunit_release_resource(struct kref *kref) +{ + struct kunit_resource *res = container_of(kref, struct kunit_resource, + refcount); + + if (res->free) + res->free(res); + + /* 'res' is valid here, as if should_kfree is set, res->free may not free + * 'res' itself, just res->data + */ + if (res->should_kfree) + kfree(res); +} + +/** + * kunit_put_resource() - When caller is done with retrieved resource, + * kunit_put_resource() should be called to drop + * reference count. The resource list maintains + * a reference count on resources, so if no users + * are utilizing a resource and it is removed from + * the resource list, it will be freed via the + * associated free function (if any). Only + * needs to be used if we alloc_and_get() or + * find() resource. + * @res: resource + */ +static inline void kunit_put_resource(struct kunit_resource *res) +{ + kref_put(&res->refcount, kunit_release_resource); +} + +/** + * __kunit_add_resource() - Internal helper to add a resource. + * + * res->should_kfree is not initialised. + * @test: The test context object. + * @init: a user-supplied function to initialize the result (if needed). If + * none is supplied, the resource data value is simply set to @data. + * If an init function is supplied, @data is passed to it instead. + * @free: a user-supplied function to free the resource (if needed). + * @res: The resource. + * @data: value to pass to init function or set in resource data field. + */ +int __kunit_add_resource(struct kunit *test, + kunit_resource_init_t init, + kunit_resource_free_t free, + struct kunit_resource *res, + void *data); + +/** + * kunit_add_resource() - Add a *test managed resource*. + * @test: The test context object. + * @init: a user-supplied function to initialize the result (if needed). If + * none is supplied, the resource data value is simply set to @data. + * If an init function is supplied, @data is passed to it instead. + * @free: a user-supplied function to free the resource (if needed). + * @res: The resource. + * @data: value to pass to init function or set in resource data field. + */ +static inline int kunit_add_resource(struct kunit *test, + kunit_resource_init_t init, + kunit_resource_free_t free, + struct kunit_resource *res, + void *data) +{ + res->should_kfree = false; + return __kunit_add_resource(test, init, free, res, data); +} + +static inline struct kunit_resource * +kunit_find_named_resource(struct kunit *test, const char *name); + +/** + * kunit_add_named_resource() - Add a named *test managed resource*. + * @test: The test context object. + * @init: a user-supplied function to initialize the resource data, if needed. + * @free: a user-supplied function to free the resource data, if needed. + * @res: The resource. + * @name: name to be set for resource. + * @data: value to pass to init function or set in resource data field. + */ +static inline int kunit_add_named_resource(struct kunit *test, + kunit_resource_init_t init, + kunit_resource_free_t free, + struct kunit_resource *res, + const char *name, + void *data) +{ + struct kunit_resource *existing; + + if (!name) + return -EINVAL; + + existing = kunit_find_named_resource(test, name); + if (existing) { + kunit_put_resource(existing); + return -EEXIST; + } + + res->name = name; + res->should_kfree = false; + + return __kunit_add_resource(test, init, free, res, data); +} + +/** + * kunit_alloc_and_get_resource() - Allocates and returns a *test managed resource*. + * @test: The test context object. + * @init: a user supplied function to initialize the resource. + * @free: a user supplied function to free the resource (if needed). + * @internal_gfp: gfp to use for internal allocations, if unsure, use GFP_KERNEL + * @context: for the user to pass in arbitrary data to the init function. + * + * Allocates a *test managed resource*, a resource which will automatically be + * cleaned up at the end of a test case. See &struct kunit_resource for an + * example. + * + * This is effectively identical to kunit_alloc_resource, but returns the + * struct kunit_resource pointer, not just the 'data' pointer. It therefore + * also increments the resource's refcount, so kunit_put_resource() should be + * called when you've finished with it. + * + * Note: KUnit needs to allocate memory for a kunit_resource object. You must + * specify an @internal_gfp that is compatible with the use context of your + * resource. + */ +static inline struct kunit_resource * +kunit_alloc_and_get_resource(struct kunit *test, + kunit_resource_init_t init, + kunit_resource_free_t free, + gfp_t internal_gfp, + void *context) +{ + struct kunit_resource *res; + int ret; + + res = kzalloc_obj(*res, internal_gfp); + if (!res) + return NULL; + + res->should_kfree = true; + + ret = __kunit_add_resource(test, init, free, res, context); + if (!ret) { + /* + * bump refcount for get; kunit_resource_put() should be called + * when done. + */ + kunit_get_resource(res); + return res; + } + return NULL; +} + +/** + * kunit_alloc_resource() - Allocates a *test managed resource*. + * @test: The test context object. + * @init: a user supplied function to initialize the resource. + * @free: a user supplied function to free the resource (if needed). + * @internal_gfp: gfp to use for internal allocations, if unsure, use GFP_KERNEL + * @context: for the user to pass in arbitrary data to the init function. + * + * Allocates a *test managed resource*, a resource which will automatically be + * cleaned up at the end of a test case. See &struct kunit_resource for an + * example. + * + * Note: KUnit needs to allocate memory for a kunit_resource object. You must + * specify an @internal_gfp that is compatible with the use context of your + * resource. + */ +static inline void *kunit_alloc_resource(struct kunit *test, + kunit_resource_init_t init, + kunit_resource_free_t free, + gfp_t internal_gfp, + void *context) +{ + struct kunit_resource *res; + + res = kzalloc_obj(*res, internal_gfp); + if (!res) + return NULL; + + res->should_kfree = true; + if (!__kunit_add_resource(test, init, free, res, context)) + return res->data; + + return NULL; +} + +typedef bool (*kunit_resource_match_t)(struct kunit *test, + struct kunit_resource *res, + void *match_data); + +/** + * kunit_resource_name_match() - Match a resource with the same name. + * @test: Test case to which the resource belongs. + * @res: The resource. + * @match_name: The name to match against. + */ +static inline bool kunit_resource_name_match(struct kunit *test, + struct kunit_resource *res, + void *match_name) +{ + return res->name && strcmp(res->name, match_name) == 0; +} + +/** + * kunit_find_resource() - Find a resource using match function/data. + * @test: Test case to which the resource belongs. + * @match: match function to be applied to resources/match data. + * @match_data: data to be used in matching. + */ +static inline struct kunit_resource * +kunit_find_resource(struct kunit *test, + kunit_resource_match_t match, + void *match_data) +{ + struct kunit_resource *res, *found = NULL; + unsigned long flags; + + spin_lock_irqsave(&test->lock, flags); + + list_for_each_entry_reverse(res, &test->resources, node) { + if (match(test, res, (void *)match_data)) { + found = res; + kunit_get_resource(found); + break; + } + } + + spin_unlock_irqrestore(&test->lock, flags); + + return found; +} + +/** + * kunit_find_named_resource() - Find a resource using match name. + * @test: Test case to which the resource belongs. + * @name: match name. + */ +static inline struct kunit_resource * +kunit_find_named_resource(struct kunit *test, + const char *name) +{ + return kunit_find_resource(test, kunit_resource_name_match, + (void *)name); +} + +/** + * kunit_destroy_resource() - Find a kunit_resource and destroy it. + * @test: Test case to which the resource belongs. + * @match: Match function. Returns whether a given resource matches @match_data. + * @match_data: Data passed into @match. + * + * RETURNS: + * 0 if kunit_resource is found and freed, -ENOENT if not found. + */ +int kunit_destroy_resource(struct kunit *test, + kunit_resource_match_t match, + void *match_data); + +static inline int kunit_destroy_named_resource(struct kunit *test, + const char *name) +{ + return kunit_destroy_resource(test, kunit_resource_name_match, + (void *)name); +} + +/** + * kunit_remove_resource() - remove resource from resource list associated with + * test. + * @test: The test context object. + * @res: The resource to be removed. + * + * Note that the resource will not be immediately freed since it is likely + * the caller has a reference to it via alloc_and_get() or find(); + * in this case a final call to kunit_put_resource() is required. + */ +void kunit_remove_resource(struct kunit *test, struct kunit_resource *res); + +/* A 'deferred action' function to be used with kunit_add_action. */ +typedef void (kunit_action_t)(void *); + +/** + * KUNIT_DEFINE_ACTION_WRAPPER() - Wrap a function for use as a deferred action. + * + * @wrapper: The name of the new wrapper function define. + * @orig: The original function to wrap. + * @arg_type: The type of the argument accepted by @orig. + * + * Defines a wrapper for a function which accepts a single, pointer-sized + * argument. This wrapper can then be passed to kunit_add_action() and + * similar. This should be used in preference to casting a function + * directly to kunit_action_t, as casting function pointers will break + * control flow integrity (CFI), leading to crashes. + */ +#define KUNIT_DEFINE_ACTION_WRAPPER(wrapper, orig, arg_type) \ + static void wrapper(void *in) \ + { \ + arg_type arg = (arg_type)in; \ + orig(arg); \ + } + + +/** + * kunit_add_action() - Call a function when the test ends. + * @test: Test case to associate the action with. + * @action: The function to run on test exit + * @ctx: Data passed into @func + * + * Defer the execution of a function until the test exits, either normally or + * due to a failure. @ctx is passed as additional context. All functions + * registered with kunit_add_action() will execute in the opposite order to that + * they were registered in. + * + * This is useful for cleaning up allocated memory and resources, as these + * functions are called even if the test aborts early due to, e.g., a failed + * assertion. + * + * See also: devm_add_action() for the devres equivalent. + * + * Returns: + * 0 on success, an error if the action could not be deferred. + */ +int kunit_add_action(struct kunit *test, kunit_action_t *action, void *ctx); + +/** + * kunit_add_action_or_reset() - Call a function when the test ends. + * @test: Test case to associate the action with. + * @action: The function to run on test exit + * @ctx: Data passed into @func + * + * Defer the execution of a function until the test exits, either normally or + * due to a failure. @ctx is passed as additional context. All functions + * registered with kunit_add_action() will execute in the opposite order to that + * they were registered in. + * + * This is useful for cleaning up allocated memory and resources, as these + * functions are called even if the test aborts early due to, e.g., a failed + * assertion. + * + * If the action cannot be created (e.g., due to the system being out of memory), + * then action(ctx) will be called immediately, and an error will be returned. + * + * See also: devm_add_action_or_reset() for the devres equivalent. + * + * Returns: + * 0 on success, an error if the action could not be deferred. + */ +int kunit_add_action_or_reset(struct kunit *test, kunit_action_t *action, + void *ctx); + +/** + * kunit_remove_action() - Cancel a matching deferred action. + * @test: Test case the action is associated with. + * @action: The deferred function to cancel. + * @ctx: The context passed to the deferred function to trigger. + * + * Prevent an action deferred via kunit_add_action() from executing when the + * test terminates. + * + * If the function/context pair was deferred multiple times, only the most + * recent one will be cancelled. + * + * See also: devm_remove_action() for the devres equivalent. + */ +void kunit_remove_action(struct kunit *test, + kunit_action_t *action, + void *ctx); + +/** + * kunit_release_action() - Run a matching action call immediately. + * @test: Test case the action is associated with. + * @action: The deferred function to trigger. + * @ctx: The context passed to the deferred function to trigger. + * + * Execute a function deferred via kunit_add_action()) immediately, rather than + * when the test ends. + * + * If the function/context pair was deferred multiple times, it will only be + * executed once here. The most recent deferral will no longer execute when + * the test ends. + * + * kunit_release_action(test, func, ctx); + * is equivalent to + * func(ctx); + * kunit_remove_action(test, func, ctx); + * + * See also: devm_release_action() for the devres equivalent. + */ +void kunit_release_action(struct kunit *test, + kunit_action_t *action, + void *ctx); +#endif /* _KUNIT_RESOURCE_H */ diff --git a/include/kunit/run-in-irq-context.h b/include/kunit/run-in-irq-context.h new file mode 100644 index 000000000..b46fa1696 --- /dev/null +++ b/include/kunit/run-in-irq-context.h @@ -0,0 +1,158 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Helper function for testing code in interrupt contexts + * + * Copyright 2025 Google LLC + */ +#ifndef _KUNIT_RUN_IN_IRQ_CONTEXT_H +#define _KUNIT_RUN_IN_IRQ_CONTEXT_H + +#include <kunit/test.h> +#include <linux/timekeeping.h> +#include <linux/hrtimer.h> +#include <linux/workqueue.h> + +struct kunit_irq_test_state { + bool (*func)(void *test_specific_state); + void *test_specific_state; + bool task_func_reported_failure; + bool hardirq_func_reported_failure; + bool softirq_func_reported_failure; + atomic_t task_func_calls; + atomic_t hardirq_func_calls; + atomic_t softirq_func_calls; + ktime_t interval; + struct hrtimer timer; + struct work_struct bh_work; +}; + +static enum hrtimer_restart kunit_irq_test_timer_func(struct hrtimer *timer) +{ + struct kunit_irq_test_state *state = + container_of(timer, typeof(*state), timer); + int task_calls, hardirq_calls, softirq_calls; + + WARN_ON_ONCE(!in_hardirq()); + task_calls = atomic_read(&state->task_func_calls); + hardirq_calls = atomic_inc_return(&state->hardirq_func_calls); + softirq_calls = atomic_read(&state->softirq_func_calls); + + /* + * If the hrtimer is running much faster than the bh_work or the task, + * then it is firing too fast and might be starving those contexts as + * well as the actual system timer tick. Increase the interval. + */ + if (hardirq_calls >= 20 && + (hardirq_calls / 2 > softirq_calls || + hardirq_calls / 2 > task_calls)) + state->interval = ktime_add_ns(state->interval, 250); + + if (!state->func(state->test_specific_state)) + state->hardirq_func_reported_failure = true; + + hrtimer_forward_now(&state->timer, state->interval); + queue_work(system_bh_wq, &state->bh_work); + return HRTIMER_RESTART; +} + +static void kunit_irq_test_bh_work_func(struct work_struct *work) +{ + struct kunit_irq_test_state *state = + container_of(work, typeof(*state), bh_work); + + WARN_ON_ONCE(!in_serving_softirq()); + atomic_inc(&state->softirq_func_calls); + + if (!state->func(state->test_specific_state)) + state->softirq_func_reported_failure = true; +} + +/* + * Helper function which repeatedly runs the given @func in task, softirq, and + * hardirq context concurrently, and reports a failure to KUnit if any + * invocation of @func in any context returns false. @func is passed + * @test_specific_state as its argument. At most 3 invocations of @func will + * run concurrently: one in each of task, softirq, and hardirq context. @func + * will continue running until either @max_iterations calls have been made (so + * long as at least one each runs in task, softirq, and hardirq contexts), or + * one second has passed. + * + * The main purpose of this interrupt context testing is to validate fallback + * code paths that run in contexts where the normal code path cannot be used, + * typically due to the FPU or vector registers already being in-use in kernel + * mode. These code paths aren't covered when the test code is executed only by + * the KUnit test runner thread in task context. The reason for the concurrency + * is because merely using hardirq context is not sufficient to reach a fallback + * code path on some architectures; the hardirq actually has to occur while the + * FPU or vector unit was already in-use in kernel mode. + * + * Another purpose of this testing is to detect issues with the architecture's + * irq_fpu_usable() and kernel_fpu_begin/end() or equivalent functions, + * especially in softirq context when the softirq may have interrupted a task + * already using kernel-mode FPU or vector (if the arch didn't prevent that). + * Crypto functions are often executed in softirqs, so this is important. + */ +static inline void kunit_run_irq_test(struct kunit *test, bool (*func)(void *), + int max_iterations, + void *test_specific_state) +{ + struct kunit_irq_test_state state = { + .func = func, + .test_specific_state = test_specific_state, + /* + * Start with a 5us timer interval. If the system can't keep + * up, kunit_irq_test_timer_func() will increase it. + */ + .interval = us_to_ktime(5), + }; + unsigned long end_jiffies; + int task_calls, hardirq_calls, softirq_calls; + + /* + * Set up a hrtimer (the way we access hardirq context) and a work + * struct for the BH workqueue (the way we access softirq context). + */ + hrtimer_setup_on_stack(&state.timer, kunit_irq_test_timer_func, + CLOCK_MONOTONIC, HRTIMER_MODE_REL_HARD); + INIT_WORK_ONSTACK(&state.bh_work, kunit_irq_test_bh_work_func); + + /* + * Run for up to max_iterations (including at least one task, softirq, + * and hardirq), or 1 second, whichever comes first. + */ + end_jiffies = jiffies + HZ; + hrtimer_start(&state.timer, state.interval, HRTIMER_MODE_REL_HARD); + do { + if (!func(test_specific_state)) + state.task_func_reported_failure = true; + + task_calls = atomic_inc_return(&state.task_func_calls); + hardirq_calls = atomic_read(&state.hardirq_func_calls); + softirq_calls = atomic_read(&state.softirq_func_calls); + } while ((task_calls + hardirq_calls + softirq_calls < max_iterations || + (task_calls == 0 || hardirq_calls == 0 || + softirq_calls == 0)) && + !time_after(jiffies, end_jiffies)); + + /* Cancel the timer and work. */ + hrtimer_cancel(&state.timer); + flush_work(&state.bh_work); + destroy_hrtimer_on_stack(&state.timer); + destroy_work_on_stack(&state.bh_work); + + /* Sanity check: the timer and BH functions should have been run. */ + KUNIT_EXPECT_GT_MSG(test, atomic_read(&state.hardirq_func_calls), 0, + "Timer function was not called"); + KUNIT_EXPECT_GT_MSG(test, atomic_read(&state.softirq_func_calls), 0, + "BH work function was not called"); + + /* Check for failure reported from any context. */ + KUNIT_EXPECT_FALSE_MSG(test, state.task_func_reported_failure, + "Failure reported from task context"); + KUNIT_EXPECT_FALSE_MSG(test, state.hardirq_func_reported_failure, + "Failure reported from hardirq context"); + KUNIT_EXPECT_FALSE_MSG(test, state.softirq_func_reported_failure, + "Failure reported from softirq context"); +} + +#endif /* _KUNIT_RUN_IN_IRQ_CONTEXT_H */ diff --git a/include/kunit/skbuff.h b/include/kunit/skbuff.h new file mode 100644 index 000000000..077846943 --- /dev/null +++ b/include/kunit/skbuff.h @@ -0,0 +1,57 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * KUnit resource management helpers for SKBs (skbuff). + * + * Copyright (C) 2023 Intel Corporation + */ + +#ifndef _KUNIT_SKBUFF_H +#define _KUNIT_SKBUFF_H + +#include <kunit/resource.h> +#include <linux/skbuff.h> + +static void kunit_action_kfree_skb(void *p) +{ + kfree_skb((struct sk_buff *)p); +} + +/** + * kunit_zalloc_skb() - Allocate and initialize a resource managed skb. + * @test: The test case to which the skb belongs + * @len: size to allocate + * @gfp: allocation flags + * + * Allocate a new struct sk_buff with gfp flags, zero fill the given length + * and add it as a resource to the kunit test for automatic cleanup. + * + * Returns: newly allocated SKB, or %NULL on error + */ +static inline struct sk_buff *kunit_zalloc_skb(struct kunit *test, int len, + gfp_t gfp) +{ + struct sk_buff *res = alloc_skb(len, gfp); + + if (!res || skb_pad(res, len)) + return NULL; + + if (kunit_add_action_or_reset(test, kunit_action_kfree_skb, res)) + return NULL; + + return res; +} + +/** + * kunit_kfree_skb() - Like kfree_skb except for allocations managed by KUnit. + * @test: The test case to which the resource belongs. + * @skb: The SKB to free. + */ +static inline void kunit_kfree_skb(struct kunit *test, struct sk_buff *skb) +{ + if (!skb) + return; + + kunit_release_action(test, kunit_action_kfree_skb, (void *)skb); +} + +#endif /* _KUNIT_SKBUFF_H */ diff --git a/include/kunit/static_stub.h b/include/kunit/static_stub.h new file mode 100644 index 000000000..bf940322d --- /dev/null +++ b/include/kunit/static_stub.h @@ -0,0 +1,113 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * KUnit function redirection (static stubbing) API. + * + * Copyright (C) 2022, Google LLC. + * Author: David Gow <davidgow@google.com> + */ +#ifndef _KUNIT_STATIC_STUB_H +#define _KUNIT_STATIC_STUB_H + +#if !IS_ENABLED(CONFIG_KUNIT) + +/* If CONFIG_KUNIT is not enabled, these stubs quietly disappear. */ +#define KUNIT_STATIC_STUB_REDIRECT(real_fn_name, args...) do {} while (0) + +#else + +#include <kunit/test.h> +#include <kunit/test-bug.h> + +#include <linux/compiler.h> /* for {un,}likely() */ +#include <linux/sched.h> /* for task_struct */ + + +/** + * KUNIT_STATIC_STUB_REDIRECT() - call a replacement 'static stub' if one exists + * @real_fn_name: The name of this function (as an identifier, not a string) + * @args: All of the arguments passed to this function + * + * This is a function prologue which is used to allow calls to the current + * function to be redirected by a KUnit test. KUnit tests can call + * kunit_activate_static_stub() to pass a replacement function in. The + * replacement function will be called by KUNIT_STATIC_STUB_REDIRECT(), which + * will then return from the function. If the caller is not in a KUnit context, + * the function will continue execution as normal. + * + * Example: + * + * .. code-block:: c + * + * int real_func(int n) + * { + * KUNIT_STATIC_STUB_REDIRECT(real_func, n); + * return 0; + * } + * + * int replacement_func(int n) + * { + * return 42; + * } + * + * void example_test(struct kunit *test) + * { + * kunit_activate_static_stub(test, real_func, replacement_func); + * KUNIT_EXPECT_EQ(test, real_func(1), 42); + * } + * + */ +#define KUNIT_STATIC_STUB_REDIRECT(real_fn_name, args...) \ +do { \ + typeof(&real_fn_name) replacement; \ + struct kunit *current_test = kunit_get_current_test(); \ + \ + if (likely(!current_test)) \ + break; \ + \ + replacement = kunit_hooks.get_static_stub_address(current_test, \ + &real_fn_name); \ + \ + if (unlikely(replacement)) \ + return replacement(args); \ +} while (0) + +/* Helper function for kunit_activate_static_stub(). The macro does + * typechecking, so use it instead. + */ +void __kunit_activate_static_stub(struct kunit *test, + void *real_fn_addr, + void *replacement_addr); + +/** + * kunit_activate_static_stub() - replace a function using static stubs. + * @test: A pointer to the 'struct kunit' test context for the current test. + * @real_fn_addr: The address of the function to replace. + * @replacement_addr: The address of the function to replace it with. + * + * When activated, calls to real_fn_addr from within this test (even if called + * indirectly) will instead call replacement_addr. The function pointed to by + * real_fn_addr must begin with the static stub prologue in + * KUNIT_STATIC_STUB_REDIRECT() for this to work. real_fn_addr and + * replacement_addr must have the same type. + * + * The redirection can be disabled again with kunit_deactivate_static_stub(). + */ +#define kunit_activate_static_stub(test, real_fn_addr, replacement_addr) do { \ + typecheck_fn(typeof(&replacement_addr), real_fn_addr); \ + __kunit_activate_static_stub(test, real_fn_addr, replacement_addr); \ +} while (0) + + +/** + * kunit_deactivate_static_stub() - disable a function redirection + * @test: A pointer to the 'struct kunit' test context for the current test. + * @real_fn_addr: The address of the function to no-longer redirect + * + * Deactivates a redirection configured with kunit_activate_static_stub(). After + * this function returns, calls to real_fn_addr() will execute the original + * real_fn, not any previously-configured replacement. + */ +void kunit_deactivate_static_stub(struct kunit *test, void *real_fn_addr); + +#endif +#endif diff --git a/include/kunit/test-bug.h b/include/kunit/test-bug.h new file mode 100644 index 000000000..99869029f --- /dev/null +++ b/include/kunit/test-bug.h @@ -0,0 +1,97 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * KUnit API providing hooks for non-test code to interact with tests. + * + * Copyright (C) 2020, Google LLC. + * Author: Uriel Guajardo <urielguajardo@google.com> + */ + +#ifndef _KUNIT_TEST_BUG_H +#define _KUNIT_TEST_BUG_H + +#include <linux/stddef.h> /* for NULL */ +#include <linux/types.h> /* for bool */ + +#if IS_ENABLED(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); + +/* Hooks table: a table of function pointers filled in when kunit loads */ +extern struct kunit_hooks_table { + __printf(3, 4) void (*fail_current_test)(const char*, int, const char*, ...); + void *(*get_static_stub_address)(struct kunit *test, void *real_fn_addr); + bool (*is_suppressed_warning)(bool count); +} kunit_hooks; + +/** + * 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. + */ +#define kunit_fail_current_test(fmt, ...) do { \ + if (static_branch_unlikely(&kunit_running)) { \ + /* Guaranteed to be non-NULL when kunit_running true*/ \ + kunit_hooks.fail_current_test(__FILE__, __LINE__, \ + fmt, ##__VA_ARGS__); \ + } \ + } while (0) + +/** + * kunit_is_suppressed_warning() - Check if warnings are being suppressed + * by the current KUnit test. + * @count: if true, increment the suppression counter on match. + * + * Returns true if the current task has active warning suppression. + * Uses the kunit_running static branch for zero overhead when no tests run. + * + * A single WARN*() may traverse multiple call sites in the warning path + * (e.g., __warn_printk() and __report_bug()). Pass @count = true at the + * primary suppression point to count each warning exactly once, and + * @count = false at secondary points to suppress output without + * inflating the count. + */ +static inline bool kunit_is_suppressed_warning(bool count) +{ + if (!static_branch_unlikely(&kunit_running)) + return false; + + return kunit_hooks.is_suppressed_warning && + kunit_hooks.is_suppressed_warning(count); +} + +#else + +static inline struct kunit *kunit_get_current_test(void) { return NULL; } +static inline bool kunit_is_suppressed_warning(bool count) { return false; } + +#define kunit_fail_current_test(fmt, ...) do {} while (0) + +#endif + +#endif /* _KUNIT_TEST_BUG_H */ diff --git a/include/kunit/test.h b/include/kunit/test.h new file mode 100644 index 000000000..da5312e0d --- /dev/null +++ b/include/kunit/test.h @@ -0,0 +1,1898 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Base unit test (KUnit) API. + * + * Copyright (C) 2019, Google LLC. + * Author: Brendan Higgins <brendanhiggins@google.com> + */ + +#ifndef _KUNIT_TEST_H +#define _KUNIT_TEST_H + +#include <kunit/assert.h> +#include <kunit/try-catch.h> + +#include <linux/args.h> +#include <linux/compiler.h> +#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> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/spinlock.h> +#include <linux/string.h> +#include <linux/types.h> + +#include <asm/rwonce.h> +#include <asm/sections.h> + +/* Static key: true if any KUnit tests are currently running */ +DECLARE_STATIC_KEY_FALSE(kunit_running); + +struct kunit; +struct string_stream; + +/* Maximum size of parameter description string. */ +#define KUNIT_PARAM_DESC_SIZE 128 + +/* Maximum size of a status comment. */ +#define KUNIT_STATUS_COMMENT_SIZE 256 + +/* + * TAP specifies subtest stream indentation of 4 spaces, 8 spaces for a + * sub-subtest. See the "Subtests" section in + * https://node-tap.org/tap-protocol/ + */ +#define KUNIT_INDENT_LEN 4 +#define KUNIT_SUBTEST_INDENT " " +#define KUNIT_SUBSUBTEST_INDENT " " + +/** + * enum kunit_status - Type of result for a test or test suite + * @KUNIT_SUCCESS: Denotes the test suite has not failed nor been skipped + * @KUNIT_FAILURE: Denotes the test has failed. + * @KUNIT_SKIPPED: Denotes the test has been skipped. + */ +enum kunit_status { + KUNIT_SUCCESS, + KUNIT_FAILURE, + KUNIT_SKIPPED, +}; + +/* Attribute struct/enum definitions */ + +/* + * Speed Attribute is stored as an enum and separated into categories of + * speed: very_slow, slow, and normal. These speeds are relative to + * other KUnit tests. + * + * Note: unset speed attribute acts as default of KUNIT_SPEED_NORMAL. + */ +enum kunit_speed { + KUNIT_SPEED_UNSET, + KUNIT_SPEED_VERY_SLOW, + KUNIT_SPEED_SLOW, + KUNIT_SPEED_NORMAL, + KUNIT_SPEED_MAX = KUNIT_SPEED_NORMAL, +}; + +/* Holds attributes for each test case and suite */ +struct kunit_attributes { + enum kunit_speed speed; +}; + +/** + * struct kunit_case - represents an individual test case. + * + * @run_case: the function representing the actual test case. + * @name: the name of the test case. + * @generate_params: the generator function for parameterized tests. + * @attr: the attributes associated with the test + * @param_init: The init function to run before a parameterized test. + * @param_exit: The exit function to run after a parameterized test. + * + * A test case is a function with the signature, + * ``void (*)(struct kunit *)`` + * that makes expectations and assertions (see KUNIT_EXPECT_TRUE() and + * KUNIT_ASSERT_TRUE()) about code under test. Each test case is associated + * with a &struct kunit_suite and will be run after the suite's init + * function and followed by the suite's exit function. + * + * A test case should be static and should only be created with the + * KUNIT_CASE() macro; additionally, every array of test cases should be + * terminated with an empty test case. + * + * Example: + * + * .. code-block:: c + * + * void add_test_basic(struct kunit *test) + * { + * KUNIT_EXPECT_EQ(test, 1, add(1, 0)); + * KUNIT_EXPECT_EQ(test, 2, add(1, 1)); + * KUNIT_EXPECT_EQ(test, 0, add(-1, 1)); + * KUNIT_EXPECT_EQ(test, INT_MAX, add(0, INT_MAX)); + * KUNIT_EXPECT_EQ(test, -1, add(INT_MAX, INT_MIN)); + * } + * + * static struct kunit_case example_test_cases[] = { + * KUNIT_CASE(add_test_basic), + * {} + * }; + * + */ +struct kunit_case { + void (*run_case)(struct kunit *test); + const char *name; + const void* (*generate_params)(struct kunit *test, + const void *prev, char *desc); + struct kunit_attributes attr; + int (*param_init)(struct kunit *test); + void (*param_exit)(struct kunit *test); + + /* private: internal use only. */ + enum kunit_status status; + char *module_name; + struct string_stream *log; +}; + +static inline char *kunit_status_to_ok_not_ok(enum kunit_status status) +{ + switch (status) { + case KUNIT_SKIPPED: + case KUNIT_SUCCESS: + return "ok"; + case KUNIT_FAILURE: + return "not ok"; + } + return "invalid"; +} + +/** + * KUNIT_CASE - A helper for creating a &struct kunit_case + * + * @test_name: a reference to a test case function. + * + * Takes a symbol for a function representing a test case and creates a + * &struct kunit_case object from it. See the documentation for + * &struct kunit_case for an example on how to use it. + */ +#define KUNIT_CASE(test_name) \ + { .run_case = test_name, .name = #test_name, \ + .module_name = KBUILD_MODNAME} + +/** + * KUNIT_CASE_ATTR - A helper for creating a &struct kunit_case + * with attributes + * + * @test_name: a reference to a test case function. + * @attributes: a reference to a struct kunit_attributes object containing + * test attributes + */ +#define KUNIT_CASE_ATTR(test_name, attributes) \ + { .run_case = test_name, .name = #test_name, \ + .attr = attributes, .module_name = KBUILD_MODNAME} + +/** + * KUNIT_CASE_SLOW - A helper for creating a &struct kunit_case + * with the slow attribute + * + * @test_name: a reference to a test case function. + */ + +#define KUNIT_CASE_SLOW(test_name) \ + { .run_case = test_name, .name = #test_name, \ + .attr.speed = KUNIT_SPEED_SLOW, .module_name = KBUILD_MODNAME} + +/** + * KUNIT_CASE_PARAM - A helper for creation a parameterized &struct kunit_case + * + * @test_name: a reference to a test case function. + * @gen_params: a reference to a parameter generator function. + * + * The generator function:: + * + * const void* gen_params(const void *prev, char *desc) + * + * is used to lazily generate a series of arbitrarily typed values that fit into + * a void*. The argument @prev is the previously returned value, which should be + * used to derive the next value; @prev is set to NULL on the initial generator + * call. When no more values are available, the generator must return NULL. + * Optionally write a string into @desc (size of KUNIT_PARAM_DESC_SIZE) + * describing the parameter. + */ +#define KUNIT_CASE_PARAM(test_name, gen_params) \ + { .run_case = test_name, .name = #test_name, \ + .generate_params = gen_params, .module_name = KBUILD_MODNAME} + +/** + * KUNIT_CASE_PARAM_ATTR - A helper for creating a parameterized &struct + * kunit_case with attributes + * + * @test_name: a reference to a test case function. + * @gen_params: a reference to a parameter generator function. + * @attributes: a reference to a struct kunit_attributes object containing + * test attributes + */ +#define KUNIT_CASE_PARAM_ATTR(test_name, gen_params, attributes) \ + { .run_case = test_name, .name = #test_name, \ + .generate_params = gen_params, \ + .attr = attributes, .module_name = KBUILD_MODNAME} + +/** + * KUNIT_CASE_PARAM_WITH_INIT - Define a parameterized KUnit test case with custom + * param_init() and param_exit() functions. + * @test_name: The function implementing the test case. + * @gen_params: The function to generate parameters for the test case. + * @init: A reference to the param_init() function to run before a parameterized test. + * @exit: A reference to the param_exit() function to run after a parameterized test. + * + * Provides the option to register param_init() and param_exit() functions. + * param_init/exit will be passed the parameterized test context and run once + * before and once after the parameterized test. The init function can be used + * to add resources to share between parameter runs, pass parameter arrays, + * and any other setup logic. The exit function can be used to clean up resources + * that were not managed by the parameterized test, and any other teardown logic. + * + * Note: If you are registering a parameter array in param_init() with + * kunit_register_param_array() then you need to pass kunit_array_gen_params() + * to this as the generator function. + */ +#define KUNIT_CASE_PARAM_WITH_INIT(test_name, gen_params, init, exit) \ + { .run_case = test_name, .name = #test_name, \ + .generate_params = gen_params, \ + .param_init = init, .param_exit = exit, \ + .module_name = KBUILD_MODNAME} + +/** + * struct kunit_suite - describes a related collection of &struct kunit_case + * + * @name: the name of the test. Purely informational. + * @suite_init: called once per test suite before the test cases. + * @suite_exit: called once per test suite after all test cases. + * @init: called before every test case. + * @exit: called after every test case. + * @test_cases: a null terminated array of test cases. + * @attr: the attributes associated with the test suite + * + * A kunit_suite is a collection of related &struct kunit_case s, such that + * @init is called before every test case and @exit is called after every + * test case, similar to the notion of a *test fixture* or a *test class* + * in other unit testing frameworks like JUnit or Googletest. + * + * Note that @exit and @suite_exit will run even if @init or @suite_init + * fail: make sure they can handle any inconsistent state which may result. + * + * Every &struct kunit_case must be associated with a kunit_suite for KUnit + * to run it. + */ +struct kunit_suite { + const char name[256]; + int (*suite_init)(struct kunit_suite *suite); + void (*suite_exit)(struct kunit_suite *suite); + int (*init)(struct kunit *test); + void (*exit)(struct kunit *test); + struct kunit_case *test_cases; + struct kunit_attributes attr; + + /* private: internal use only */ + char status_comment[KUNIT_STATUS_COMMENT_SIZE]; + struct dentry *debugfs; + struct string_stream *log; + int suite_init_err; + bool is_init; + enum kunit_status status; +}; + +/* Stores an array of suites, end points one past the end */ +struct kunit_suite_set { + struct kunit_suite * const *start; + struct kunit_suite * const *end; +}; + +/* Stores the pointer to the parameter array and its metadata. */ +struct kunit_params { + /* + * Reference to the parameter array for a parameterized test. This + * is NULL if a parameter array wasn't directly passed to the + * parameterized test context struct kunit via kunit_register_params_array(). + */ + const void *params; + /* Reference to a function that gets the description of a parameter. */ + void (*get_description)(struct kunit *test, const void *param, char *desc); + size_t num_params; + size_t elem_size; +}; + +/** + * struct kunit - represents a running instance of a test. + * + * @priv: for user to store arbitrary data. Commonly used to pass data + * created in the init function (see &struct kunit_suite). + * @parent: reference to the parent context of type struct kunit that can + * be used for storing shared resources. + * @params_array: for storing the parameter array. + * + * Used to store information about the current context under which the test + * is running. Most of this data is private and should only be accessed + * indirectly via public functions; the exceptions are @priv, @parent and + * @params_array which can be used by the test writer to store arbitrary data, + * access the parent context, and to store the parameter array, respectively. + */ +struct kunit { + void *priv; + struct kunit *parent; + struct kunit_params params_array; + + /* private: internal use only. */ + const char *name; /* Read only after initialization! */ + struct string_stream *log; /* Points at case log after initialization */ + struct kunit_try_catch try_catch; + /* param_value is the current parameter value for a test case. */ + const void *param_value; + /* param_index stores the index of the parameter in parameterized tests. */ + int param_index; + /* + * success starts as true, and may only be set to false during a + * test case; thus, it is safe to update this across multiple + * threads using WRITE_ONCE; however, as a consequence, it may only + * be read after the test case finishes once all threads associated + * with the test case have terminated. + */ + spinlock_t lock; /* Guards all mutable test state. */ + enum kunit_status status; /* Read only after test_case finishes! */ + /* + * Because resources is a list that may be updated multiple times (with + * new resources) from any thread associated with a test case, we must + * protect it with some type of lock. + */ + struct list_head resources; /* Protected by lock. */ + + char status_comment[KUNIT_STATUS_COMMENT_SIZE]; + /* Saves the last seen test. Useful to help with faults. */ + struct kunit_loc last_seen; +}; + +static inline void kunit_set_failure(struct kunit *test) +{ + WRITE_ONCE(test->status, KUNIT_FAILURE); +} + +bool kunit_enabled(void); +bool kunit_autorun(void); +const char *kunit_action(void); +const char *kunit_filter_glob(void); +char *kunit_filter(void); +char *kunit_filter_action(void); + +void kunit_init_test(struct kunit *test, const char *name, struct string_stream *log); + +int kunit_run_tests(struct kunit_suite *suite); + +size_t kunit_suite_num_test_cases(struct kunit_suite *suite); + +unsigned int kunit_test_case_num(struct kunit_suite *suite, + struct kunit_case *test_case); + +struct kunit_suite_set +kunit_filter_suites(const struct kunit_suite_set *suite_set, + const char *filter_glob, + char *filters, + char *filter_action, + int *err); +void kunit_free_suite_set(struct kunit_suite_set suite_set); + +int __kunit_test_suites_init(struct kunit_suite * const * const suites, int num_suites, + bool run_tests); + +void __kunit_test_suites_exit(struct kunit_suite **suites, int num_suites); + +void kunit_exec_run_tests(struct kunit_suite_set *suite_set, bool builtin); +void kunit_exec_list_tests(struct kunit_suite_set *suite_set, bool include_attr); + +struct kunit_suite_set kunit_merge_suite_sets(struct kunit_suite_set init_suite_set, + struct kunit_suite_set suite_set); + +const void *kunit_array_gen_params(struct kunit *test, const void *prev, char *desc); + +#if IS_BUILTIN(CONFIG_KUNIT) +int kunit_run_all_tests(void); +#else +static inline int kunit_run_all_tests(void) +{ + return 0; +} +#endif /* IS_BUILTIN(CONFIG_KUNIT) */ + +#define __kunit_test_suites(unique_array, ...) \ + static struct kunit_suite *unique_array[] \ + __aligned(sizeof(struct kunit_suite *)) \ + __used __section(".kunit_test_suites") = { __VA_ARGS__ } + +/** + * kunit_test_suites() - used to register one or more &struct kunit_suite + * with KUnit. + * + * @__suites: a statically allocated list of &struct kunit_suite. + * + * Registers @suites with the test framework. + * This is done by placing the array of struct kunit_suite * in the + * .kunit_test_suites ELF section. + * + * When builtin, KUnit tests are all run via the executor at boot, and when + * built as a module, they run on module load. + * + */ +#define kunit_test_suites(__suites...) \ + __kunit_test_suites(__UNIQUE_ID(array), \ + ##__suites) + +#define kunit_test_suite(suite) kunit_test_suites(&suite) + +#define __kunit_init_test_suites(unique_array, ...) \ + static struct kunit_suite *unique_array[] \ + __aligned(sizeof(struct kunit_suite *)) \ + __used __section(".kunit_init_test_suites") = { __VA_ARGS__ } + +/** + * kunit_test_init_section_suites() - used to register one or more &struct + * kunit_suite containing init functions or + * init data. + * + * @__suites: a statically allocated list of &struct kunit_suite. + * + * This functions similar to kunit_test_suites() except that it compiles the + * list of suites during init phase. + * + * This macro also suffixes the array and suite declarations it makes with + * _probe; so that modpost suppresses warnings about referencing init data + * for symbols named in this manner. + * + * Note: these init tests are not able to be run after boot so there is no + * "run" debugfs file generated for these tests. + * + * Also, do not mark the suite or test case structs with __initdata because + * they will be used after the init phase with debugfs. + */ +#define kunit_test_init_section_suites(__suites...) \ + __kunit_init_test_suites(CONCATENATE(__UNIQUE_ID(array), _probe), \ + ##__suites) + +#define kunit_test_init_section_suite(suite) \ + kunit_test_init_section_suites(&suite) + +#define kunit_suite_for_each_test_case(suite, test_case) \ + for (test_case = suite->test_cases; test_case->run_case; test_case++) + +enum kunit_status kunit_suite_has_succeeded(struct kunit_suite *suite); + +/** + * kunit_kmalloc_array() - Like kmalloc_array() except the allocation is *test managed*. + * @test: The test context object. + * @n: number of elements. + * @size: The size in bytes of the desired memory. + * @gfp: flags passed to underlying kmalloc(). + * + * Just like `kmalloc_array(...)`, except the allocation is managed by the test case + * and is automatically cleaned up after the test case concludes. See kunit_add_action() + * for more information. + * + * Note that some internal context data is also allocated with GFP_KERNEL, + * regardless of the gfp passed in. + */ +void *kunit_kmalloc_array(struct kunit *test, size_t n, size_t size, gfp_t gfp); + +/** + * kunit_kmalloc() - Like kmalloc() except the allocation is *test managed*. + * @test: The test context object. + * @size: The size in bytes of the desired memory. + * @gfp: flags passed to underlying kmalloc(). + * + * See kmalloc() and kunit_kmalloc_array() for more information. + * + * Note that some internal context data is also allocated with GFP_KERNEL, + * regardless of the gfp passed in. + */ +static inline void *kunit_kmalloc(struct kunit *test, size_t size, gfp_t gfp) +{ + return kunit_kmalloc_array(test, 1, size, gfp); +} + +/** + * kunit_kfree() - Like kfree except for allocations managed by KUnit. + * @test: The test case to which the resource belongs. + * @ptr: The memory allocation to free. + */ +void kunit_kfree(struct kunit *test, const void *ptr); + +/** + * kunit_kzalloc() - Just like kunit_kmalloc(), but zeroes the allocation. + * @test: The test context object. + * @size: The size in bytes of the desired memory. + * @gfp: flags passed to underlying kmalloc(). + * + * See kzalloc() and kunit_kmalloc_array() for more information. + */ +static inline void *kunit_kzalloc(struct kunit *test, size_t size, gfp_t gfp) +{ + return kunit_kmalloc(test, size, gfp | __GFP_ZERO); +} + +/** + * kunit_kcalloc() - Just like kunit_kmalloc_array(), but zeroes the allocation. + * @test: The test context object. + * @n: number of elements. + * @size: The size in bytes of the desired memory. + * @gfp: flags passed to underlying kmalloc(). + * + * See kcalloc() and kunit_kmalloc_array() for more information. + */ +static inline void *kunit_kcalloc(struct kunit *test, size_t n, size_t size, gfp_t gfp) +{ + return kunit_kmalloc_array(test, n, size, gfp | __GFP_ZERO); +} + + +/** + * kunit_kfree_const() - conditionally free test managed memory + * @test: The test context object. + * @x: pointer to the memory + * + * Calls kunit_kfree() only if @x is not in .rodata section. + * See kunit_kstrdup_const() for more information. + */ +void kunit_kfree_const(struct kunit *test, const void *x); + +/** + * kunit_kstrdup() - Duplicates a string into a test managed allocation. + * + * @test: The test context object. + * @str: The NULL-terminated string to duplicate. + * @gfp: flags passed to underlying kmalloc(). + * + * See kstrdup() and kunit_kmalloc_array() for more information. + */ +static inline char *kunit_kstrdup(struct kunit *test, const char *str, gfp_t gfp) +{ + size_t len; + char *buf; + + if (!str) + return NULL; + + len = strlen(str) + 1; + buf = kunit_kmalloc(test, len, gfp); + if (buf) + memcpy(buf, str, len); + return buf; +} + +/** + * kunit_kstrdup_const() - Conditionally duplicates a string into a test managed allocation. + * + * @test: The test context object. + * @str: The NULL-terminated string to duplicate. + * @gfp: flags passed to underlying kmalloc(). + * + * Calls kunit_kstrdup() only if @str is not in the rodata section. Must be freed with + * kunit_kfree_const() -- not kunit_kfree(). + * See kstrdup_const() and kunit_kmalloc_array() for more information. + */ +const char *kunit_kstrdup_const(struct kunit *test, const char *str, gfp_t gfp); + +/** + * kunit_attach_mm() - Create and attach a new mm if it doesn't already exist. + * + * Allocates a &struct mm_struct and attaches it to @current. In most cases, call + * kunit_vm_mmap() without calling kunit_attach_mm() directly. Only necessary when + * code under test accesses the mm before executing the mmap (e.g., to perform + * additional initialization beforehand). + * + * Return: 0 on success, -errno on failure. + */ +int kunit_attach_mm(void); + +/** + * kunit_vm_mmap() - Allocate KUnit-tracked vm_mmap() area + * @test: The test context object. + * @file: struct file pointer to map from, if any + * @addr: desired address, if any + * @len: how many bytes to allocate + * @prot: mmap PROT_* bits + * @flag: mmap flags + * @offset: offset into @file to start mapping from. + * + * See vm_mmap() for more information. + */ +unsigned long kunit_vm_mmap(struct kunit *test, struct file *file, + unsigned long addr, unsigned long len, + unsigned long prot, unsigned long flag, + unsigned long offset); + +void kunit_cleanup(struct kunit *test); +void kunit_free_boot_suites(void); + +void __printf(2, 3) kunit_log_append(struct string_stream *log, const char *fmt, ...); + +/** + * kunit_mark_skipped() - Marks @test as skipped + * + * @test: The test context object. + * @fmt: A printk() style format string. + * + * Marks the test as skipped. @fmt is given output as the test status + * comment, typically the reason the test was skipped. + * + * Test execution continues after kunit_mark_skipped() is called. + */ +#define kunit_mark_skipped(test, fmt, ...) \ + do { \ + WRITE_ONCE((test)->status, KUNIT_SKIPPED); \ + scnprintf((test)->status_comment, \ + KUNIT_STATUS_COMMENT_SIZE, \ + fmt, ##__VA_ARGS__); \ + } while (0) + +/** + * kunit_skip() - Marks @test as skipped + * + * @test: The test context object. + * @fmt: A printk() style format string. + * + * Skips the test. @fmt is given output as the test status + * comment, typically the reason the test was skipped. + * + * Test execution is halted after kunit_skip() is called. + */ +#define kunit_skip(test, fmt, ...) \ + do { \ + kunit_mark_skipped((test), fmt, ##__VA_ARGS__); \ + kunit_try_catch_throw(&((test)->try_catch)); \ + } while (0) + +/* + * printk and log to per-test or per-suite log buffer. Logging only done + * if CONFIG_KUNIT_DEBUGFS is 'y'; if it is 'n', no log is allocated/used. + */ +#define kunit_log(lvl, test_or_suite, fmt, ...) \ + do { \ + printk(lvl fmt, ##__VA_ARGS__); \ + kunit_log_append((test_or_suite)->log, fmt, \ + ##__VA_ARGS__); \ + } while (0) + +#define kunit_printk(lvl, test, fmt, ...) \ + kunit_log(lvl, test, KUNIT_SUBTEST_INDENT "# %s: " fmt, \ + (test)->name, ##__VA_ARGS__) + +/** + * kunit_info() - Prints an INFO level message associated with @test. + * + * @test: The test context object. + * @fmt: A printk() style format string. + * + * Prints an info level message associated with the test suite being run. + * Takes a variable number of format parameters just like printk(). + */ +#define kunit_info(test, fmt, ...) \ + kunit_printk(KERN_INFO, test, fmt, ##__VA_ARGS__) + +/** + * kunit_warn() - Prints a WARN level message associated with @test. + * + * @test: The test context object. + * @fmt: A printk() style format string. + * + * Prints a warning level message. + */ +#define kunit_warn(test, fmt, ...) \ + kunit_printk(KERN_WARNING, test, fmt, ##__VA_ARGS__) + +/** + * kunit_err() - Prints an ERROR level message associated with @test. + * + * @test: The test context object. + * @fmt: A printk() style format string. + * + * Prints an error level message. + */ +#define kunit_err(test, fmt, ...) \ + kunit_printk(KERN_ERR, test, fmt, ##__VA_ARGS__) + +/* + * Must be called at the beginning of each KUNIT_*_ASSERTION(). + * Cf. KUNIT_CURRENT_LOC. + */ +#define _KUNIT_SAVE_LOC(test) do { \ + WRITE_ONCE(test->last_seen.file, __FILE__); \ + WRITE_ONCE(test->last_seen.line, __LINE__); \ +} while (0) + +/** + * KUNIT_SUCCEED() - A no-op expectation. Only exists for code clarity. + * @test: The test context object. + * + * The opposite of KUNIT_FAIL(), it is an expectation that cannot fail. In other + * words, it does nothing and only exists for code clarity. See + * KUNIT_EXPECT_TRUE() for more information. + */ +#define KUNIT_SUCCEED(test) _KUNIT_SAVE_LOC(test) + +void __noreturn __kunit_abort(struct kunit *test); + +void __printf(6, 7) __kunit_do_failed_assertion(struct kunit *test, + const struct kunit_loc *loc, + enum kunit_assert_type type, + const struct kunit_assert *assert, + assert_format_t assert_format, + const char *fmt, ...); + +#define _KUNIT_FAILED(test, assert_type, assert_class, assert_format, INITIALIZER, fmt, ...) do { \ + static const struct kunit_loc __loc = KUNIT_CURRENT_LOC; \ + const struct assert_class __assertion = INITIALIZER; \ + __kunit_do_failed_assertion(test, \ + &__loc, \ + assert_type, \ + &__assertion.assert, \ + assert_format, \ + fmt, \ + ##__VA_ARGS__); \ + if (assert_type == KUNIT_ASSERTION) \ + __kunit_abort(test); \ +} while (0) + + +#define KUNIT_FAIL_ASSERTION(test, assert_type, fmt, ...) do { \ + _KUNIT_SAVE_LOC(test); \ + _KUNIT_FAILED(test, \ + assert_type, \ + kunit_fail_assert, \ + kunit_fail_assert_format, \ + {}, \ + fmt, \ + ##__VA_ARGS__); \ +} while (0) + +/** + * KUNIT_FAIL() - Always causes a test to fail when evaluated. + * @test: The test context object. + * @fmt: an informational message to be printed when the assertion is made. + * @...: string format arguments. + * + * The opposite of KUNIT_SUCCEED(), it is an expectation that always fails. In + * other words, it always results in a failed expectation, and consequently + * always causes the test case to fail when evaluated. See KUNIT_EXPECT_TRUE() + * for more information. + */ +#define KUNIT_FAIL(test, fmt, ...) \ + KUNIT_FAIL_ASSERTION(test, \ + KUNIT_EXPECTATION, \ + 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_, \ + fmt, \ + ...) \ +do { \ + _KUNIT_SAVE_LOC(test); \ + if (likely(!!(condition_) == !!expected_true_)) \ + break; \ + \ + _KUNIT_FAILED(test, \ + assert_type, \ + kunit_unary_assert, \ + kunit_unary_assert_format, \ + KUNIT_INIT_ASSERT(.condition = #condition_, \ + .expected_true = expected_true_), \ + fmt, \ + ##__VA_ARGS__); \ +} while (0) + +#define KUNIT_TRUE_MSG_ASSERTION(test, assert_type, condition, fmt, ...) \ + KUNIT_UNARY_ASSERTION(test, \ + assert_type, \ + condition, \ + true, \ + fmt, \ + ##__VA_ARGS__) + +#define KUNIT_FALSE_MSG_ASSERTION(test, assert_type, condition, fmt, ...) \ + KUNIT_UNARY_ASSERTION(test, \ + assert_type, \ + condition, \ + false, \ + fmt, \ + ##__VA_ARGS__) + +/* + * A factory macro for defining the assertions and expectations for the basic + * comparisons defined for the built in types. + * + * Unfortunately, there is no common type that all types can be promoted to for + * which all the binary operators behave the same way as for the actual types + * (for example, there is no type that long long and unsigned long long can + * both be cast to where the comparison result is preserved for all values). So + * the best we can do is do the comparison in the original types and then coerce + * everything to long long for printing; this way, the comparison behaves + * correctly and the printed out value usually makes sense without + * interpretation, but can always be interpreted to figure out the actual + * value. + */ +#define KUNIT_BASE_BINARY_ASSERTION(test, \ + assert_class, \ + format_func, \ + assert_type, \ + left, \ + op, \ + right, \ + fmt, \ + ...) \ +do { \ + const typeof(left) __left = (left); \ + const typeof(right) __right = (right); \ + static const struct kunit_binary_assert_text __text = { \ + .operation = #op, \ + .left_text = #left, \ + .right_text = #right, \ + }; \ + \ + _KUNIT_SAVE_LOC(test); \ + if (likely(__left op __right)) \ + break; \ + \ + _KUNIT_FAILED(test, \ + assert_type, \ + assert_class, \ + format_func, \ + KUNIT_INIT_ASSERT(.text = &__text, \ + .left_value = __left, \ + .right_value = __right), \ + fmt, \ + ##__VA_ARGS__); \ +} while (0) + +#define KUNIT_BINARY_INT_ASSERTION(test, \ + assert_type, \ + left, \ + op, \ + right, \ + fmt, \ + ...) \ + KUNIT_BASE_BINARY_ASSERTION(test, \ + kunit_binary_assert, \ + kunit_binary_assert_format, \ + assert_type, \ + left, op, right, \ + fmt, \ + ##__VA_ARGS__) + +#define KUNIT_BINARY_PTR_ASSERTION(test, \ + assert_type, \ + left, \ + op, \ + right, \ + fmt, \ + ...) \ + KUNIT_BASE_BINARY_ASSERTION(test, \ + kunit_binary_ptr_assert, \ + kunit_binary_ptr_assert_format, \ + assert_type, \ + left, op, right, \ + fmt, \ + ##__VA_ARGS__) + +#define KUNIT_BINARY_STR_ASSERTION(test, \ + assert_type, \ + left, \ + op, \ + right, \ + fmt, \ + ...) \ +do { \ + const char *__left = (left); \ + const char *__right = (right); \ + static const struct kunit_binary_assert_text __text = { \ + .operation = #op, \ + .left_text = #left, \ + .right_text = #right, \ + }; \ + \ + _KUNIT_SAVE_LOC(test); \ + if (likely(!IS_ERR_OR_NULL(__left) && !IS_ERR_OR_NULL(__right) && \ + (strcmp(__left, __right) op 0))) \ + break; \ + \ + \ + _KUNIT_FAILED(test, \ + assert_type, \ + kunit_binary_str_assert, \ + kunit_binary_str_assert_format, \ + 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, \ + }; \ + \ + _KUNIT_SAVE_LOC(test); \ + if (likely(__left && __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) + +#define KUNIT_PTR_NOT_ERR_OR_NULL_MSG_ASSERTION(test, \ + assert_type, \ + ptr, \ + fmt, \ + ...) \ +do { \ + const typeof(ptr) __ptr = (ptr); \ + \ + _KUNIT_SAVE_LOC(test); \ + if (!IS_ERR_OR_NULL(__ptr)) \ + break; \ + \ + _KUNIT_FAILED(test, \ + assert_type, \ + kunit_ptr_not_err_assert, \ + kunit_ptr_not_err_assert_format, \ + KUNIT_INIT_ASSERT(.text = #ptr, .value = __ptr), \ + fmt, \ + ##__VA_ARGS__); \ +} while (0) + +/** + * KUNIT_EXPECT_TRUE() - Causes a test failure when the expression is not true. + * @test: The test context object. + * @condition: an arbitrary boolean expression. The test fails when this does + * not evaluate to true. + * + * This and expectations of the form `KUNIT_EXPECT_*` will cause the test case + * to fail when the specified condition is not met; however, it will not prevent + * the test case from continuing to run; this is otherwise known as an + * *expectation failure*. + */ +#define KUNIT_EXPECT_TRUE(test, condition) \ + KUNIT_EXPECT_TRUE_MSG(test, condition, NULL) + +#define KUNIT_EXPECT_TRUE_MSG(test, condition, fmt, ...) \ + KUNIT_TRUE_MSG_ASSERTION(test, \ + KUNIT_EXPECTATION, \ + condition, \ + fmt, \ + ##__VA_ARGS__) + +/** + * KUNIT_EXPECT_FALSE() - Makes a test failure when the expression is not false. + * @test: The test context object. + * @condition: an arbitrary boolean expression. The test fails when this does + * not evaluate to false. + * + * Sets an expectation that @condition evaluates to false. See + * KUNIT_EXPECT_TRUE() for more information. + */ +#define KUNIT_EXPECT_FALSE(test, condition) \ + KUNIT_EXPECT_FALSE_MSG(test, condition, NULL) + +#define KUNIT_EXPECT_FALSE_MSG(test, condition, fmt, ...) \ + KUNIT_FALSE_MSG_ASSERTION(test, \ + KUNIT_EXPECTATION, \ + condition, \ + fmt, \ + ##__VA_ARGS__) + +/** + * KUNIT_EXPECT_EQ() - Sets an expectation that @left and @right are equal. + * @test: The test context object. + * @left: an arbitrary expression that evaluates to a primitive C type. + * @right: an arbitrary expression that evaluates to a primitive C type. + * + * Sets an expectation that the values that @left and @right evaluate to are + * equal. This is semantically equivalent to + * KUNIT_EXPECT_TRUE(@test, (@left) == (@right)). See KUNIT_EXPECT_TRUE() for + * more information. + */ +#define KUNIT_EXPECT_EQ(test, left, right) \ + KUNIT_EXPECT_EQ_MSG(test, left, right, NULL) + +#define KUNIT_EXPECT_EQ_MSG(test, left, right, fmt, ...) \ + KUNIT_BINARY_INT_ASSERTION(test, \ + KUNIT_EXPECTATION, \ + left, ==, right, \ + fmt, \ + ##__VA_ARGS__) + +/** + * KUNIT_EXPECT_PTR_EQ() - Expects that pointers @left and @right are equal. + * @test: The test context object. + * @left: an arbitrary expression that evaluates to a pointer. + * @right: an arbitrary expression that evaluates to a pointer. + * + * Sets an expectation that the values that @left and @right evaluate to are + * equal. This is semantically equivalent to + * KUNIT_EXPECT_TRUE(@test, (@left) == (@right)). See KUNIT_EXPECT_TRUE() for + * more information. + */ +#define KUNIT_EXPECT_PTR_EQ(test, left, right) \ + KUNIT_EXPECT_PTR_EQ_MSG(test, left, right, NULL) + +#define KUNIT_EXPECT_PTR_EQ_MSG(test, left, right, fmt, ...) \ + KUNIT_BINARY_PTR_ASSERTION(test, \ + KUNIT_EXPECTATION, \ + left, ==, right, \ + fmt, \ + ##__VA_ARGS__) + +/** + * KUNIT_EXPECT_NE() - An expectation that @left and @right are not equal. + * @test: The test context object. + * @left: an arbitrary expression that evaluates to a primitive C type. + * @right: an arbitrary expression that evaluates to a primitive C type. + * + * Sets an expectation that the values that @left and @right evaluate to are not + * equal. This is semantically equivalent to + * KUNIT_EXPECT_TRUE(@test, (@left) != (@right)). See KUNIT_EXPECT_TRUE() for + * more information. + */ +#define KUNIT_EXPECT_NE(test, left, right) \ + KUNIT_EXPECT_NE_MSG(test, left, right, NULL) + +#define KUNIT_EXPECT_NE_MSG(test, left, right, fmt, ...) \ + KUNIT_BINARY_INT_ASSERTION(test, \ + KUNIT_EXPECTATION, \ + left, !=, right, \ + fmt, \ + ##__VA_ARGS__) + +/** + * KUNIT_EXPECT_PTR_NE() - Expects that pointers @left and @right are not equal. + * @test: The test context object. + * @left: an arbitrary expression that evaluates to a pointer. + * @right: an arbitrary expression that evaluates to a pointer. + * + * Sets an expectation that the values that @left and @right evaluate to are not + * equal. This is semantically equivalent to + * KUNIT_EXPECT_TRUE(@test, (@left) != (@right)). See KUNIT_EXPECT_TRUE() for + * more information. + */ +#define KUNIT_EXPECT_PTR_NE(test, left, right) \ + KUNIT_EXPECT_PTR_NE_MSG(test, left, right, NULL) + +#define KUNIT_EXPECT_PTR_NE_MSG(test, left, right, fmt, ...) \ + KUNIT_BINARY_PTR_ASSERTION(test, \ + KUNIT_EXPECTATION, \ + left, !=, right, \ + fmt, \ + ##__VA_ARGS__) + +/** + * KUNIT_EXPECT_LT() - An expectation that @left is less than @right. + * @test: The test context object. + * @left: an arbitrary expression that evaluates to a primitive C type. + * @right: an arbitrary expression that evaluates to a primitive C type. + * + * Sets an expectation that the value that @left evaluates to is less than the + * value that @right evaluates to. This is semantically equivalent to + * KUNIT_EXPECT_TRUE(@test, (@left) < (@right)). See KUNIT_EXPECT_TRUE() for + * more information. + */ +#define KUNIT_EXPECT_LT(test, left, right) \ + KUNIT_EXPECT_LT_MSG(test, left, right, NULL) + +#define KUNIT_EXPECT_LT_MSG(test, left, right, fmt, ...) \ + KUNIT_BINARY_INT_ASSERTION(test, \ + KUNIT_EXPECTATION, \ + left, <, right, \ + fmt, \ + ##__VA_ARGS__) + +/** + * KUNIT_EXPECT_LE() - Expects that @left is less than or equal to @right. + * @test: The test context object. + * @left: an arbitrary expression that evaluates to a primitive C type. + * @right: an arbitrary expression that evaluates to a primitive C type. + * + * Sets an expectation that the value that @left evaluates to is less than or + * equal to the value that @right evaluates to. Semantically this is equivalent + * to KUNIT_EXPECT_TRUE(@test, (@left) <= (@right)). See KUNIT_EXPECT_TRUE() for + * more information. + */ +#define KUNIT_EXPECT_LE(test, left, right) \ + KUNIT_EXPECT_LE_MSG(test, left, right, NULL) + +#define KUNIT_EXPECT_LE_MSG(test, left, right, fmt, ...) \ + KUNIT_BINARY_INT_ASSERTION(test, \ + KUNIT_EXPECTATION, \ + left, <=, right, \ + fmt, \ + ##__VA_ARGS__) + +/** + * KUNIT_EXPECT_GT() - An expectation that @left is greater than @right. + * @test: The test context object. + * @left: an arbitrary expression that evaluates to a primitive C type. + * @right: an arbitrary expression that evaluates to a primitive C type. + * + * Sets an expectation that the value that @left evaluates to is greater than + * the value that @right evaluates to. This is semantically equivalent to + * KUNIT_EXPECT_TRUE(@test, (@left) > (@right)). See KUNIT_EXPECT_TRUE() for + * more information. + */ +#define KUNIT_EXPECT_GT(test, left, right) \ + KUNIT_EXPECT_GT_MSG(test, left, right, NULL) + +#define KUNIT_EXPECT_GT_MSG(test, left, right, fmt, ...) \ + KUNIT_BINARY_INT_ASSERTION(test, \ + KUNIT_EXPECTATION, \ + left, >, right, \ + fmt, \ + ##__VA_ARGS__) + +/** + * KUNIT_EXPECT_GE() - Expects that @left is greater than or equal to @right. + * @test: The test context object. + * @left: an arbitrary expression that evaluates to a primitive C type. + * @right: an arbitrary expression that evaluates to a primitive C type. + * + * Sets an expectation that the value that @left evaluates to is greater than + * the value that @right evaluates to. This is semantically equivalent to + * KUNIT_EXPECT_TRUE(@test, (@left) >= (@right)). See KUNIT_EXPECT_TRUE() for + * more information. + */ +#define KUNIT_EXPECT_GE(test, left, right) \ + KUNIT_EXPECT_GE_MSG(test, left, right, NULL) + +#define KUNIT_EXPECT_GE_MSG(test, left, right, fmt, ...) \ + KUNIT_BINARY_INT_ASSERTION(test, \ + KUNIT_EXPECTATION, \ + left, >=, right, \ + fmt, \ + ##__VA_ARGS__) + +/** + * KUNIT_EXPECT_STREQ() - Expects that strings @left and @right are equal. + * @test: The test context object. + * @left: an arbitrary expression that evaluates to a null terminated string. + * @right: an arbitrary expression that evaluates to a null terminated string. + * + * Sets an expectation that the values that @left and @right evaluate to are + * equal. This is semantically equivalent to + * KUNIT_EXPECT_TRUE(@test, !strcmp((@left), (@right))). See KUNIT_EXPECT_TRUE() + * for more information. + */ +#define KUNIT_EXPECT_STREQ(test, left, right) \ + KUNIT_EXPECT_STREQ_MSG(test, left, right, NULL) + +#define KUNIT_EXPECT_STREQ_MSG(test, left, right, fmt, ...) \ + KUNIT_BINARY_STR_ASSERTION(test, \ + KUNIT_EXPECTATION, \ + left, ==, right, \ + fmt, \ + ##__VA_ARGS__) + +/** + * KUNIT_EXPECT_STRNEQ() - Expects that strings @left and @right are not equal. + * @test: The test context object. + * @left: an arbitrary expression that evaluates to a null terminated string. + * @right: an arbitrary expression that evaluates to a null terminated string. + * + * Sets an expectation that the values that @left and @right evaluate to are + * not equal. This is semantically equivalent to + * KUNIT_EXPECT_TRUE(@test, strcmp((@left), (@right))). See KUNIT_EXPECT_TRUE() + * for more information. + */ +#define KUNIT_EXPECT_STRNEQ(test, left, right) \ + KUNIT_EXPECT_STRNEQ_MSG(test, left, right, NULL) + +#define KUNIT_EXPECT_STRNEQ_MSG(test, left, right, fmt, ...) \ + KUNIT_BINARY_STR_ASSERTION(test, \ + KUNIT_EXPECTATION, \ + left, !=, right, \ + 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. + * @ptr: an arbitrary pointer. + * + * Sets an expectation that the value that @ptr evaluates to is null. This is + * semantically equivalent to KUNIT_EXPECT_PTR_EQ(@test, ptr, NULL). + * See KUNIT_EXPECT_TRUE() for more information. + */ +#define KUNIT_EXPECT_NULL(test, ptr) \ + KUNIT_EXPECT_NULL_MSG(test, \ + ptr, \ + NULL) + +#define KUNIT_EXPECT_NULL_MSG(test, ptr, fmt, ...) \ + KUNIT_BINARY_PTR_ASSERTION(test, \ + KUNIT_EXPECTATION, \ + ptr, ==, NULL, \ + fmt, \ + ##__VA_ARGS__) + +/** + * KUNIT_EXPECT_NOT_NULL() - Expects that @ptr is not null. + * @test: The test context object. + * @ptr: an arbitrary pointer. + * + * Sets an expectation that the value that @ptr evaluates to is not null. This + * is semantically equivalent to KUNIT_EXPECT_PTR_NE(@test, ptr, NULL). + * See KUNIT_EXPECT_TRUE() for more information. + */ +#define KUNIT_EXPECT_NOT_NULL(test, ptr) \ + KUNIT_EXPECT_NOT_NULL_MSG(test, \ + ptr, \ + NULL) + +#define KUNIT_EXPECT_NOT_NULL_MSG(test, ptr, fmt, ...) \ + KUNIT_BINARY_PTR_ASSERTION(test, \ + KUNIT_EXPECTATION, \ + ptr, !=, NULL, \ + fmt, \ + ##__VA_ARGS__) + +/** + * KUNIT_EXPECT_NOT_ERR_OR_NULL() - Expects that @ptr is not null and not err. + * @test: The test context object. + * @ptr: an arbitrary pointer. + * + * Sets an expectation that the value that @ptr evaluates to is not null and not + * an errno stored in a pointer. This is semantically equivalent to + * KUNIT_EXPECT_TRUE(@test, !IS_ERR_OR_NULL(@ptr)). See KUNIT_EXPECT_TRUE() for + * more information. + */ +#define KUNIT_EXPECT_NOT_ERR_OR_NULL(test, ptr) \ + KUNIT_EXPECT_NOT_ERR_OR_NULL_MSG(test, ptr, NULL) + +#define KUNIT_EXPECT_NOT_ERR_OR_NULL_MSG(test, ptr, fmt, ...) \ + KUNIT_PTR_NOT_ERR_OR_NULL_MSG_ASSERTION(test, \ + KUNIT_EXPECTATION, \ + ptr, \ + fmt, \ + ##__VA_ARGS__) + +/** + * KUNIT_FAIL_AND_ABORT() - Always causes a test to fail and abort when evaluated. + * @test: The test context object. + * @fmt: an informational message to be printed when the assertion is made. + * @...: string format arguments. + * + * The opposite of KUNIT_SUCCEED(), it is an assertion that always fails. In + * other words, it always results in a failed assertion, and consequently + * always causes the test case to fail and abort when evaluated. + * See KUNIT_ASSERT_TRUE() for more information. + */ +#define KUNIT_FAIL_AND_ABORT(test, fmt, ...) \ + KUNIT_FAIL_ASSERTION(test, KUNIT_ASSERTION, fmt, ##__VA_ARGS__) + +/** + * KUNIT_ASSERT_TRUE() - Sets an assertion that @condition is true. + * @test: The test context object. + * @condition: an arbitrary boolean expression. The test fails and aborts when + * this does not evaluate to true. + * + * This and assertions of the form `KUNIT_ASSERT_*` will cause the test case to + * fail *and immediately abort* when the specified condition is not met. Unlike + * an expectation failure, it will prevent the test case from continuing to run; + * this is otherwise known as an *assertion failure*. + */ +#define KUNIT_ASSERT_TRUE(test, condition) \ + KUNIT_ASSERT_TRUE_MSG(test, condition, NULL) + +#define KUNIT_ASSERT_TRUE_MSG(test, condition, fmt, ...) \ + KUNIT_TRUE_MSG_ASSERTION(test, \ + KUNIT_ASSERTION, \ + condition, \ + fmt, \ + ##__VA_ARGS__) + +/** + * KUNIT_ASSERT_FALSE() - Sets an assertion that @condition is false. + * @test: The test context object. + * @condition: an arbitrary boolean expression. + * + * Sets an assertion that the value that @condition evaluates to is false. This + * is the same as KUNIT_EXPECT_FALSE(), except it causes an assertion failure + * (see KUNIT_ASSERT_TRUE()) when the assertion is not met. + */ +#define KUNIT_ASSERT_FALSE(test, condition) \ + KUNIT_ASSERT_FALSE_MSG(test, condition, NULL) + +#define KUNIT_ASSERT_FALSE_MSG(test, condition, fmt, ...) \ + KUNIT_FALSE_MSG_ASSERTION(test, \ + KUNIT_ASSERTION, \ + condition, \ + fmt, \ + ##__VA_ARGS__) + +/** + * KUNIT_ASSERT_EQ() - Sets an assertion that @left and @right are equal. + * @test: The test context object. + * @left: an arbitrary expression that evaluates to a primitive C type. + * @right: an arbitrary expression that evaluates to a primitive C type. + * + * Sets an assertion that the values that @left and @right evaluate to are + * equal. This is the same as KUNIT_EXPECT_EQ(), except it causes an assertion + * failure (see KUNIT_ASSERT_TRUE()) when the assertion is not met. + */ +#define KUNIT_ASSERT_EQ(test, left, right) \ + KUNIT_ASSERT_EQ_MSG(test, left, right, NULL) + +#define KUNIT_ASSERT_EQ_MSG(test, left, right, fmt, ...) \ + KUNIT_BINARY_INT_ASSERTION(test, \ + KUNIT_ASSERTION, \ + left, ==, right, \ + fmt, \ + ##__VA_ARGS__) + +/** + * KUNIT_ASSERT_PTR_EQ() - Asserts that pointers @left and @right are equal. + * @test: The test context object. + * @left: an arbitrary expression that evaluates to a pointer. + * @right: an arbitrary expression that evaluates to a pointer. + * + * Sets an assertion that the values that @left and @right evaluate to are + * equal. This is the same as KUNIT_EXPECT_EQ(), except it causes an assertion + * failure (see KUNIT_ASSERT_TRUE()) when the assertion is not met. + */ +#define KUNIT_ASSERT_PTR_EQ(test, left, right) \ + KUNIT_ASSERT_PTR_EQ_MSG(test, left, right, NULL) + +#define KUNIT_ASSERT_PTR_EQ_MSG(test, left, right, fmt, ...) \ + KUNIT_BINARY_PTR_ASSERTION(test, \ + KUNIT_ASSERTION, \ + left, ==, right, \ + fmt, \ + ##__VA_ARGS__) + +/** + * KUNIT_ASSERT_NE() - An assertion that @left and @right are not equal. + * @test: The test context object. + * @left: an arbitrary expression that evaluates to a primitive C type. + * @right: an arbitrary expression that evaluates to a primitive C type. + * + * Sets an assertion that the values that @left and @right evaluate to are not + * equal. This is the same as KUNIT_EXPECT_NE(), except it causes an assertion + * failure (see KUNIT_ASSERT_TRUE()) when the assertion is not met. + */ +#define KUNIT_ASSERT_NE(test, left, right) \ + KUNIT_ASSERT_NE_MSG(test, left, right, NULL) + +#define KUNIT_ASSERT_NE_MSG(test, left, right, fmt, ...) \ + KUNIT_BINARY_INT_ASSERTION(test, \ + KUNIT_ASSERTION, \ + left, !=, right, \ + fmt, \ + ##__VA_ARGS__) + +/** + * KUNIT_ASSERT_PTR_NE() - Asserts that pointers @left and @right are not equal. + * KUNIT_ASSERT_PTR_EQ() - Asserts that pointers @left and @right are equal. + * @test: The test context object. + * @left: an arbitrary expression that evaluates to a pointer. + * @right: an arbitrary expression that evaluates to a pointer. + * + * Sets an assertion that the values that @left and @right evaluate to are not + * equal. This is the same as KUNIT_EXPECT_NE(), except it causes an assertion + * failure (see KUNIT_ASSERT_TRUE()) when the assertion is not met. + */ +#define KUNIT_ASSERT_PTR_NE(test, left, right) \ + KUNIT_ASSERT_PTR_NE_MSG(test, left, right, NULL) + +#define KUNIT_ASSERT_PTR_NE_MSG(test, left, right, fmt, ...) \ + KUNIT_BINARY_PTR_ASSERTION(test, \ + KUNIT_ASSERTION, \ + left, !=, right, \ + fmt, \ + ##__VA_ARGS__) +/** + * KUNIT_ASSERT_LT() - An assertion that @left is less than @right. + * @test: The test context object. + * @left: an arbitrary expression that evaluates to a primitive C type. + * @right: an arbitrary expression that evaluates to a primitive C type. + * + * Sets an assertion that the value that @left evaluates to is less than the + * value that @right evaluates to. This is the same as KUNIT_EXPECT_LT(), except + * it causes an assertion failure (see KUNIT_ASSERT_TRUE()) when the assertion + * is not met. + */ +#define KUNIT_ASSERT_LT(test, left, right) \ + KUNIT_ASSERT_LT_MSG(test, left, right, NULL) + +#define KUNIT_ASSERT_LT_MSG(test, left, right, fmt, ...) \ + KUNIT_BINARY_INT_ASSERTION(test, \ + KUNIT_ASSERTION, \ + left, <, right, \ + fmt, \ + ##__VA_ARGS__) +/** + * KUNIT_ASSERT_LE() - An assertion that @left is less than or equal to @right. + * @test: The test context object. + * @left: an arbitrary expression that evaluates to a primitive C type. + * @right: an arbitrary expression that evaluates to a primitive C type. + * + * Sets an assertion that the value that @left evaluates to is less than or + * equal to the value that @right evaluates to. This is the same as + * KUNIT_EXPECT_LE(), except it causes an assertion failure (see + * KUNIT_ASSERT_TRUE()) when the assertion is not met. + */ +#define KUNIT_ASSERT_LE(test, left, right) \ + KUNIT_ASSERT_LE_MSG(test, left, right, NULL) + +#define KUNIT_ASSERT_LE_MSG(test, left, right, fmt, ...) \ + KUNIT_BINARY_INT_ASSERTION(test, \ + KUNIT_ASSERTION, \ + left, <=, right, \ + fmt, \ + ##__VA_ARGS__) + +/** + * KUNIT_ASSERT_GT() - An assertion that @left is greater than @right. + * @test: The test context object. + * @left: an arbitrary expression that evaluates to a primitive C type. + * @right: an arbitrary expression that evaluates to a primitive C type. + * + * Sets an assertion that the value that @left evaluates to is greater than the + * value that @right evaluates to. This is the same as KUNIT_EXPECT_GT(), except + * it causes an assertion failure (see KUNIT_ASSERT_TRUE()) when the assertion + * is not met. + */ +#define KUNIT_ASSERT_GT(test, left, right) \ + KUNIT_ASSERT_GT_MSG(test, left, right, NULL) + +#define KUNIT_ASSERT_GT_MSG(test, left, right, fmt, ...) \ + KUNIT_BINARY_INT_ASSERTION(test, \ + KUNIT_ASSERTION, \ + left, >, right, \ + fmt, \ + ##__VA_ARGS__) + +/** + * KUNIT_ASSERT_GE() - Assertion that @left is greater than or equal to @right. + * @test: The test context object. + * @left: an arbitrary expression that evaluates to a primitive C type. + * @right: an arbitrary expression that evaluates to a primitive C type. + * + * Sets an assertion that the value that @left evaluates to is greater than the + * value that @right evaluates to. This is the same as KUNIT_EXPECT_GE(), except + * it causes an assertion failure (see KUNIT_ASSERT_TRUE()) when the assertion + * is not met. + */ +#define KUNIT_ASSERT_GE(test, left, right) \ + KUNIT_ASSERT_GE_MSG(test, left, right, NULL) + +#define KUNIT_ASSERT_GE_MSG(test, left, right, fmt, ...) \ + KUNIT_BINARY_INT_ASSERTION(test, \ + KUNIT_ASSERTION, \ + left, >=, right, \ + fmt, \ + ##__VA_ARGS__) + +/** + * KUNIT_ASSERT_STREQ() - An assertion that strings @left and @right are equal. + * @test: The test context object. + * @left: an arbitrary expression that evaluates to a null terminated string. + * @right: an arbitrary expression that evaluates to a null terminated string. + * + * Sets an assertion that the values that @left and @right evaluate to are + * equal. This is the same as KUNIT_EXPECT_STREQ(), except it causes an + * assertion failure (see KUNIT_ASSERT_TRUE()) when the assertion is not met. + */ +#define KUNIT_ASSERT_STREQ(test, left, right) \ + KUNIT_ASSERT_STREQ_MSG(test, left, right, NULL) + +#define KUNIT_ASSERT_STREQ_MSG(test, left, right, fmt, ...) \ + KUNIT_BINARY_STR_ASSERTION(test, \ + KUNIT_ASSERTION, \ + left, ==, right, \ + fmt, \ + ##__VA_ARGS__) + +/** + * KUNIT_ASSERT_STRNEQ() - An assertion that strings @left and @right are not equal. + * @test: The test context object. + * @left: an arbitrary expression that evaluates to a null terminated string. + * @right: an arbitrary expression that evaluates to a null terminated string. + * + * Sets an assertion that the values that @left and @right evaluate to are + * not equal. This is semantically equivalent to + * KUNIT_ASSERT_TRUE(@test, strcmp((@left), (@right))). See KUNIT_ASSERT_TRUE() + * for more information. + */ +#define KUNIT_ASSERT_STRNEQ(test, left, right) \ + KUNIT_ASSERT_STRNEQ_MSG(test, left, right, NULL) + +#define KUNIT_ASSERT_STRNEQ_MSG(test, left, right, fmt, ...) \ + KUNIT_BINARY_STR_ASSERTION(test, \ + KUNIT_ASSERTION, \ + left, !=, right, \ + fmt, \ + ##__VA_ARGS__) + +/** + * KUNIT_ASSERT_MEMEQ() - Asserts 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 assertion that the values that @left and @right evaluate to are + * equal. This is semantically equivalent to + * KUNIT_ASSERT_TRUE(@test, !memcmp((@left), (@right), (@size))). See + * KUNIT_ASSERT_TRUE() for more information. + * + * Although this assertion works for any memory block, it is not recommended + * for comparing more structured data, such as structs. This assertion is + * recommended for comparing, for example, data arrays. + */ +#define KUNIT_ASSERT_MEMEQ(test, left, right, size) \ + KUNIT_ASSERT_MEMEQ_MSG(test, left, right, size, NULL) + +#define KUNIT_ASSERT_MEMEQ_MSG(test, left, right, size, fmt, ...) \ + KUNIT_MEM_ASSERTION(test, \ + KUNIT_ASSERTION, \ + left, ==, right, \ + size, \ + fmt, \ + ##__VA_ARGS__) + +/** + * KUNIT_ASSERT_MEMNEQ() - Asserts 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 assertion that the values that @left and @right evaluate to are + * not equal. This is semantically equivalent to + * KUNIT_ASSERT_TRUE(@test, memcmp((@left), (@right), (@size))). See + * KUNIT_ASSERT_TRUE() for more information. + * + * Although this assertion works for any memory block, it is not recommended + * for comparing more structured data, such as structs. This assertion is + * recommended for comparing, for example, data arrays. + */ +#define KUNIT_ASSERT_MEMNEQ(test, left, right, size) \ + KUNIT_ASSERT_MEMNEQ_MSG(test, left, right, size, NULL) + +#define KUNIT_ASSERT_MEMNEQ_MSG(test, left, right, size, fmt, ...) \ + KUNIT_MEM_ASSERTION(test, \ + KUNIT_ASSERTION, \ + left, !=, right, \ + size, \ + fmt, \ + ##__VA_ARGS__) + +/** + * KUNIT_ASSERT_NULL() - Asserts that pointers @ptr is null. + * @test: The test context object. + * @ptr: an arbitrary pointer. + * + * Sets an assertion that the values that @ptr evaluates to is null. This is + * the same as KUNIT_EXPECT_NULL(), except it causes an assertion + * failure (see KUNIT_ASSERT_TRUE()) when the assertion is not met. + */ +#define KUNIT_ASSERT_NULL(test, ptr) \ + KUNIT_ASSERT_NULL_MSG(test, \ + ptr, \ + NULL) + +#define KUNIT_ASSERT_NULL_MSG(test, ptr, fmt, ...) \ + KUNIT_BINARY_PTR_ASSERTION(test, \ + KUNIT_ASSERTION, \ + ptr, ==, NULL, \ + fmt, \ + ##__VA_ARGS__) + +/** + * KUNIT_ASSERT_NOT_NULL() - Asserts that pointers @ptr is not null. + * @test: The test context object. + * @ptr: an arbitrary pointer. + * + * Sets an assertion that the values that @ptr evaluates to is not null. This + * is the same as KUNIT_EXPECT_NOT_NULL(), except it causes an assertion + * failure (see KUNIT_ASSERT_TRUE()) when the assertion is not met. + */ +#define KUNIT_ASSERT_NOT_NULL(test, ptr) \ + KUNIT_ASSERT_NOT_NULL_MSG(test, \ + ptr, \ + NULL) + +#define KUNIT_ASSERT_NOT_NULL_MSG(test, ptr, fmt, ...) \ + KUNIT_BINARY_PTR_ASSERTION(test, \ + KUNIT_ASSERTION, \ + ptr, !=, NULL, \ + fmt, \ + ##__VA_ARGS__) + +/** + * KUNIT_ASSERT_NOT_ERR_OR_NULL() - Assertion that @ptr is not null and not err. + * @test: The test context object. + * @ptr: an arbitrary pointer. + * + * Sets an assertion that the value that @ptr evaluates to is not null and not + * an errno stored in a pointer. This is the same as + * KUNIT_EXPECT_NOT_ERR_OR_NULL(), except it causes an assertion failure (see + * KUNIT_ASSERT_TRUE()) when the assertion is not met. + */ +#define KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ptr) \ + KUNIT_ASSERT_NOT_ERR_OR_NULL_MSG(test, ptr, NULL) + +#define KUNIT_ASSERT_NOT_ERR_OR_NULL_MSG(test, ptr, fmt, ...) \ + KUNIT_PTR_NOT_ERR_OR_NULL_MSG_ASSERTION(test, \ + KUNIT_ASSERTION, \ + ptr, \ + fmt, \ + ##__VA_ARGS__) + +/** + * KUNIT_ARRAY_PARAM() - Define test parameter generator from an array. + * @name: prefix for the test parameter generator function. + * @array: array of test parameters. + * @get_desc: function to convert param to description; NULL to use default + * + * Define function @name_gen_params which uses @array to generate parameters. + */ +#define KUNIT_ARRAY_PARAM(name, array, get_desc) \ + static const void *name##_gen_params(struct kunit *test, \ + const void *prev, char *desc) \ + { \ + typeof((array)[0]) *__next = prev ? ((typeof(__next)) prev) + 1 : (array); \ + if (!prev) \ + kunit_register_params_array(test, array, ARRAY_SIZE(array), NULL); \ + if (__next - (array) < ARRAY_SIZE((array))) { \ + void (*__get_desc)(typeof(__next), char *) = get_desc; \ + if (__get_desc) \ + __get_desc(__next, desc); \ + return __next; \ + } \ + return NULL; \ + } + +/** + * KUNIT_ARRAY_PARAM_DESC() - Define test parameter generator from an array. + * @name: prefix for the test parameter generator function. + * @array: array of test parameters. + * @desc_member: structure member from array element to use as description + * + * Define function @name_gen_params which uses @array to generate parameters. + */ +#define KUNIT_ARRAY_PARAM_DESC(name, array, desc_member) \ + static const void *name##_gen_params(struct kunit *test, \ + const void *prev, char *desc) \ + { \ + typeof((array)[0]) *__next = prev ? ((typeof(__next)) prev) + 1 : (array); \ + if (!prev) \ + kunit_register_params_array(test, array, ARRAY_SIZE(array), NULL); \ + if (__next - (array) < ARRAY_SIZE((array))) { \ + strscpy(desc, __next->desc_member, KUNIT_PARAM_DESC_SIZE); \ + return __next; \ + } \ + return NULL; \ + } + +/** + * kunit_register_params_array() - Register parameter array for a KUnit test. + * @test: The KUnit test structure to which parameters will be added. + * @array: An array of test parameters. + * @param_count: Number of parameters. + * @get_desc: Function that generates a string description for a given parameter + * element. + * + * This macro initializes the @test's parameter array data, storing information + * including the parameter array, its count, the element size, and the parameter + * description function within `test->params_array`. + * + * Note: If using this macro in param_init(), kunit_array_gen_params() + * will then need to be manually provided as the parameter generator function to + * KUNIT_CASE_PARAM_WITH_INIT(). kunit_array_gen_params() is a KUnit + * function that uses the registered array to generate parameters + */ +#define kunit_register_params_array(test, array, param_count, get_desc) \ + do { \ + struct kunit *_test = (test); \ + const typeof((array)[0]) * _params_ptr = &(array)[0]; \ + _test->params_array.params = _params_ptr; \ + _test->params_array.num_params = (param_count); \ + _test->params_array.elem_size = sizeof(*_params_ptr); \ + _test->params_array.get_description = (get_desc); \ + } while (0) + +// TODO(dlatypov@google.com): consider eventually migrating users to explicitly +// include resource.h themselves if they need it. +#include <kunit/resource.h> + +/* + * Warning backtrace suppression API. + * + * Suppresses WARN*() backtraces on the current task while active. Two forms + * are provided: + * + * - Scoped: kunit_warning_suppress(test) { ... } + * Suppression is active for the duration of the block. On normal exit, + * the for-loop increment deactivates suppression. On early exit (break, + * return, goto), the __cleanup attribute fires. On kthread_exit() (e.g., + * a failed KUnit assertion), kunit_add_action() cleans up at test + * teardown. The suppression handle is only accessible inside the block, + * so warning counts must be checked before the block exits. + * + * - Direct: kunit_start_suppress_warning() / kunit_end_suppress_warning() + * The underlying functions, returning an explicit handle pointer. Use + * when the handle needs to be retained (e.g., for post-suppression + * count checks) or passed across helper functions. + */ +struct kunit_suppressed_warning; + +struct kunit_suppressed_warning * +kunit_start_suppress_warning(struct kunit *test); +void kunit_end_suppress_warning(struct kunit *test, + struct kunit_suppressed_warning *w); +int kunit_suppressed_warning_count(struct kunit_suppressed_warning *w); +void __kunit_suppress_auto_cleanup(struct kunit_suppressed_warning **wp); +bool kunit_has_active_suppress_warning(void); + +/** + * kunit_warning_suppress() - Suppress WARN*() backtraces for the duration + * of a block. + * @test: The test context object. + * + * Scoped form of the suppression API. Suppression starts when the block is + * entered and ends automatically when the block exits through any path. See + * the section comment above for the cleanup guarantees on each exit path. + * Fails the test if suppression is already active; nesting is not supported. + * + * The warning count can be checked inside the block via + * KUNIT_EXPECT_SUPPRESSED_WARNING_COUNT(). The handle is not accessible + * after the block exits. + * + * Example:: + * + * kunit_warning_suppress(test) { + * trigger_warning(); + * KUNIT_EXPECT_SUPPRESSED_WARNING_COUNT(test, 1); + * } + */ +#define kunit_warning_suppress(test) \ + for (struct kunit_suppressed_warning *__kunit_suppress \ + __cleanup(__kunit_suppress_auto_cleanup) = \ + kunit_start_suppress_warning(test); \ + __kunit_suppress; \ + kunit_end_suppress_warning(test, __kunit_suppress), \ + __kunit_suppress = NULL) + +/** + * KUNIT_SUPPRESSED_WARNING_COUNT() - Returns the suppressed warning count. + * + * Returns the number of WARN*() calls suppressed since the current + * suppression block started, or 0 if the handle is NULL. Usable inside a + * kunit_warning_suppress() block. + */ +#define KUNIT_SUPPRESSED_WARNING_COUNT() \ + kunit_suppressed_warning_count(__kunit_suppress) + +/** + * KUNIT_EXPECT_SUPPRESSED_WARNING_COUNT() - Sets an expectation that the + * suppressed warning count equals + * @expected. + * @test: The test context object. + * @expected: an expression that evaluates to the expected warning count. + * + * Sets an expectation that the number of suppressed WARN*() calls equals + * @expected. This is semantically equivalent to + * KUNIT_EXPECT_EQ(@test, KUNIT_SUPPRESSED_WARNING_COUNT(), @expected). + * See KUNIT_EXPECT_EQ() for more information. + */ +#define KUNIT_EXPECT_SUPPRESSED_WARNING_COUNT(test, expected) \ + KUNIT_EXPECT_EQ(test, KUNIT_SUPPRESSED_WARNING_COUNT(), expected) + +/** + * KUNIT_ASSERT_SUPPRESSED_WARNING_COUNT() - Sets an assertion that the + * suppressed warning count equals + * @expected. + * @test: The test context object. + * @expected: an expression that evaluates to the expected warning count. + * + * Sets an assertion that the number of suppressed WARN*() calls equals + * @expected. This is the same as KUNIT_EXPECT_SUPPRESSED_WARNING_COUNT(), + * except it causes an assertion failure (see KUNIT_ASSERT_TRUE()) when the + * assertion is not met. + */ +#define KUNIT_ASSERT_SUPPRESSED_WARNING_COUNT(test, expected) \ + KUNIT_ASSERT_EQ(test, KUNIT_SUPPRESSED_WARNING_COUNT(), expected) + +#endif /* _KUNIT_TEST_H */ diff --git a/include/kunit/try-catch.h b/include/kunit/try-catch.h new file mode 100644 index 000000000..d4e1a5b98 --- /dev/null +++ b/include/kunit/try-catch.h @@ -0,0 +1,63 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * An API to allow a function, that may fail, to be executed, and recover in a + * controlled manner. + * + * Copyright (C) 2019, Google LLC. + * Author: Brendan Higgins <brendanhiggins@google.com> + */ + +#ifndef _KUNIT_TRY_CATCH_H +#define _KUNIT_TRY_CATCH_H + +#include <linux/types.h> + +typedef void (*kunit_try_catch_func_t)(void *); + +struct kunit; + +/** + * struct kunit_try_catch - provides a generic way to run code which might fail. + * @test: The test case that is currently being executed. + * @try_result: Contains any errno obtained while running test case. + * @try: The function, the test case, to attempt to run. + * @catch: The function called if @try bails out. + * @context: used to pass user data to the try and catch functions. + * + * kunit_try_catch provides a generic, architecture independent way to execute + * an arbitrary function of type kunit_try_catch_func_t which may bail out by + * calling kunit_try_catch_throw(). If kunit_try_catch_throw() is called, @try + * is stopped at the site of invocation and @catch is called. + * + * struct kunit_try_catch provides a generic interface for the functionality + * needed to implement kunit->abort() which in turn is needed for implementing + * assertions. Assertions allow stating a precondition for a test simplifying + * how test cases are written and presented. + * + * Assertions are like expectations, except they abort (call + * kunit_try_catch_throw()) when the specified condition is not met. This is + * useful when you look at a test case as a logical statement about some piece + * of code, where assertions are the premises for the test case, and the + * conclusion is a set of predicates, rather expectations, that must all be + * true. If your premises are violated, it does not makes sense to continue. + */ +struct kunit_try_catch { + /* private: internal use only. */ + struct kunit *test; + int try_result; + kunit_try_catch_func_t try; + kunit_try_catch_func_t catch; + unsigned long timeout; + void *context; +}; + +void kunit_try_catch_run(struct kunit_try_catch *try_catch, void *context); + +void __noreturn kunit_try_catch_throw(struct kunit_try_catch *try_catch); + +static inline int kunit_try_catch_get_result(struct kunit_try_catch *try_catch) +{ + return try_catch->try_result; +} + +#endif /* _KUNIT_TRY_CATCH_H */ diff --git a/include/kunit/visibility.h b/include/kunit/visibility.h new file mode 100644 index 000000000..7c34c8ffc --- /dev/null +++ b/include/kunit/visibility.h @@ -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. + * @symbol: the symbol identifier to export + */ + #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 */ |
