@@ -67,6 +67,104 @@ static const char *attr_string_to_string(void *attr, bool *to_free)
67
67
return (char * ) attr ;
68
68
}
69
69
70
+ /* Filter Methods */
71
+
72
+ static const char op_list [] = "<>!=" ;
73
+
74
+ /*
75
+ * Returns whether the inputted integer value matches the filter given
76
+ * by the operation string and inputted integer.
77
+ */
78
+ static int int_filter (long val , const char * op , int input , int * err )
79
+ {
80
+ if (!strncmp (op , "<=" , 2 ))
81
+ return (val <= input );
82
+ else if (!strncmp (op , ">=" , 2 ))
83
+ return (val >= input );
84
+ else if (!strncmp (op , "!=" , 2 ))
85
+ return (val != input );
86
+ else if (!strncmp (op , ">" , 1 ))
87
+ return (val > input );
88
+ else if (!strncmp (op , "<" , 1 ))
89
+ return (val < input );
90
+ else if (!strncmp (op , "=" , 1 ))
91
+ return (val == input );
92
+ * err = - EINVAL ;
93
+ pr_err ("kunit executor: invalid filter operation: %s\n" , op );
94
+ return false;
95
+ }
96
+
97
+ /*
98
+ * Returns whether the inputted enum value "attr" matches the filter given
99
+ * by the input string. Note: the str_list includes the corresponding string
100
+ * list to the enum values.
101
+ */
102
+ static int attr_enum_filter (void * attr , const char * input , int * err ,
103
+ const char * const str_list [], int max )
104
+ {
105
+ int i , j , input_int ;
106
+ long test_val = (long )attr ;
107
+ const char * input_val = NULL ;
108
+
109
+ for (i = 0 ; input [i ]; i ++ ) {
110
+ if (!strchr (op_list , input [i ])) {
111
+ input_val = input + i ;
112
+ break ;
113
+ }
114
+ }
115
+
116
+ if (!input_val ) {
117
+ * err = - EINVAL ;
118
+ pr_err ("kunit executor: filter value not found: %s\n" , input );
119
+ return false;
120
+ }
121
+
122
+ for (j = 0 ; j <= max ; j ++ ) {
123
+ if (!strcmp (input_val , str_list [j ]))
124
+ input_int = j ;
125
+ }
126
+
127
+ if (!input_int ) {
128
+ * err = - EINVAL ;
129
+ pr_err ("kunit executor: invalid filter input: %s\n" , input );
130
+ return false;
131
+ }
132
+
133
+ return int_filter (test_val , input , input_int , err );
134
+ }
135
+
136
+ static int attr_speed_filter (void * attr , const char * input , int * err )
137
+ {
138
+ return attr_enum_filter (attr , input , err , speed_str_list , KUNIT_SPEED_MAX );
139
+ }
140
+
141
+ /*
142
+ * Returns whether the inputted string value (attr) matches the filter given
143
+ * by the input string.
144
+ */
145
+ static int attr_string_filter (void * attr , const char * input , int * err )
146
+ {
147
+ char * str = attr ;
148
+
149
+ if (!strncmp (input , "<" , 1 )) {
150
+ * err = - EINVAL ;
151
+ pr_err ("kunit executor: invalid filter input: %s\n" , input );
152
+ return false;
153
+ } else if (!strncmp (input , ">" , 1 )) {
154
+ * err = - EINVAL ;
155
+ pr_err ("kunit executor: invalid filter input: %s\n" , input );
156
+ return false;
157
+ } else if (!strncmp (input , "!=" , 2 )) {
158
+ return (strcmp (input + 2 , str ) != 0 );
159
+ } else if (!strncmp (input , "=" , 1 )) {
160
+ return (strcmp (input + 1 , str ) == 0 );
161
+ }
162
+ * err = - EINVAL ;
163
+ pr_err ("kunit executor: invalid filter operation: %s\n" , input );
164
+ return false;
165
+ }
166
+
167
+
70
168
/* Get Attribute Methods */
71
169
72
170
static void * attr_speed_get (void * test_or_suite , bool is_test )
@@ -99,20 +197,27 @@ static struct kunit_attr kunit_attr_list[] = {
99
197
.name = "speed" ,
100
198
.get_attr = attr_speed_get ,
101
199
.to_string = attr_speed_to_string ,
200
+ .filter = attr_speed_filter ,
102
201
.attr_default = (void * )KUNIT_SPEED_NORMAL ,
103
202
.print = PRINT_ALWAYS ,
104
203
},
105
204
{
106
205
.name = "module" ,
107
206
.get_attr = attr_module_get ,
108
207
.to_string = attr_string_to_string ,
208
+ .filter = attr_string_filter ,
109
209
.attr_default = (void * )"" ,
110
210
.print = PRINT_SUITE ,
111
211
}
112
212
};
113
213
114
214
/* Helper Functions to Access Attributes */
115
215
216
+ const char * kunit_attr_filter_name (struct kunit_attr_filter filter )
217
+ {
218
+ return filter .attr -> name ;
219
+ }
220
+
116
221
void kunit_print_attr (void * test_or_suite , bool is_test , unsigned int test_level )
117
222
{
118
223
int i ;
@@ -145,3 +250,169 @@ void kunit_print_attr(void *test_or_suite, bool is_test, unsigned int test_level
145
250
}
146
251
}
147
252
}
253
+
254
+ /* Helper Functions to Filter Attributes */
255
+
256
+ int kunit_get_filter_count (char * input )
257
+ {
258
+ int i , comma_index , count = 0 ;
259
+
260
+ for (i = 0 ; input [i ]; i ++ ) {
261
+ if (input [i ] == ',' ) {
262
+ if ((i - comma_index ) > 1 )
263
+ count ++ ;
264
+ comma_index = i ;
265
+ }
266
+ }
267
+ if ((i - comma_index ) > 0 )
268
+ count ++ ;
269
+ return count ;
270
+ }
271
+
272
+ struct kunit_attr_filter kunit_next_attr_filter (char * * filters , int * err )
273
+ {
274
+ struct kunit_attr_filter filter = {};
275
+ int i , j , comma_index , new_start_index ;
276
+ int op_index = -1 , attr_index = -1 ;
277
+ char op ;
278
+ char * input = * filters ;
279
+
280
+ /* Parse input until operation */
281
+ for (i = 0 ; input [i ]; i ++ ) {
282
+ if (op_index < 0 && strchr (op_list , input [i ])) {
283
+ op_index = i ;
284
+ } else if (!comma_index && input [i ] == ',' ) {
285
+ comma_index = i ;
286
+ } else if (comma_index && input [i ] != ' ' ) {
287
+ new_start_index = i ;
288
+ break ;
289
+ }
290
+ }
291
+
292
+ if (op_index <= 0 ) {
293
+ * err = - EINVAL ;
294
+ pr_err ("kunit executor: filter operation not found: %s\n" , input );
295
+ return filter ;
296
+ }
297
+
298
+ /* Temporarily set operator to \0 character. */
299
+ op = input [op_index ];
300
+ input [op_index ] = '\0' ;
301
+
302
+ /* Find associated kunit_attr object */
303
+ for (j = 0 ; j < ARRAY_SIZE (kunit_attr_list ); j ++ ) {
304
+ if (!strcmp (input , kunit_attr_list [j ].name )) {
305
+ attr_index = j ;
306
+ break ;
307
+ }
308
+ }
309
+
310
+ input [op_index ] = op ;
311
+
312
+ if (attr_index < 0 ) {
313
+ * err = - EINVAL ;
314
+ pr_err ("kunit executor: attribute not found: %s\n" , input );
315
+ } else {
316
+ filter .attr = & kunit_attr_list [attr_index ];
317
+ }
318
+
319
+ if (comma_index ) {
320
+ input [comma_index ] = '\0' ;
321
+ filter .input = input + op_index ;
322
+ input = input + new_start_index ;
323
+ } else {
324
+ filter .input = input + op_index ;
325
+ input = NULL ;
326
+ }
327
+
328
+ * filters = input ;
329
+
330
+ return filter ;
331
+ }
332
+
333
+ struct kunit_suite * kunit_filter_attr_tests (const struct kunit_suite * const suite ,
334
+ struct kunit_attr_filter filter , char * action , int * err )
335
+ {
336
+ int n = 0 ;
337
+ struct kunit_case * filtered , * test_case ;
338
+ struct kunit_suite * copy ;
339
+ void * suite_val , * test_val ;
340
+ bool suite_result , test_result , default_result , result ;
341
+
342
+ /* Allocate memory for new copy of suite and list of test cases */
343
+ copy = kmemdup (suite , sizeof (* copy ), GFP_KERNEL );
344
+ if (!copy )
345
+ return ERR_PTR (- ENOMEM );
346
+
347
+ kunit_suite_for_each_test_case (suite , test_case ) { n ++ ; }
348
+
349
+ filtered = kcalloc (n + 1 , sizeof (* filtered ), GFP_KERNEL );
350
+ if (!filtered ) {
351
+ kfree (copy );
352
+ return ERR_PTR (- ENOMEM );
353
+ }
354
+
355
+ n = 0 ;
356
+
357
+ /* Save filtering result on default value */
358
+ default_result = filter .attr -> filter (filter .attr -> attr_default , filter .input , err );
359
+ if (* err ) {
360
+ kfree (copy );
361
+ kfree (filtered );
362
+ return NULL ;
363
+ }
364
+
365
+ /* Save suite attribute value and filtering result on that value */
366
+ suite_val = filter .attr -> get_attr ((void * )suite , false);
367
+ suite_result = filter .attr -> filter (suite_val , filter .input , err );
368
+ if (* err ) {
369
+ kfree (copy );
370
+ kfree (filtered );
371
+ return NULL ;
372
+ }
373
+
374
+ /* For each test case, save test case if passes filtering. */
375
+ kunit_suite_for_each_test_case (suite , test_case ) {
376
+ test_val = filter .attr -> get_attr ((void * ) test_case , true);
377
+ test_result = filter .attr -> filter (filter .attr -> get_attr (test_case , true),
378
+ filter .input , err );
379
+ if (* err ) {
380
+ kfree (copy );
381
+ kfree (filtered );
382
+ return NULL ;
383
+ }
384
+
385
+ /*
386
+ * If attribute value of test case is set, filter on that value.
387
+ * If not, filter on suite value if set. If not, filter on
388
+ * default value.
389
+ */
390
+ result = false;
391
+ if (test_val ) {
392
+ if (test_result )
393
+ result = true;
394
+ } else if (suite_val ) {
395
+ if (suite_result )
396
+ result = true;
397
+ } else if (default_result ) {
398
+ result = true;
399
+ }
400
+
401
+ if (result ) {
402
+ filtered [n ++ ] = * test_case ;
403
+ } else if (action && strcmp (action , "skip" ) == 0 ) {
404
+ test_case -> status = KUNIT_SKIPPED ;
405
+ filtered [n ++ ] = * test_case ;
406
+ }
407
+ }
408
+
409
+ if (n == 0 ) {
410
+ kfree (copy );
411
+ kfree (filtered );
412
+ return NULL ;
413
+ }
414
+
415
+ copy -> test_cases = filtered ;
416
+
417
+ return copy ;
418
+ }
0 commit comments