162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * KUnit API to save and access test attributes 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2023, Google LLC. 662306a36Sopenharmony_ci * Author: Rae Moar <rmoar@google.com> 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <kunit/test.h> 1062306a36Sopenharmony_ci#include <kunit/attributes.h> 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci/* Options for printing attributes: 1362306a36Sopenharmony_ci * PRINT_ALWAYS - attribute is printed for every test case and suite if set 1462306a36Sopenharmony_ci * PRINT_SUITE - attribute is printed for every suite if set but not for test cases 1562306a36Sopenharmony_ci * PRINT_NEVER - attribute is never printed 1662306a36Sopenharmony_ci */ 1762306a36Sopenharmony_cienum print_ops { 1862306a36Sopenharmony_ci PRINT_ALWAYS, 1962306a36Sopenharmony_ci PRINT_SUITE, 2062306a36Sopenharmony_ci PRINT_NEVER, 2162306a36Sopenharmony_ci}; 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci/** 2462306a36Sopenharmony_ci * struct kunit_attr - represents a test attribute and holds flexible 2562306a36Sopenharmony_ci * helper functions to interact with attribute. 2662306a36Sopenharmony_ci * 2762306a36Sopenharmony_ci * @name: name of test attribute, eg. speed 2862306a36Sopenharmony_ci * @get_attr: function to return attribute value given a test 2962306a36Sopenharmony_ci * @to_string: function to return string representation of given 3062306a36Sopenharmony_ci * attribute value 3162306a36Sopenharmony_ci * @filter: function to indicate whether a given attribute value passes a 3262306a36Sopenharmony_ci * filter 3362306a36Sopenharmony_ci * @attr_default: default attribute value used during filtering 3462306a36Sopenharmony_ci * @print: value of enum print_ops to indicate when to print attribute 3562306a36Sopenharmony_ci */ 3662306a36Sopenharmony_cistruct kunit_attr { 3762306a36Sopenharmony_ci const char *name; 3862306a36Sopenharmony_ci void *(*get_attr)(void *test_or_suite, bool is_test); 3962306a36Sopenharmony_ci const char *(*to_string)(void *attr, bool *to_free); 4062306a36Sopenharmony_ci int (*filter)(void *attr, const char *input, int *err); 4162306a36Sopenharmony_ci void *attr_default; 4262306a36Sopenharmony_ci enum print_ops print; 4362306a36Sopenharmony_ci}; 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci/* String Lists for enum Attributes */ 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_cistatic const char * const speed_str_list[] = {"unset", "very_slow", "slow", "normal"}; 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci/* To String Methods */ 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_cistatic const char *attr_enum_to_string(void *attr, const char * const str_list[], bool *to_free) 5262306a36Sopenharmony_ci{ 5362306a36Sopenharmony_ci long val = (long)attr; 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci *to_free = false; 5662306a36Sopenharmony_ci if (!val) 5762306a36Sopenharmony_ci return NULL; 5862306a36Sopenharmony_ci return str_list[val]; 5962306a36Sopenharmony_ci} 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_cistatic const char *attr_speed_to_string(void *attr, bool *to_free) 6262306a36Sopenharmony_ci{ 6362306a36Sopenharmony_ci return attr_enum_to_string(attr, speed_str_list, to_free); 6462306a36Sopenharmony_ci} 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_cistatic const char *attr_string_to_string(void *attr, bool *to_free) 6762306a36Sopenharmony_ci{ 6862306a36Sopenharmony_ci *to_free = false; 6962306a36Sopenharmony_ci return (char *) attr; 7062306a36Sopenharmony_ci} 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci/* Filter Methods */ 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_cistatic const char op_list[] = "<>!="; 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci/* 7762306a36Sopenharmony_ci * Returns whether the inputted integer value matches the filter given 7862306a36Sopenharmony_ci * by the operation string and inputted integer. 7962306a36Sopenharmony_ci */ 8062306a36Sopenharmony_cistatic int int_filter(long val, const char *op, int input, int *err) 8162306a36Sopenharmony_ci{ 8262306a36Sopenharmony_ci if (!strncmp(op, "<=", 2)) 8362306a36Sopenharmony_ci return (val <= input); 8462306a36Sopenharmony_ci else if (!strncmp(op, ">=", 2)) 8562306a36Sopenharmony_ci return (val >= input); 8662306a36Sopenharmony_ci else if (!strncmp(op, "!=", 2)) 8762306a36Sopenharmony_ci return (val != input); 8862306a36Sopenharmony_ci else if (!strncmp(op, ">", 1)) 8962306a36Sopenharmony_ci return (val > input); 9062306a36Sopenharmony_ci else if (!strncmp(op, "<", 1)) 9162306a36Sopenharmony_ci return (val < input); 9262306a36Sopenharmony_ci else if (!strncmp(op, "=", 1)) 9362306a36Sopenharmony_ci return (val == input); 9462306a36Sopenharmony_ci *err = -EINVAL; 9562306a36Sopenharmony_ci pr_err("kunit executor: invalid filter operation: %s\n", op); 9662306a36Sopenharmony_ci return false; 9762306a36Sopenharmony_ci} 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci/* 10062306a36Sopenharmony_ci * Returns whether the inputted enum value "attr" matches the filter given 10162306a36Sopenharmony_ci * by the input string. Note: the str_list includes the corresponding string 10262306a36Sopenharmony_ci * list to the enum values. 10362306a36Sopenharmony_ci */ 10462306a36Sopenharmony_cistatic int attr_enum_filter(void *attr, const char *input, int *err, 10562306a36Sopenharmony_ci const char * const str_list[], int max) 10662306a36Sopenharmony_ci{ 10762306a36Sopenharmony_ci int i, j, input_int = -1; 10862306a36Sopenharmony_ci long test_val = (long)attr; 10962306a36Sopenharmony_ci const char *input_val = NULL; 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci for (i = 0; input[i]; i++) { 11262306a36Sopenharmony_ci if (!strchr(op_list, input[i])) { 11362306a36Sopenharmony_ci input_val = input + i; 11462306a36Sopenharmony_ci break; 11562306a36Sopenharmony_ci } 11662306a36Sopenharmony_ci } 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci if (!input_val) { 11962306a36Sopenharmony_ci *err = -EINVAL; 12062306a36Sopenharmony_ci pr_err("kunit executor: filter value not found: %s\n", input); 12162306a36Sopenharmony_ci return false; 12262306a36Sopenharmony_ci } 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci for (j = 0; j <= max; j++) { 12562306a36Sopenharmony_ci if (!strcmp(input_val, str_list[j])) 12662306a36Sopenharmony_ci input_int = j; 12762306a36Sopenharmony_ci } 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci if (input_int < 0) { 13062306a36Sopenharmony_ci *err = -EINVAL; 13162306a36Sopenharmony_ci pr_err("kunit executor: invalid filter input: %s\n", input); 13262306a36Sopenharmony_ci return false; 13362306a36Sopenharmony_ci } 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci return int_filter(test_val, input, input_int, err); 13662306a36Sopenharmony_ci} 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_cistatic int attr_speed_filter(void *attr, const char *input, int *err) 13962306a36Sopenharmony_ci{ 14062306a36Sopenharmony_ci return attr_enum_filter(attr, input, err, speed_str_list, KUNIT_SPEED_MAX); 14162306a36Sopenharmony_ci} 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci/* 14462306a36Sopenharmony_ci * Returns whether the inputted string value (attr) matches the filter given 14562306a36Sopenharmony_ci * by the input string. 14662306a36Sopenharmony_ci */ 14762306a36Sopenharmony_cistatic int attr_string_filter(void *attr, const char *input, int *err) 14862306a36Sopenharmony_ci{ 14962306a36Sopenharmony_ci char *str = attr; 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci if (!strncmp(input, "<", 1)) { 15262306a36Sopenharmony_ci *err = -EINVAL; 15362306a36Sopenharmony_ci pr_err("kunit executor: invalid filter input: %s\n", input); 15462306a36Sopenharmony_ci return false; 15562306a36Sopenharmony_ci } else if (!strncmp(input, ">", 1)) { 15662306a36Sopenharmony_ci *err = -EINVAL; 15762306a36Sopenharmony_ci pr_err("kunit executor: invalid filter input: %s\n", input); 15862306a36Sopenharmony_ci return false; 15962306a36Sopenharmony_ci } else if (!strncmp(input, "!=", 2)) { 16062306a36Sopenharmony_ci return (strcmp(input + 2, str) != 0); 16162306a36Sopenharmony_ci } else if (!strncmp(input, "=", 1)) { 16262306a36Sopenharmony_ci return (strcmp(input + 1, str) == 0); 16362306a36Sopenharmony_ci } 16462306a36Sopenharmony_ci *err = -EINVAL; 16562306a36Sopenharmony_ci pr_err("kunit executor: invalid filter operation: %s\n", input); 16662306a36Sopenharmony_ci return false; 16762306a36Sopenharmony_ci} 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci/* Get Attribute Methods */ 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_cistatic void *attr_speed_get(void *test_or_suite, bool is_test) 17362306a36Sopenharmony_ci{ 17462306a36Sopenharmony_ci struct kunit_suite *suite = is_test ? NULL : test_or_suite; 17562306a36Sopenharmony_ci struct kunit_case *test = is_test ? test_or_suite : NULL; 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci if (test) 17862306a36Sopenharmony_ci return ((void *) test->attr.speed); 17962306a36Sopenharmony_ci else 18062306a36Sopenharmony_ci return ((void *) suite->attr.speed); 18162306a36Sopenharmony_ci} 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_cistatic void *attr_module_get(void *test_or_suite, bool is_test) 18462306a36Sopenharmony_ci{ 18562306a36Sopenharmony_ci struct kunit_suite *suite = is_test ? NULL : test_or_suite; 18662306a36Sopenharmony_ci struct kunit_case *test = is_test ? test_or_suite : NULL; 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci // Suites get their module attribute from their first test_case 18962306a36Sopenharmony_ci if (test) 19062306a36Sopenharmony_ci return ((void *) test->module_name); 19162306a36Sopenharmony_ci else if (kunit_suite_num_test_cases(suite) > 0) 19262306a36Sopenharmony_ci return ((void *) suite->test_cases[0].module_name); 19362306a36Sopenharmony_ci else 19462306a36Sopenharmony_ci return (void *) ""; 19562306a36Sopenharmony_ci} 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci/* List of all Test Attributes */ 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_cistatic struct kunit_attr kunit_attr_list[] = { 20062306a36Sopenharmony_ci { 20162306a36Sopenharmony_ci .name = "speed", 20262306a36Sopenharmony_ci .get_attr = attr_speed_get, 20362306a36Sopenharmony_ci .to_string = attr_speed_to_string, 20462306a36Sopenharmony_ci .filter = attr_speed_filter, 20562306a36Sopenharmony_ci .attr_default = (void *)KUNIT_SPEED_NORMAL, 20662306a36Sopenharmony_ci .print = PRINT_ALWAYS, 20762306a36Sopenharmony_ci }, 20862306a36Sopenharmony_ci { 20962306a36Sopenharmony_ci .name = "module", 21062306a36Sopenharmony_ci .get_attr = attr_module_get, 21162306a36Sopenharmony_ci .to_string = attr_string_to_string, 21262306a36Sopenharmony_ci .filter = attr_string_filter, 21362306a36Sopenharmony_ci .attr_default = (void *)"", 21462306a36Sopenharmony_ci .print = PRINT_SUITE, 21562306a36Sopenharmony_ci } 21662306a36Sopenharmony_ci}; 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci/* Helper Functions to Access Attributes */ 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ciconst char *kunit_attr_filter_name(struct kunit_attr_filter filter) 22162306a36Sopenharmony_ci{ 22262306a36Sopenharmony_ci return filter.attr->name; 22362306a36Sopenharmony_ci} 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_civoid kunit_print_attr(void *test_or_suite, bool is_test, unsigned int test_level) 22662306a36Sopenharmony_ci{ 22762306a36Sopenharmony_ci int i; 22862306a36Sopenharmony_ci bool to_free = false; 22962306a36Sopenharmony_ci void *attr; 23062306a36Sopenharmony_ci const char *attr_name, *attr_str; 23162306a36Sopenharmony_ci struct kunit_suite *suite = is_test ? NULL : test_or_suite; 23262306a36Sopenharmony_ci struct kunit_case *test = is_test ? test_or_suite : NULL; 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(kunit_attr_list); i++) { 23562306a36Sopenharmony_ci if (kunit_attr_list[i].print == PRINT_NEVER || 23662306a36Sopenharmony_ci (test && kunit_attr_list[i].print == PRINT_SUITE)) 23762306a36Sopenharmony_ci continue; 23862306a36Sopenharmony_ci attr = kunit_attr_list[i].get_attr(test_or_suite, is_test); 23962306a36Sopenharmony_ci if (attr) { 24062306a36Sopenharmony_ci attr_name = kunit_attr_list[i].name; 24162306a36Sopenharmony_ci attr_str = kunit_attr_list[i].to_string(attr, &to_free); 24262306a36Sopenharmony_ci if (test) { 24362306a36Sopenharmony_ci kunit_log(KERN_INFO, test, "%*s# %s.%s: %s", 24462306a36Sopenharmony_ci KUNIT_INDENT_LEN * test_level, "", test->name, 24562306a36Sopenharmony_ci attr_name, attr_str); 24662306a36Sopenharmony_ci } else { 24762306a36Sopenharmony_ci kunit_log(KERN_INFO, suite, "%*s# %s: %s", 24862306a36Sopenharmony_ci KUNIT_INDENT_LEN * test_level, "", attr_name, attr_str); 24962306a36Sopenharmony_ci } 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci /* Free to_string of attribute if needed */ 25262306a36Sopenharmony_ci if (to_free) 25362306a36Sopenharmony_ci kfree(attr_str); 25462306a36Sopenharmony_ci } 25562306a36Sopenharmony_ci } 25662306a36Sopenharmony_ci} 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci/* Helper Functions to Filter Attributes */ 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ciint kunit_get_filter_count(char *input) 26162306a36Sopenharmony_ci{ 26262306a36Sopenharmony_ci int i, comma_index = 0, count = 0; 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci for (i = 0; input[i]; i++) { 26562306a36Sopenharmony_ci if (input[i] == ',') { 26662306a36Sopenharmony_ci if ((i - comma_index) > 1) 26762306a36Sopenharmony_ci count++; 26862306a36Sopenharmony_ci comma_index = i; 26962306a36Sopenharmony_ci } 27062306a36Sopenharmony_ci } 27162306a36Sopenharmony_ci if ((i - comma_index) > 0) 27262306a36Sopenharmony_ci count++; 27362306a36Sopenharmony_ci return count; 27462306a36Sopenharmony_ci} 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_cistruct kunit_attr_filter kunit_next_attr_filter(char **filters, int *err) 27762306a36Sopenharmony_ci{ 27862306a36Sopenharmony_ci struct kunit_attr_filter filter = {}; 27962306a36Sopenharmony_ci int i, j, comma_index = 0, new_start_index = 0; 28062306a36Sopenharmony_ci int op_index = -1, attr_index = -1; 28162306a36Sopenharmony_ci char op; 28262306a36Sopenharmony_ci char *input = *filters; 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci /* Parse input until operation */ 28562306a36Sopenharmony_ci for (i = 0; input[i]; i++) { 28662306a36Sopenharmony_ci if (op_index < 0 && strchr(op_list, input[i])) { 28762306a36Sopenharmony_ci op_index = i; 28862306a36Sopenharmony_ci } else if (!comma_index && input[i] == ',') { 28962306a36Sopenharmony_ci comma_index = i; 29062306a36Sopenharmony_ci } else if (comma_index && input[i] != ' ') { 29162306a36Sopenharmony_ci new_start_index = i; 29262306a36Sopenharmony_ci break; 29362306a36Sopenharmony_ci } 29462306a36Sopenharmony_ci } 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci if (op_index <= 0) { 29762306a36Sopenharmony_ci *err = -EINVAL; 29862306a36Sopenharmony_ci pr_err("kunit executor: filter operation not found: %s\n", input); 29962306a36Sopenharmony_ci return filter; 30062306a36Sopenharmony_ci } 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci /* Temporarily set operator to \0 character. */ 30362306a36Sopenharmony_ci op = input[op_index]; 30462306a36Sopenharmony_ci input[op_index] = '\0'; 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci /* Find associated kunit_attr object */ 30762306a36Sopenharmony_ci for (j = 0; j < ARRAY_SIZE(kunit_attr_list); j++) { 30862306a36Sopenharmony_ci if (!strcmp(input, kunit_attr_list[j].name)) { 30962306a36Sopenharmony_ci attr_index = j; 31062306a36Sopenharmony_ci break; 31162306a36Sopenharmony_ci } 31262306a36Sopenharmony_ci } 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci input[op_index] = op; 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci if (attr_index < 0) { 31762306a36Sopenharmony_ci *err = -EINVAL; 31862306a36Sopenharmony_ci pr_err("kunit executor: attribute not found: %s\n", input); 31962306a36Sopenharmony_ci } else { 32062306a36Sopenharmony_ci filter.attr = &kunit_attr_list[attr_index]; 32162306a36Sopenharmony_ci } 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci if (comma_index > 0) { 32462306a36Sopenharmony_ci input[comma_index] = '\0'; 32562306a36Sopenharmony_ci filter.input = input + op_index; 32662306a36Sopenharmony_ci input = input + new_start_index; 32762306a36Sopenharmony_ci } else { 32862306a36Sopenharmony_ci filter.input = input + op_index; 32962306a36Sopenharmony_ci input = NULL; 33062306a36Sopenharmony_ci } 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci *filters = input; 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci return filter; 33562306a36Sopenharmony_ci} 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_cistruct kunit_suite *kunit_filter_attr_tests(const struct kunit_suite *const suite, 33862306a36Sopenharmony_ci struct kunit_attr_filter filter, char *action, int *err) 33962306a36Sopenharmony_ci{ 34062306a36Sopenharmony_ci int n = 0; 34162306a36Sopenharmony_ci struct kunit_case *filtered, *test_case; 34262306a36Sopenharmony_ci struct kunit_suite *copy; 34362306a36Sopenharmony_ci void *suite_val, *test_val; 34462306a36Sopenharmony_ci bool suite_result, test_result, default_result, result; 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci /* Allocate memory for new copy of suite and list of test cases */ 34762306a36Sopenharmony_ci copy = kmemdup(suite, sizeof(*copy), GFP_KERNEL); 34862306a36Sopenharmony_ci if (!copy) 34962306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci kunit_suite_for_each_test_case(suite, test_case) { n++; } 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci filtered = kcalloc(n + 1, sizeof(*filtered), GFP_KERNEL); 35462306a36Sopenharmony_ci if (!filtered) { 35562306a36Sopenharmony_ci kfree(copy); 35662306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 35762306a36Sopenharmony_ci } 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci n = 0; 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci /* Save filtering result on default value */ 36262306a36Sopenharmony_ci default_result = filter.attr->filter(filter.attr->attr_default, filter.input, err); 36362306a36Sopenharmony_ci if (*err) 36462306a36Sopenharmony_ci goto err; 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci /* Save suite attribute value and filtering result on that value */ 36762306a36Sopenharmony_ci suite_val = filter.attr->get_attr((void *)suite, false); 36862306a36Sopenharmony_ci suite_result = filter.attr->filter(suite_val, filter.input, err); 36962306a36Sopenharmony_ci if (*err) 37062306a36Sopenharmony_ci goto err; 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci /* For each test case, save test case if passes filtering. */ 37362306a36Sopenharmony_ci kunit_suite_for_each_test_case(suite, test_case) { 37462306a36Sopenharmony_ci test_val = filter.attr->get_attr((void *) test_case, true); 37562306a36Sopenharmony_ci test_result = filter.attr->filter(filter.attr->get_attr(test_case, true), 37662306a36Sopenharmony_ci filter.input, err); 37762306a36Sopenharmony_ci if (*err) 37862306a36Sopenharmony_ci goto err; 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci /* 38162306a36Sopenharmony_ci * If attribute value of test case is set, filter on that value. 38262306a36Sopenharmony_ci * If not, filter on suite value if set. If not, filter on 38362306a36Sopenharmony_ci * default value. 38462306a36Sopenharmony_ci */ 38562306a36Sopenharmony_ci result = false; 38662306a36Sopenharmony_ci if (test_val) { 38762306a36Sopenharmony_ci if (test_result) 38862306a36Sopenharmony_ci result = true; 38962306a36Sopenharmony_ci } else if (suite_val) { 39062306a36Sopenharmony_ci if (suite_result) 39162306a36Sopenharmony_ci result = true; 39262306a36Sopenharmony_ci } else if (default_result) { 39362306a36Sopenharmony_ci result = true; 39462306a36Sopenharmony_ci } 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci if (result) { 39762306a36Sopenharmony_ci filtered[n++] = *test_case; 39862306a36Sopenharmony_ci } else if (action && strcmp(action, "skip") == 0) { 39962306a36Sopenharmony_ci test_case->status = KUNIT_SKIPPED; 40062306a36Sopenharmony_ci filtered[n++] = *test_case; 40162306a36Sopenharmony_ci } 40262306a36Sopenharmony_ci } 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_cierr: 40562306a36Sopenharmony_ci if (n == 0 || *err) { 40662306a36Sopenharmony_ci kfree(copy); 40762306a36Sopenharmony_ci kfree(filtered); 40862306a36Sopenharmony_ci return NULL; 40962306a36Sopenharmony_ci } 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci copy->test_cases = filtered; 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci return copy; 41462306a36Sopenharmony_ci} 415