linux/lib/kunit/attributes.c
Rae Moar 39e92cb1e4 kunit: Add test attributes API structure
Add the basic structure of the test attribute API to KUnit, which can be
used to save and access test associated data.

Add attributes.c and attributes.h to hold associated structs and functions
for the API.

Create a struct that holds a variety of associated helper functions for
each test attribute. These helper functions will be used to get the
attribute value, convert the value to a string, and filter based on the
value. This struct is flexible by design to allow for attributes of
numerous types and contexts.

Add a method to print test attributes in the format of "# [<test_name if
not suite>.]<attribute_name>: <attribute_value>".

Example for a suite: "# speed: slow"

Example for a test case: "# test_case.speed: very_slow"

Use this method to report attributes in the KTAP output (KTAP spec:
https://docs.kernel.org/dev-tools/ktap.html) and _list_tests output when
kernel's new kunit.action=list_attr option is used. Note this is derivative
of the kunit.action=list option.

In test.h, add fields and associated helper functions to test cases and
suites to hold user-inputted test attributes.

Reviewed-by: David Gow <davidgow@google.com>
Signed-off-by: Rae Moar <rmoar@google.com>
Signed-off-by: Shuah Khan <skhan@linuxfoundation.org>
2023-07-26 13:28:57 -06:00

81 lines
2.2 KiB
C

// 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>
*/
#include <kunit/test.h>
#include <kunit/attributes.h>
/* Options for printing attributes:
* PRINT_ALWAYS - attribute is printed for every test case and suite if set
* PRINT_SUITE - attribute is printed for every suite if set but not for test cases
* PRINT_NEVER - attribute is never printed
*/
enum print_ops {
PRINT_ALWAYS,
PRINT_SUITE,
PRINT_NEVER,
};
/**
* struct kunit_attr - represents a test attribute and holds flexible
* helper functions to interact with attribute.
*
* @name: name of test attribute, eg. speed
* @get_attr: function to return attribute value given a test
* @to_string: function to return string representation of given
* attribute value
* @filter: function to indicate whether a given attribute value passes a
* filter
*/
struct kunit_attr {
const char *name;
void *(*get_attr)(void *test_or_suite, bool is_test);
const char *(*to_string)(void *attr, bool *to_free);
int (*filter)(void *attr, const char *input, int *err);
void *attr_default;
enum print_ops print;
};
/* List of all Test Attributes */
static struct kunit_attr kunit_attr_list[] = {};
/* Helper Functions to Access Attributes */
void kunit_print_attr(void *test_or_suite, bool is_test, unsigned int test_level)
{
int i;
bool to_free;
void *attr;
const char *attr_name, *attr_str;
struct kunit_suite *suite = is_test ? NULL : test_or_suite;
struct kunit_case *test = is_test ? test_or_suite : NULL;
for (i = 0; i < ARRAY_SIZE(kunit_attr_list); i++) {
if (kunit_attr_list[i].print == PRINT_NEVER ||
(test && kunit_attr_list[i].print == PRINT_SUITE))
continue;
attr = kunit_attr_list[i].get_attr(test_or_suite, is_test);
if (attr) {
attr_name = kunit_attr_list[i].name;
attr_str = kunit_attr_list[i].to_string(attr, &to_free);
if (test) {
kunit_log(KERN_INFO, test, "%*s# %s.%s: %s",
KUNIT_INDENT_LEN * test_level, "", test->name,
attr_name, attr_str);
} else {
kunit_log(KERN_INFO, suite, "%*s# %s: %s",
KUNIT_INDENT_LEN * test_level, "", attr_name, attr_str);
}
/* Free to_string of attribute if needed */
if (to_free)
kfree(attr_str);
}
}
}