1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * KUnit API to save and access test attributes 4 * 5 * Copyright (C) 2023, Google LLC. 6 * Author: Rae Moar <[email protected]> 7 */ 8 9 #include <kunit/test.h> 10 #include <kunit/attributes.h> 11 12 /* Options for printing attributes: 13 * PRINT_ALWAYS - attribute is printed for every test case and suite if set 14 * PRINT_SUITE - attribute is printed for every suite if set but not for test cases 15 * PRINT_NEVER - attribute is never printed 16 */ 17 enum print_ops { 18 PRINT_ALWAYS, 19 PRINT_SUITE, 20 PRINT_NEVER, 21 }; 22 23 /** 24 * struct kunit_attr - represents a test attribute and holds flexible 25 * helper functions to interact with attribute. 26 * 27 * @name: name of test attribute, eg. speed 28 * @get_attr: function to return attribute value given a test 29 * @to_string: function to return string representation of given 30 * attribute value 31 * @filter: function to indicate whether a given attribute value passes a 32 * filter 33 */ 34 struct kunit_attr { 35 const char *name; 36 void *(*get_attr)(void *test_or_suite, bool is_test); 37 const char *(*to_string)(void *attr, bool *to_free); 38 int (*filter)(void *attr, const char *input, int *err); 39 void *attr_default; 40 enum print_ops print; 41 }; 42 43 /* String Lists for enum Attributes */ 44 45 static const char * const speed_str_list[] = {"unset", "very_slow", "slow", "normal"}; 46 47 /* To String Methods */ 48 49 static const char *attr_enum_to_string(void *attr, const char * const str_list[], bool *to_free) 50 { 51 long val = (long)attr; 52 53 *to_free = false; 54 if (!val) 55 return NULL; 56 return str_list[val]; 57 } 58 59 static const char *attr_speed_to_string(void *attr, bool *to_free) 60 { 61 return attr_enum_to_string(attr, speed_str_list, to_free); 62 } 63 64 static const char *attr_string_to_string(void *attr, bool *to_free) 65 { 66 *to_free = false; 67 return (char *) attr; 68 } 69 70 /* Get Attribute Methods */ 71 72 static void *attr_speed_get(void *test_or_suite, bool is_test) 73 { 74 struct kunit_suite *suite = is_test ? NULL : test_or_suite; 75 struct kunit_case *test = is_test ? test_or_suite : NULL; 76 77 if (test) 78 return ((void *) test->attr.speed); 79 else 80 return ((void *) suite->attr.speed); 81 } 82 83 static void *attr_module_get(void *test_or_suite, bool is_test) 84 { 85 struct kunit_suite *suite = is_test ? NULL : test_or_suite; 86 struct kunit_case *test = is_test ? test_or_suite : NULL; 87 88 // Suites get their module attribute from their first test_case 89 if (test) 90 return ((void *) test->module_name); 91 else 92 return ((void *) suite->test_cases[0].module_name); 93 } 94 95 /* List of all Test Attributes */ 96 97 static struct kunit_attr kunit_attr_list[] = { 98 { 99 .name = "speed", 100 .get_attr = attr_speed_get, 101 .to_string = attr_speed_to_string, 102 .attr_default = (void *)KUNIT_SPEED_NORMAL, 103 .print = PRINT_ALWAYS, 104 }, 105 { 106 .name = "module", 107 .get_attr = attr_module_get, 108 .to_string = attr_string_to_string, 109 .attr_default = (void *)"", 110 .print = PRINT_SUITE, 111 } 112 }; 113 114 /* Helper Functions to Access Attributes */ 115 116 void kunit_print_attr(void *test_or_suite, bool is_test, unsigned int test_level) 117 { 118 int i; 119 bool to_free; 120 void *attr; 121 const char *attr_name, *attr_str; 122 struct kunit_suite *suite = is_test ? NULL : test_or_suite; 123 struct kunit_case *test = is_test ? test_or_suite : NULL; 124 125 for (i = 0; i < ARRAY_SIZE(kunit_attr_list); i++) { 126 if (kunit_attr_list[i].print == PRINT_NEVER || 127 (test && kunit_attr_list[i].print == PRINT_SUITE)) 128 continue; 129 attr = kunit_attr_list[i].get_attr(test_or_suite, is_test); 130 if (attr) { 131 attr_name = kunit_attr_list[i].name; 132 attr_str = kunit_attr_list[i].to_string(attr, &to_free); 133 if (test) { 134 kunit_log(KERN_INFO, test, "%*s# %s.%s: %s", 135 KUNIT_INDENT_LEN * test_level, "", test->name, 136 attr_name, attr_str); 137 } else { 138 kunit_log(KERN_INFO, suite, "%*s# %s: %s", 139 KUNIT_INDENT_LEN * test_level, "", attr_name, attr_str); 140 } 141 142 /* Free to_string of attribute if needed */ 143 if (to_free) 144 kfree(attr_str); 145 } 146 } 147 } 148