Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'linux_kselftest-kunit-6.7-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/shuah/linux-kselftest

Pull kunit updates from Shuah Khan:

- string-stream testing enhancements

- several fixes memory leaks

- fix to reset status during parameter handling

* tag 'linux_kselftest-kunit-6.7-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/shuah/linux-kselftest:
kunit: test: Fix the possible memory leak in executor_test
kunit: Fix possible memory leak in kunit_filter_suites()
kunit: Fix the wrong kfree of copy for kunit_filter_suites()
kunit: Fix missed memory release in kunit_free_suite_set()
kunit: Reset test status on each param iteration
kunit: string-stream: Test performance of string_stream
kunit: Use string_stream for test log
kunit: string-stream: Add tests for freeing resource-managed string_stream
kunit: string-stream: Decouple string_stream from kunit
kunit: string-stream: Add kunit_alloc_string_stream()
kunit: Don't use a managed alloc in is_literal()
kunit: string-stream-test: Add cases for string_stream newline appending
kunit: string-stream: Add option to make all lines end with newline
kunit: string-stream: Improve testing of string_stream
kunit: string-stream: Don't create a fragment for empty strings

+734 -147
+6 -8
include/kunit/test.h
··· 33 33 DECLARE_STATIC_KEY_FALSE(kunit_running); 34 34 35 35 struct kunit; 36 - 37 - /* Size of log associated with test. */ 38 - #define KUNIT_LOG_SIZE 2048 36 + struct string_stream; 39 37 40 38 /* Maximum size of parameter description string. */ 41 39 #define KUNIT_PARAM_DESC_SIZE 128 ··· 131 133 /* private: internal use only. */ 132 134 enum kunit_status status; 133 135 char *module_name; 134 - char *log; 136 + struct string_stream *log; 135 137 }; 136 138 137 139 static inline char *kunit_status_to_ok_not_ok(enum kunit_status status) ··· 251 253 /* private: internal use only */ 252 254 char status_comment[KUNIT_STATUS_COMMENT_SIZE]; 253 255 struct dentry *debugfs; 254 - char *log; 256 + struct string_stream *log; 255 257 int suite_init_err; 256 258 }; 257 259 ··· 277 279 278 280 /* private: internal use only. */ 279 281 const char *name; /* Read only after initialization! */ 280 - char *log; /* Points at case log after initialization */ 282 + struct string_stream *log; /* Points at case log after initialization */ 281 283 struct kunit_try_catch try_catch; 282 284 /* param_value is the current parameter value for a test case. */ 283 285 const void *param_value; ··· 313 315 char *kunit_filter(void); 314 316 char *kunit_filter_action(void); 315 317 316 - void kunit_init_test(struct kunit *test, const char *name, char *log); 318 + void kunit_init_test(struct kunit *test, const char *name, struct string_stream *log); 317 319 318 320 int kunit_run_tests(struct kunit_suite *suite); 319 321 ··· 471 473 472 474 void kunit_cleanup(struct kunit *test); 473 475 474 - void __printf(2, 3) kunit_log_append(char *log, const char *fmt, ...); 476 + void __printf(2, 3) kunit_log_append(struct string_stream *log, const char *fmt, ...); 475 477 476 478 /** 477 479 * kunit_mark_skipped() - Marks @test_or_suite as skipped
+6 -8
lib/kunit/assert.c
··· 89 89 EXPORT_SYMBOL_GPL(kunit_ptr_not_err_assert_format); 90 90 91 91 /* Checks if `text` is a literal representing `value`, e.g. "5" and 5 */ 92 - static bool is_literal(struct kunit *test, const char *text, long long value, 93 - gfp_t gfp) 92 + static bool is_literal(const char *text, long long value) 94 93 { 95 94 char *buffer; 96 95 int len; ··· 99 100 if (strlen(text) != len) 100 101 return false; 101 102 102 - buffer = kunit_kmalloc(test, len+1, gfp); 103 + buffer = kmalloc(len+1, GFP_KERNEL); 103 104 if (!buffer) 104 105 return false; 105 106 106 107 snprintf(buffer, len+1, "%lld", value); 107 108 ret = strncmp(buffer, text, len) == 0; 108 109 109 - kunit_kfree(test, buffer); 110 + kfree(buffer); 111 + 110 112 return ret; 111 113 } 112 114 ··· 125 125 binary_assert->text->left_text, 126 126 binary_assert->text->operation, 127 127 binary_assert->text->right_text); 128 - if (!is_literal(stream->test, binary_assert->text->left_text, 129 - binary_assert->left_value, stream->gfp)) 128 + if (!is_literal(binary_assert->text->left_text, binary_assert->left_value)) 130 129 string_stream_add(stream, KUNIT_SUBSUBTEST_INDENT "%s == %lld (0x%llx)\n", 131 130 binary_assert->text->left_text, 132 131 binary_assert->left_value, 133 132 binary_assert->left_value); 134 - if (!is_literal(stream->test, binary_assert->text->right_text, 135 - binary_assert->right_value, stream->gfp)) 133 + if (!is_literal(binary_assert->text->right_text, binary_assert->right_value)) 136 134 string_stream_add(stream, KUNIT_SUBSUBTEST_INDENT "%s == %lld (0x%llx)", 137 135 binary_assert->text->right_text, 138 136 binary_assert->right_value,
+23 -13
lib/kunit/debugfs.c
··· 37 37 debugfs_rootdir = debugfs_create_dir(KUNIT_DEBUGFS_ROOT, NULL); 38 38 } 39 39 40 - static void debugfs_print_result(struct seq_file *seq, 41 - struct kunit_suite *suite, 42 - struct kunit_case *test_case) 40 + static void debugfs_print_result(struct seq_file *seq, struct string_stream *log) 43 41 { 44 - if (!test_case || !test_case->log) 42 + struct string_stream_fragment *frag_container; 43 + 44 + if (!log) 45 45 return; 46 46 47 - seq_printf(seq, "%s", test_case->log); 47 + /* 48 + * Walk the fragments so we don't need to allocate a temporary 49 + * buffer to hold the entire string. 50 + */ 51 + spin_lock(&log->lock); 52 + list_for_each_entry(frag_container, &log->fragments, node) 53 + seq_printf(seq, "%s", frag_container->fragment); 54 + spin_unlock(&log->lock); 48 55 } 49 56 50 57 /* ··· 76 69 seq_printf(seq, KUNIT_SUBTEST_INDENT "1..%zd\n", kunit_suite_num_test_cases(suite)); 77 70 78 71 kunit_suite_for_each_test_case(suite, test_case) 79 - debugfs_print_result(seq, suite, test_case); 72 + debugfs_print_result(seq, test_case->log); 80 73 81 - if (suite->log) 82 - seq_printf(seq, "%s", suite->log); 74 + debugfs_print_result(seq, suite->log); 83 75 84 76 seq_printf(seq, "%s %d %s\n", 85 77 kunit_status_to_ok_not_ok(success), 1, suite->name); ··· 111 105 struct kunit_case *test_case; 112 106 113 107 /* Allocate logs before creating debugfs representation. */ 114 - suite->log = kzalloc(KUNIT_LOG_SIZE, GFP_KERNEL); 115 - kunit_suite_for_each_test_case(suite, test_case) 116 - test_case->log = kzalloc(KUNIT_LOG_SIZE, GFP_KERNEL); 108 + suite->log = alloc_string_stream(GFP_KERNEL); 109 + string_stream_set_append_newlines(suite->log, true); 110 + 111 + kunit_suite_for_each_test_case(suite, test_case) { 112 + test_case->log = alloc_string_stream(GFP_KERNEL); 113 + string_stream_set_append_newlines(test_case->log, true); 114 + } 117 115 118 116 suite->debugfs = debugfs_create_dir(suite->name, debugfs_rootdir); 119 117 ··· 131 121 struct kunit_case *test_case; 132 122 133 123 debugfs_remove_recursive(suite->debugfs); 134 - kfree(suite->log); 124 + string_stream_destroy(suite->log); 135 125 kunit_suite_for_each_test_case(suite, test_case) 136 - kfree(test_case->log); 126 + string_stream_destroy(test_case->log); 137 127 }
+17 -6
lib/kunit/executor.c
··· 137 137 { 138 138 struct kunit_suite * const *suites; 139 139 140 - for (suites = suite_set.start; suites < suite_set.end; suites++) 140 + for (suites = suite_set.start; suites < suite_set.end; suites++) { 141 + kfree((*suites)->test_cases); 141 142 kfree(*suites); 143 + } 142 144 kfree(suite_set.start); 143 145 } 144 146 ··· 157 155 struct kunit_suite_set filtered = {NULL, NULL}; 158 156 struct kunit_glob_filter parsed_glob; 159 157 struct kunit_attr_filter *parsed_filters = NULL; 158 + struct kunit_suite * const *suites; 160 159 161 160 const size_t max = suite_set->end - suite_set->start; 162 161 163 - copy = kmalloc_array(max, sizeof(*filtered.start), GFP_KERNEL); 162 + copy = kcalloc(max, sizeof(*filtered.start), GFP_KERNEL); 164 163 if (!copy) { /* won't be able to run anything, return an empty set */ 165 164 return filtered; 166 165 } ··· 196 193 parsed_glob.test_glob); 197 194 if (IS_ERR(filtered_suite)) { 198 195 *err = PTR_ERR(filtered_suite); 199 - goto free_parsed_filters; 196 + goto free_filtered_suite; 200 197 } 201 198 } 202 199 if (filter_count > 0 && parsed_filters != NULL) { ··· 213 210 filtered_suite = new_filtered_suite; 214 211 215 212 if (*err) 216 - goto free_parsed_filters; 213 + goto free_filtered_suite; 217 214 218 215 if (IS_ERR(filtered_suite)) { 219 216 *err = PTR_ERR(filtered_suite); 220 - goto free_parsed_filters; 217 + goto free_filtered_suite; 221 218 } 222 219 if (!filtered_suite) 223 220 break; ··· 232 229 filtered.start = copy_start; 233 230 filtered.end = copy; 234 231 232 + free_filtered_suite: 233 + if (*err) { 234 + for (suites = copy_start; suites < copy; suites++) { 235 + kfree((*suites)->test_cases); 236 + kfree(*suites); 237 + } 238 + } 239 + 235 240 free_parsed_filters: 236 241 if (filter_count) 237 242 kfree(parsed_filters); ··· 252 241 253 242 free_copy: 254 243 if (*err) 255 - kfree(copy); 244 + kfree(copy_start); 256 245 257 246 return filtered; 258 247 }
+22 -14
lib/kunit/executor_test.c
··· 9 9 #include <kunit/test.h> 10 10 #include <kunit/attributes.h> 11 11 12 - static void kfree_at_end(struct kunit *test, const void *to_free); 12 + static void free_suite_set_at_end(struct kunit *test, const void *to_free); 13 13 static struct kunit_suite *alloc_fake_suite(struct kunit *test, 14 14 const char *suite_name, 15 15 struct kunit_case *test_cases); ··· 56 56 got = kunit_filter_suites(&suite_set, "suite2", NULL, NULL, &err); 57 57 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, got.start); 58 58 KUNIT_ASSERT_EQ(test, err, 0); 59 - kfree_at_end(test, got.start); 59 + free_suite_set_at_end(test, &got); 60 60 61 61 /* Validate we just have suite2 */ 62 62 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, got.start[0]); ··· 82 82 got = kunit_filter_suites(&suite_set, "suite2.test2", NULL, NULL, &err); 83 83 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, got.start); 84 84 KUNIT_ASSERT_EQ(test, err, 0); 85 - kfree_at_end(test, got.start); 85 + free_suite_set_at_end(test, &got); 86 86 87 87 /* Validate we just have suite2 */ 88 88 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, got.start[0]); ··· 109 109 110 110 got = kunit_filter_suites(&suite_set, "not_found", NULL, NULL, &err); 111 111 KUNIT_ASSERT_EQ(test, err, 0); 112 - kfree_at_end(test, got.start); /* just in case */ 112 + free_suite_set_at_end(test, &got); /* just in case */ 113 113 114 114 KUNIT_EXPECT_PTR_EQ_MSG(test, got.start, got.end, 115 115 "should be empty to indicate no match"); ··· 172 172 got = kunit_filter_suites(&suite_set, NULL, filter, NULL, &err); 173 173 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, got.start); 174 174 KUNIT_ASSERT_EQ(test, err, 0); 175 - kfree_at_end(test, got.start); 175 + free_suite_set_at_end(test, &got); 176 176 177 177 /* Validate we just have normal_suite */ 178 178 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, got.start[0]); ··· 200 200 201 201 got = kunit_filter_suites(&suite_set, NULL, filter, NULL, &err); 202 202 KUNIT_ASSERT_EQ(test, err, 0); 203 - kfree_at_end(test, got.start); /* just in case */ 203 + free_suite_set_at_end(test, &got); /* just in case */ 204 204 205 205 KUNIT_EXPECT_PTR_EQ_MSG(test, got.start, got.end, 206 206 "should be empty to indicate no match"); ··· 222 222 got = kunit_filter_suites(&suite_set, NULL, filter, "skip", &err); 223 223 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, got.start); 224 224 KUNIT_ASSERT_EQ(test, err, 0); 225 - kfree_at_end(test, got.start); 225 + free_suite_set_at_end(test, &got); 226 226 227 227 /* Validate we have both the slow and normal test */ 228 228 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, got.start[0]->test_cases); ··· 256 256 257 257 /* Test helpers */ 258 258 259 - /* Use the resource API to register a call to kfree(to_free). 259 + static void free_suite_set(void *suite_set) 260 + { 261 + kunit_free_suite_set(*(struct kunit_suite_set *)suite_set); 262 + kfree(suite_set); 263 + } 264 + 265 + /* Use the resource API to register a call to free_suite_set. 260 266 * Since we never actually use the resource, it's safe to use on const data. 261 267 */ 262 - static void kfree_at_end(struct kunit *test, const void *to_free) 268 + static void free_suite_set_at_end(struct kunit *test, const void *to_free) 263 269 { 264 - /* kfree() handles NULL already, but avoid allocating a no-op cleanup. */ 265 - if (IS_ERR_OR_NULL(to_free)) 270 + struct kunit_suite_set *free; 271 + 272 + if (!((struct kunit_suite_set *)to_free)->start) 266 273 return; 267 274 268 - kunit_add_action(test, 269 - (kunit_action_t *)kfree, 270 - (void *)to_free); 275 + free = kzalloc(sizeof(struct kunit_suite_set), GFP_KERNEL); 276 + *free = *(struct kunit_suite_set *)to_free; 277 + 278 + kunit_add_action(test, free_suite_set, (void *)free); 271 279 } 272 280 273 281 static struct kunit_suite *alloc_fake_suite(struct kunit *test,
+3 -2
lib/kunit/kunit-example-test.c
··· 190 190 static const struct example_param { 191 191 int value; 192 192 } example_params_array[] = { 193 + { .value = 3, }, 193 194 { .value = 2, }, 194 195 { .value = 1, }, 195 196 { .value = 0, }, ··· 214 213 KUNIT_ASSERT_NOT_NULL(test, param); 215 214 216 215 /* Test can be skipped on unsupported param values */ 217 - if (!param->value) 218 - kunit_skip(test, "unsupported param value"); 216 + if (!is_power_of_2(param->value)) 217 + kunit_skip(test, "unsupported param value %d", param->value); 219 218 220 219 /* You can use param values for parameterized testing */ 221 220 KUNIT_EXPECT_EQ(test, param->value % param->value, 0);
+47 -9
lib/kunit/kunit-test.c
··· 8 8 #include <kunit/test.h> 9 9 #include <kunit/test-bug.h> 10 10 11 + #include "string-stream.h" 11 12 #include "try-catch-impl.h" 12 13 13 14 struct kunit_try_catch_test_context { ··· 531 530 .test_cases = kunit_resource_test_cases, 532 531 }; 533 532 533 + /* 534 + * Log tests call string_stream functions, which aren't exported. So only 535 + * build this code if this test is built-in. 536 + */ 537 + #if IS_BUILTIN(CONFIG_KUNIT_TEST) 538 + 539 + /* This avoids a cast warning if kfree() is passed direct to kunit_add_action(). */ 540 + static void kfree_wrapper(void *p) 541 + { 542 + kfree(p); 543 + } 544 + 534 545 static void kunit_log_test(struct kunit *test) 535 546 { 536 547 struct kunit_suite suite; 537 - 538 - suite.log = kunit_kzalloc(test, KUNIT_LOG_SIZE, GFP_KERNEL); 548 + #ifdef CONFIG_KUNIT_DEBUGFS 549 + char *full_log; 550 + #endif 551 + suite.log = kunit_alloc_string_stream(test, GFP_KERNEL); 539 552 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, suite.log); 553 + string_stream_set_append_newlines(suite.log, true); 540 554 541 555 kunit_log(KERN_INFO, test, "put this in log."); 542 556 kunit_log(KERN_INFO, test, "this too."); ··· 559 543 kunit_log(KERN_INFO, &suite, "along with this."); 560 544 561 545 #ifdef CONFIG_KUNIT_DEBUGFS 546 + KUNIT_EXPECT_TRUE(test, test->log->append_newlines); 547 + 548 + full_log = string_stream_get_string(test->log); 549 + kunit_add_action(test, (kunit_action_t *)kfree, full_log); 562 550 KUNIT_EXPECT_NOT_ERR_OR_NULL(test, 563 - strstr(test->log, "put this in log.")); 551 + strstr(full_log, "put this in log.")); 564 552 KUNIT_EXPECT_NOT_ERR_OR_NULL(test, 565 - strstr(test->log, "this too.")); 553 + strstr(full_log, "this too.")); 554 + 555 + full_log = string_stream_get_string(suite.log); 556 + kunit_add_action(test, kfree_wrapper, full_log); 566 557 KUNIT_EXPECT_NOT_ERR_OR_NULL(test, 567 - strstr(suite.log, "add to suite log.")); 558 + strstr(full_log, "add to suite log.")); 568 559 KUNIT_EXPECT_NOT_ERR_OR_NULL(test, 569 - strstr(suite.log, "along with this.")); 560 + strstr(full_log, "along with this.")); 570 561 #else 571 562 KUNIT_EXPECT_NULL(test, test->log); 572 563 #endif ··· 581 558 582 559 static void kunit_log_newline_test(struct kunit *test) 583 560 { 561 + char *full_log; 562 + 584 563 kunit_info(test, "Add newline\n"); 585 564 if (test->log) { 586 - KUNIT_ASSERT_NOT_NULL_MSG(test, strstr(test->log, "Add newline\n"), 587 - "Missing log line, full log:\n%s", test->log); 588 - KUNIT_EXPECT_NULL(test, strstr(test->log, "Add newline\n\n")); 565 + full_log = string_stream_get_string(test->log); 566 + kunit_add_action(test, kfree_wrapper, full_log); 567 + KUNIT_ASSERT_NOT_NULL_MSG(test, strstr(full_log, "Add newline\n"), 568 + "Missing log line, full log:\n%s", full_log); 569 + KUNIT_EXPECT_NULL(test, strstr(full_log, "Add newline\n\n")); 589 570 } else { 590 571 kunit_skip(test, "only useful when debugfs is enabled"); 591 572 } 592 573 } 574 + #else 575 + static void kunit_log_test(struct kunit *test) 576 + { 577 + kunit_skip(test, "Log tests only run when built-in"); 578 + } 579 + 580 + static void kunit_log_newline_test(struct kunit *test) 581 + { 582 + kunit_skip(test, "Log tests only run when built-in"); 583 + } 584 + #endif /* IS_BUILTIN(CONFIG_KUNIT_TEST) */ 593 585 594 586 static struct kunit_case kunit_log_test_cases[] = { 595 587 KUNIT_CASE(kunit_log_test),
+508 -17
lib/kunit/string-stream-test.c
··· 6 6 * Author: Brendan Higgins <brendanhiggins@google.com> 7 7 */ 8 8 9 + #include <kunit/static_stub.h> 9 10 #include <kunit/test.h> 11 + #include <linux/ktime.h> 10 12 #include <linux/slab.h> 13 + #include <linux/timekeeping.h> 11 14 12 15 #include "string-stream.h" 13 16 14 - static void string_stream_test_empty_on_creation(struct kunit *test) 17 + struct string_stream_test_priv { 18 + /* For testing resource-managed free. */ 19 + struct string_stream *expected_free_stream; 20 + bool stream_was_freed; 21 + bool stream_free_again; 22 + }; 23 + 24 + /* Avoids a cast warning if kfree() is passed direct to kunit_add_action(). */ 25 + static void kfree_wrapper(void *p) 15 26 { 16 - struct string_stream *stream = alloc_string_stream(test, GFP_KERNEL); 27 + kfree(p); 28 + } 29 + 30 + /* Avoids a cast warning if string_stream_destroy() is passed direct to kunit_add_action(). */ 31 + static void cleanup_raw_stream(void *p) 32 + { 33 + struct string_stream *stream = p; 34 + 35 + string_stream_destroy(stream); 36 + } 37 + 38 + static char *get_concatenated_string(struct kunit *test, struct string_stream *stream) 39 + { 40 + char *str = string_stream_get_string(stream); 41 + 42 + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, str); 43 + kunit_add_action(test, kfree_wrapper, (void *)str); 44 + 45 + return str; 46 + } 47 + 48 + /* Managed string_stream object is initialized correctly. */ 49 + static void string_stream_managed_init_test(struct kunit *test) 50 + { 51 + struct string_stream *stream; 52 + 53 + /* Resource-managed initialization. */ 54 + stream = kunit_alloc_string_stream(test, GFP_KERNEL); 55 + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, stream); 56 + 57 + KUNIT_EXPECT_EQ(test, stream->length, 0); 58 + KUNIT_EXPECT_TRUE(test, list_empty(&stream->fragments)); 59 + KUNIT_EXPECT_TRUE(test, (stream->gfp == GFP_KERNEL)); 60 + KUNIT_EXPECT_FALSE(test, stream->append_newlines); 61 + KUNIT_EXPECT_TRUE(test, string_stream_is_empty(stream)); 62 + } 63 + 64 + /* Unmanaged string_stream object is initialized correctly. */ 65 + static void string_stream_unmanaged_init_test(struct kunit *test) 66 + { 67 + struct string_stream *stream; 68 + 69 + stream = alloc_string_stream(GFP_KERNEL); 70 + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, stream); 71 + kunit_add_action(test, cleanup_raw_stream, stream); 72 + 73 + KUNIT_EXPECT_EQ(test, stream->length, 0); 74 + KUNIT_EXPECT_TRUE(test, list_empty(&stream->fragments)); 75 + KUNIT_EXPECT_EQ(test, stream->gfp, GFP_KERNEL); 76 + KUNIT_EXPECT_FALSE(test, stream->append_newlines); 17 77 18 78 KUNIT_EXPECT_TRUE(test, string_stream_is_empty(stream)); 19 79 } 20 80 21 - static void string_stream_test_not_empty_after_add(struct kunit *test) 81 + static void string_stream_destroy_stub(struct string_stream *stream) 22 82 { 23 - struct string_stream *stream = alloc_string_stream(test, GFP_KERNEL); 83 + struct kunit *fake_test = kunit_get_current_test(); 84 + struct string_stream_test_priv *priv = fake_test->priv; 24 85 25 - string_stream_add(stream, "Foo"); 86 + /* The kunit could own string_streams other than the one we are testing. */ 87 + if (stream == priv->expected_free_stream) { 88 + if (priv->stream_was_freed) 89 + priv->stream_free_again = true; 90 + else 91 + priv->stream_was_freed = true; 92 + } 26 93 27 - KUNIT_EXPECT_FALSE(test, string_stream_is_empty(stream)); 94 + /* 95 + * Calling string_stream_destroy() will only call this function again 96 + * because the redirection stub is still active. 97 + * Avoid calling deactivate_static_stub() or changing current->kunit_test 98 + * during cleanup. 99 + */ 100 + string_stream_clear(stream); 101 + kfree(stream); 28 102 } 29 103 30 - static void string_stream_test_get_string(struct kunit *test) 104 + /* kunit_free_string_stream() calls string_stream_desrtoy() */ 105 + static void string_stream_managed_free_test(struct kunit *test) 31 106 { 32 - struct string_stream *stream = alloc_string_stream(test, GFP_KERNEL); 33 - char *output; 107 + struct string_stream_test_priv *priv = test->priv; 34 108 35 - string_stream_add(stream, "Foo"); 36 - string_stream_add(stream, " %s", "bar"); 109 + priv->expected_free_stream = NULL; 110 + priv->stream_was_freed = false; 111 + priv->stream_free_again = false; 37 112 38 - output = string_stream_get_string(stream); 39 - KUNIT_ASSERT_STREQ(test, output, "Foo bar"); 113 + kunit_activate_static_stub(test, 114 + string_stream_destroy, 115 + string_stream_destroy_stub); 116 + 117 + priv->expected_free_stream = kunit_alloc_string_stream(test, GFP_KERNEL); 118 + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv->expected_free_stream); 119 + 120 + /* This should call the stub function. */ 121 + kunit_free_string_stream(test, priv->expected_free_stream); 122 + 123 + KUNIT_EXPECT_TRUE(test, priv->stream_was_freed); 124 + KUNIT_EXPECT_FALSE(test, priv->stream_free_again); 125 + } 126 + 127 + /* string_stream object is freed when test is cleaned up. */ 128 + static void string_stream_resource_free_test(struct kunit *test) 129 + { 130 + struct string_stream_test_priv *priv = test->priv; 131 + struct kunit *fake_test; 132 + 133 + fake_test = kunit_kzalloc(test, sizeof(*fake_test), GFP_KERNEL); 134 + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, fake_test); 135 + 136 + kunit_init_test(fake_test, "string_stream_fake_test", NULL); 137 + fake_test->priv = priv; 138 + 139 + /* 140 + * Activate stub before creating string_stream so the 141 + * string_stream will be cleaned up first. 142 + */ 143 + priv->expected_free_stream = NULL; 144 + priv->stream_was_freed = false; 145 + priv->stream_free_again = false; 146 + 147 + kunit_activate_static_stub(fake_test, 148 + string_stream_destroy, 149 + string_stream_destroy_stub); 150 + 151 + priv->expected_free_stream = kunit_alloc_string_stream(fake_test, GFP_KERNEL); 152 + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv->expected_free_stream); 153 + 154 + /* Set current->kunit_test to fake_test so the static stub will be called. */ 155 + current->kunit_test = fake_test; 156 + 157 + /* Cleanup test - the stub function should be called */ 158 + kunit_cleanup(fake_test); 159 + 160 + /* Set current->kunit_test back to current test. */ 161 + current->kunit_test = test; 162 + 163 + KUNIT_EXPECT_TRUE(test, priv->stream_was_freed); 164 + KUNIT_EXPECT_FALSE(test, priv->stream_free_again); 165 + } 166 + 167 + /* 168 + * Add a series of lines to a string_stream. Check that all lines 169 + * appear in the correct order and no characters are dropped. 170 + */ 171 + static void string_stream_line_add_test(struct kunit *test) 172 + { 173 + struct string_stream *stream; 174 + char line[60]; 175 + char *concat_string, *pos, *string_end; 176 + size_t len, total_len; 177 + int num_lines, i; 178 + 179 + stream = kunit_alloc_string_stream(test, GFP_KERNEL); 180 + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, stream); 181 + 182 + /* Add series of sequence numbered lines */ 183 + total_len = 0; 184 + for (i = 0; i < 100; ++i) { 185 + len = snprintf(line, sizeof(line), 186 + "The quick brown fox jumps over the lazy penguin %d\n", i); 187 + 188 + /* Sanity-check that our test string isn't truncated */ 189 + KUNIT_ASSERT_LT(test, len, sizeof(line)); 190 + 191 + string_stream_add(stream, line); 192 + total_len += len; 193 + } 194 + num_lines = i; 195 + 196 + concat_string = get_concatenated_string(test, stream); 197 + KUNIT_EXPECT_NOT_ERR_OR_NULL(test, concat_string); 198 + KUNIT_EXPECT_EQ(test, strlen(concat_string), total_len); 199 + 200 + /* 201 + * Split the concatenated string at the newlines and check that 202 + * all the original added strings are present. 203 + */ 204 + pos = concat_string; 205 + for (i = 0; i < num_lines; ++i) { 206 + string_end = strchr(pos, '\n'); 207 + KUNIT_EXPECT_NOT_NULL(test, string_end); 208 + 209 + /* Convert to NULL-terminated string */ 210 + *string_end = '\0'; 211 + 212 + snprintf(line, sizeof(line), 213 + "The quick brown fox jumps over the lazy penguin %d", i); 214 + KUNIT_EXPECT_STREQ(test, pos, line); 215 + 216 + pos = string_end + 1; 217 + } 218 + 219 + /* There shouldn't be any more data after this */ 220 + KUNIT_EXPECT_EQ(test, strlen(pos), 0); 221 + } 222 + 223 + /* Add a series of lines of variable length to a string_stream. */ 224 + static void string_stream_variable_length_line_test(struct kunit *test) 225 + { 226 + static const char line[] = 227 + "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" 228 + " 0123456789!$%^&*()_-+={}[]:;@'~#<>,.?/|"; 229 + struct string_stream *stream; 230 + struct rnd_state rnd; 231 + char *concat_string, *pos, *string_end; 232 + size_t offset, total_len; 233 + int num_lines, i; 234 + 235 + stream = kunit_alloc_string_stream(test, GFP_KERNEL); 236 + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, stream); 237 + 238 + /* 239 + * Log many lines of varying lengths until we have created 240 + * many fragments. 241 + * The "randomness" must be repeatable. 242 + */ 243 + prandom_seed_state(&rnd, 3141592653589793238ULL); 244 + total_len = 0; 245 + for (i = 0; i < 100; ++i) { 246 + offset = prandom_u32_state(&rnd) % (sizeof(line) - 1); 247 + string_stream_add(stream, "%s\n", &line[offset]); 248 + total_len += sizeof(line) - offset; 249 + } 250 + num_lines = i; 251 + 252 + concat_string = get_concatenated_string(test, stream); 253 + KUNIT_EXPECT_NOT_ERR_OR_NULL(test, concat_string); 254 + KUNIT_EXPECT_EQ(test, strlen(concat_string), total_len); 255 + 256 + /* 257 + * Split the concatenated string at the newlines and check that 258 + * all the original added strings are present. 259 + */ 260 + prandom_seed_state(&rnd, 3141592653589793238ULL); 261 + pos = concat_string; 262 + for (i = 0; i < num_lines; ++i) { 263 + string_end = strchr(pos, '\n'); 264 + KUNIT_EXPECT_NOT_NULL(test, string_end); 265 + 266 + /* Convert to NULL-terminated string */ 267 + *string_end = '\0'; 268 + 269 + offset = prandom_u32_state(&rnd) % (sizeof(line) - 1); 270 + KUNIT_EXPECT_STREQ(test, pos, &line[offset]); 271 + 272 + pos = string_end + 1; 273 + } 274 + 275 + /* There shouldn't be any more data after this */ 276 + KUNIT_EXPECT_EQ(test, strlen(pos), 0); 277 + } 278 + 279 + /* Appending the content of one string stream to another. */ 280 + static void string_stream_append_test(struct kunit *test) 281 + { 282 + static const char * const strings_1[] = { 283 + "one", "two", "three", "four", "five", "six", 284 + "seven", "eight", "nine", "ten", 285 + }; 286 + static const char * const strings_2[] = { 287 + "Apple", "Pear", "Orange", "Banana", "Grape", "Apricot", 288 + }; 289 + struct string_stream *stream_1, *stream_2; 290 + const char *stream1_content_before_append, *stream_2_content; 291 + char *combined_content; 292 + size_t combined_length; 293 + int i; 294 + 295 + stream_1 = kunit_alloc_string_stream(test, GFP_KERNEL); 296 + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, stream_1); 297 + 298 + stream_2 = kunit_alloc_string_stream(test, GFP_KERNEL); 299 + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, stream_2); 300 + 301 + /* Append content of empty stream to empty stream */ 302 + string_stream_append(stream_1, stream_2); 303 + KUNIT_EXPECT_EQ(test, strlen(get_concatenated_string(test, stream_1)), 0); 304 + 305 + /* Add some data to stream_1 */ 306 + for (i = 0; i < ARRAY_SIZE(strings_1); ++i) 307 + string_stream_add(stream_1, "%s\n", strings_1[i]); 308 + 309 + stream1_content_before_append = get_concatenated_string(test, stream_1); 310 + 311 + /* Append content of empty stream to non-empty stream */ 312 + string_stream_append(stream_1, stream_2); 313 + KUNIT_EXPECT_STREQ(test, get_concatenated_string(test, stream_1), 314 + stream1_content_before_append); 315 + 316 + /* Add some data to stream_2 */ 317 + for (i = 0; i < ARRAY_SIZE(strings_2); ++i) 318 + string_stream_add(stream_2, "%s\n", strings_2[i]); 319 + 320 + /* Append content of non-empty stream to non-empty stream */ 321 + string_stream_append(stream_1, stream_2); 322 + 323 + /* 324 + * End result should be the original content of stream_1 plus 325 + * the content of stream_2. 326 + */ 327 + stream_2_content = get_concatenated_string(test, stream_2); 328 + combined_length = strlen(stream1_content_before_append) + strlen(stream_2_content); 329 + combined_length++; /* for terminating \0 */ 330 + combined_content = kunit_kmalloc(test, combined_length, GFP_KERNEL); 331 + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, combined_content); 332 + snprintf(combined_content, combined_length, "%s%s", 333 + stream1_content_before_append, stream_2_content); 334 + 335 + KUNIT_EXPECT_STREQ(test, get_concatenated_string(test, stream_1), combined_content); 336 + 337 + /* Append content of non-empty stream to empty stream */ 338 + kunit_free_string_stream(test, stream_1); 339 + 340 + stream_1 = kunit_alloc_string_stream(test, GFP_KERNEL); 341 + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, stream_1); 342 + 343 + string_stream_append(stream_1, stream_2); 344 + KUNIT_EXPECT_STREQ(test, get_concatenated_string(test, stream_1), stream_2_content); 345 + } 346 + 347 + /* Appending the content of one string stream to one with auto-newlining. */ 348 + static void string_stream_append_auto_newline_test(struct kunit *test) 349 + { 350 + struct string_stream *stream_1, *stream_2; 351 + 352 + /* Stream 1 has newline appending enabled */ 353 + stream_1 = kunit_alloc_string_stream(test, GFP_KERNEL); 354 + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, stream_1); 355 + string_stream_set_append_newlines(stream_1, true); 356 + KUNIT_EXPECT_TRUE(test, stream_1->append_newlines); 357 + 358 + /* Stream 2 does not append newlines */ 359 + stream_2 = kunit_alloc_string_stream(test, GFP_KERNEL); 360 + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, stream_2); 361 + 362 + /* Appending a stream with a newline should not add another newline */ 363 + string_stream_add(stream_1, "Original string\n"); 364 + string_stream_add(stream_2, "Appended content\n"); 365 + string_stream_add(stream_2, "More stuff\n"); 366 + string_stream_append(stream_1, stream_2); 367 + KUNIT_EXPECT_STREQ(test, get_concatenated_string(test, stream_1), 368 + "Original string\nAppended content\nMore stuff\n"); 369 + 370 + kunit_free_string_stream(test, stream_2); 371 + stream_2 = kunit_alloc_string_stream(test, GFP_KERNEL); 372 + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, stream_2); 373 + 374 + /* 375 + * Appending a stream without newline should add a final newline. 376 + * The appended string_stream is treated as a single string so newlines 377 + * should not be inserted between fragments. 378 + */ 379 + string_stream_add(stream_2, "Another"); 380 + string_stream_add(stream_2, "And again"); 381 + string_stream_append(stream_1, stream_2); 382 + KUNIT_EXPECT_STREQ(test, get_concatenated_string(test, stream_1), 383 + "Original string\nAppended content\nMore stuff\nAnotherAnd again\n"); 384 + } 385 + 386 + /* Adding an empty string should not create a fragment. */ 387 + static void string_stream_append_empty_string_test(struct kunit *test) 388 + { 389 + struct string_stream *stream; 390 + int original_frag_count; 391 + 392 + stream = kunit_alloc_string_stream(test, GFP_KERNEL); 393 + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, stream); 394 + 395 + /* Formatted empty string */ 396 + string_stream_add(stream, "%s", ""); 397 + KUNIT_EXPECT_TRUE(test, string_stream_is_empty(stream)); 398 + KUNIT_EXPECT_TRUE(test, list_empty(&stream->fragments)); 399 + 400 + /* Adding an empty string to a non-empty stream */ 401 + string_stream_add(stream, "Add this line"); 402 + original_frag_count = list_count_nodes(&stream->fragments); 403 + 404 + string_stream_add(stream, "%s", ""); 405 + KUNIT_EXPECT_EQ(test, list_count_nodes(&stream->fragments), original_frag_count); 406 + KUNIT_EXPECT_STREQ(test, get_concatenated_string(test, stream), "Add this line"); 407 + } 408 + 409 + /* Adding strings without automatic newline appending */ 410 + static void string_stream_no_auto_newline_test(struct kunit *test) 411 + { 412 + struct string_stream *stream; 413 + 414 + stream = kunit_alloc_string_stream(test, GFP_KERNEL); 415 + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, stream); 416 + 417 + /* 418 + * Add some strings with and without newlines. All formatted newlines 419 + * should be preserved. It should not add any extra newlines. 420 + */ 421 + string_stream_add(stream, "One"); 422 + string_stream_add(stream, "Two\n"); 423 + string_stream_add(stream, "%s\n", "Three"); 424 + string_stream_add(stream, "%s", "Four\n"); 425 + string_stream_add(stream, "Five\n%s", "Six"); 426 + string_stream_add(stream, "Seven\n\n"); 427 + string_stream_add(stream, "Eight"); 428 + KUNIT_EXPECT_STREQ(test, get_concatenated_string(test, stream), 429 + "OneTwo\nThree\nFour\nFive\nSixSeven\n\nEight"); 430 + } 431 + 432 + /* Adding strings with automatic newline appending */ 433 + static void string_stream_auto_newline_test(struct kunit *test) 434 + { 435 + struct string_stream *stream; 436 + 437 + stream = kunit_alloc_string_stream(test, GFP_KERNEL); 438 + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, stream); 439 + 440 + string_stream_set_append_newlines(stream, true); 441 + KUNIT_EXPECT_TRUE(test, stream->append_newlines); 442 + 443 + /* 444 + * Add some strings with and without newlines. Newlines should 445 + * be appended to lines that do not end with \n, but newlines 446 + * resulting from the formatting should not be changed. 447 + */ 448 + string_stream_add(stream, "One"); 449 + string_stream_add(stream, "Two\n"); 450 + string_stream_add(stream, "%s\n", "Three"); 451 + string_stream_add(stream, "%s", "Four\n"); 452 + string_stream_add(stream, "Five\n%s", "Six"); 453 + string_stream_add(stream, "Seven\n\n"); 454 + string_stream_add(stream, "Eight"); 455 + KUNIT_EXPECT_STREQ(test, get_concatenated_string(test, stream), 456 + "One\nTwo\nThree\nFour\nFive\nSix\nSeven\n\nEight\n"); 457 + } 458 + 459 + /* 460 + * This doesn't actually "test" anything. It reports time taken 461 + * and memory used for logging a large number of lines. 462 + */ 463 + static void string_stream_performance_test(struct kunit *test) 464 + { 465 + struct string_stream_fragment *frag_container; 466 + struct string_stream *stream; 467 + char test_line[101]; 468 + ktime_t start_time, end_time; 469 + size_t len, bytes_requested, actual_bytes_used, total_string_length; 470 + int offset, i; 471 + 472 + stream = kunit_alloc_string_stream(test, GFP_KERNEL); 473 + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, stream); 474 + 475 + memset(test_line, 'x', sizeof(test_line) - 1); 476 + test_line[sizeof(test_line) - 1] = '\0'; 477 + 478 + start_time = ktime_get(); 479 + for (i = 0; i < 10000; i++) { 480 + offset = i % (sizeof(test_line) - 1); 481 + string_stream_add(stream, "%s: %d\n", &test_line[offset], i); 482 + } 483 + end_time = ktime_get(); 484 + 485 + /* 486 + * Calculate memory used. This doesn't include invisible 487 + * overhead due to kernel allocator fragment size rounding. 488 + */ 489 + bytes_requested = sizeof(*stream); 490 + actual_bytes_used = ksize(stream); 491 + total_string_length = 0; 492 + 493 + list_for_each_entry(frag_container, &stream->fragments, node) { 494 + bytes_requested += sizeof(*frag_container); 495 + actual_bytes_used += ksize(frag_container); 496 + 497 + len = strlen(frag_container->fragment); 498 + total_string_length += len; 499 + bytes_requested += len + 1; /* +1 for '\0' */ 500 + actual_bytes_used += ksize(frag_container->fragment); 501 + } 502 + 503 + kunit_info(test, "Time elapsed: %lld us\n", 504 + ktime_us_delta(end_time, start_time)); 505 + kunit_info(test, "Total string length: %zu\n", total_string_length); 506 + kunit_info(test, "Bytes requested: %zu\n", bytes_requested); 507 + kunit_info(test, "Actual bytes allocated: %zu\n", actual_bytes_used); 508 + } 509 + 510 + static int string_stream_test_init(struct kunit *test) 511 + { 512 + struct string_stream_test_priv *priv; 513 + 514 + priv = kunit_kzalloc(test, sizeof(*priv), GFP_KERNEL); 515 + if (!priv) 516 + return -ENOMEM; 517 + 518 + test->priv = priv; 519 + 520 + return 0; 40 521 } 41 522 42 523 static struct kunit_case string_stream_test_cases[] = { 43 - KUNIT_CASE(string_stream_test_empty_on_creation), 44 - KUNIT_CASE(string_stream_test_not_empty_after_add), 45 - KUNIT_CASE(string_stream_test_get_string), 524 + KUNIT_CASE(string_stream_managed_init_test), 525 + KUNIT_CASE(string_stream_unmanaged_init_test), 526 + KUNIT_CASE(string_stream_managed_free_test), 527 + KUNIT_CASE(string_stream_resource_free_test), 528 + KUNIT_CASE(string_stream_line_add_test), 529 + KUNIT_CASE(string_stream_variable_length_line_test), 530 + KUNIT_CASE(string_stream_append_test), 531 + KUNIT_CASE(string_stream_append_auto_newline_test), 532 + KUNIT_CASE(string_stream_append_empty_string_test), 533 + KUNIT_CASE(string_stream_no_auto_newline_test), 534 + KUNIT_CASE(string_stream_auto_newline_test), 535 + KUNIT_CASE(string_stream_performance_test), 46 536 {} 47 537 }; 48 538 49 539 static struct kunit_suite string_stream_test_suite = { 50 540 .name = "string-stream-test", 51 - .test_cases = string_stream_test_cases 541 + .test_cases = string_stream_test_cases, 542 + .init = string_stream_test_init, 52 543 }; 53 544 kunit_test_suites(&string_stream_test_suite);
+76 -24
lib/kunit/string-stream.c
··· 6 6 * Author: Brendan Higgins <brendanhiggins@google.com> 7 7 */ 8 8 9 + #include <kunit/static_stub.h> 9 10 #include <kunit/test.h> 10 11 #include <linux/list.h> 11 12 #include <linux/slab.h> ··· 14 13 #include "string-stream.h" 15 14 16 15 17 - static struct string_stream_fragment *alloc_string_stream_fragment( 18 - struct kunit *test, int len, gfp_t gfp) 16 + static struct string_stream_fragment *alloc_string_stream_fragment(int len, gfp_t gfp) 19 17 { 20 18 struct string_stream_fragment *frag; 21 19 22 - frag = kunit_kzalloc(test, sizeof(*frag), gfp); 20 + frag = kzalloc(sizeof(*frag), gfp); 23 21 if (!frag) 24 22 return ERR_PTR(-ENOMEM); 25 23 26 - frag->fragment = kunit_kmalloc(test, len, gfp); 24 + frag->fragment = kmalloc(len, gfp); 27 25 if (!frag->fragment) { 28 - kunit_kfree(test, frag); 26 + kfree(frag); 29 27 return ERR_PTR(-ENOMEM); 30 28 } 31 29 32 30 return frag; 33 31 } 34 32 35 - static void string_stream_fragment_destroy(struct kunit *test, 36 - struct string_stream_fragment *frag) 33 + static void string_stream_fragment_destroy(struct string_stream_fragment *frag) 37 34 { 38 35 list_del(&frag->node); 39 - kunit_kfree(test, frag->fragment); 40 - kunit_kfree(test, frag); 36 + kfree(frag->fragment); 37 + kfree(frag); 41 38 } 42 39 43 40 int string_stream_vadd(struct string_stream *stream, ··· 43 44 va_list args) 44 45 { 45 46 struct string_stream_fragment *frag_container; 46 - int len; 47 + int buf_len, result_len; 47 48 va_list args_for_counting; 48 49 49 50 /* Make a copy because `vsnprintf` could change it */ 50 51 va_copy(args_for_counting, args); 51 52 52 - /* Need space for null byte. */ 53 - len = vsnprintf(NULL, 0, fmt, args_for_counting) + 1; 53 + /* Evaluate length of formatted string */ 54 + buf_len = vsnprintf(NULL, 0, fmt, args_for_counting); 54 55 55 56 va_end(args_for_counting); 56 57 57 - frag_container = alloc_string_stream_fragment(stream->test, 58 - len, 59 - stream->gfp); 58 + if (buf_len == 0) 59 + return 0; 60 + 61 + /* Reserve one extra for possible appended newline. */ 62 + if (stream->append_newlines) 63 + buf_len++; 64 + 65 + /* Need space for null byte. */ 66 + buf_len++; 67 + 68 + frag_container = alloc_string_stream_fragment(buf_len, stream->gfp); 60 69 if (IS_ERR(frag_container)) 61 70 return PTR_ERR(frag_container); 62 71 63 - len = vsnprintf(frag_container->fragment, len, fmt, args); 72 + if (stream->append_newlines) { 73 + /* Don't include reserved newline byte in writeable length. */ 74 + result_len = vsnprintf(frag_container->fragment, buf_len - 1, fmt, args); 75 + 76 + /* Append newline if necessary. */ 77 + if (frag_container->fragment[result_len - 1] != '\n') 78 + result_len = strlcat(frag_container->fragment, "\n", buf_len); 79 + } else { 80 + result_len = vsnprintf(frag_container->fragment, buf_len, fmt, args); 81 + } 82 + 64 83 spin_lock(&stream->lock); 65 - stream->length += len; 84 + stream->length += result_len; 66 85 list_add_tail(&frag_container->node, &stream->fragments); 67 86 spin_unlock(&stream->lock); 68 87 ··· 99 82 return result; 100 83 } 101 84 102 - static void string_stream_clear(struct string_stream *stream) 85 + void string_stream_clear(struct string_stream *stream) 103 86 { 104 87 struct string_stream_fragment *frag_container, *frag_container_safe; 105 88 ··· 108 91 frag_container_safe, 109 92 &stream->fragments, 110 93 node) { 111 - string_stream_fragment_destroy(stream->test, frag_container); 94 + string_stream_fragment_destroy(frag_container); 112 95 } 113 96 stream->length = 0; 114 97 spin_unlock(&stream->lock); ··· 120 103 size_t buf_len = stream->length + 1; /* +1 for null byte. */ 121 104 char *buf; 122 105 123 - buf = kunit_kzalloc(stream->test, buf_len, stream->gfp); 106 + buf = kzalloc(buf_len, stream->gfp); 124 107 if (!buf) 125 108 return NULL; 126 109 ··· 136 119 struct string_stream *other) 137 120 { 138 121 const char *other_content; 122 + int ret; 139 123 140 124 other_content = string_stream_get_string(other); 141 125 142 126 if (!other_content) 143 127 return -ENOMEM; 144 128 145 - return string_stream_add(stream, other_content); 129 + ret = string_stream_add(stream, other_content); 130 + kfree(other_content); 131 + 132 + return ret; 146 133 } 147 134 148 135 bool string_stream_is_empty(struct string_stream *stream) ··· 154 133 return list_empty(&stream->fragments); 155 134 } 156 135 157 - struct string_stream *alloc_string_stream(struct kunit *test, gfp_t gfp) 136 + struct string_stream *alloc_string_stream(gfp_t gfp) 158 137 { 159 138 struct string_stream *stream; 160 139 161 - stream = kunit_kzalloc(test, sizeof(*stream), gfp); 140 + stream = kzalloc(sizeof(*stream), gfp); 162 141 if (!stream) 163 142 return ERR_PTR(-ENOMEM); 164 143 165 144 stream->gfp = gfp; 166 - stream->test = test; 167 145 INIT_LIST_HEAD(&stream->fragments); 168 146 spin_lock_init(&stream->lock); 169 147 ··· 171 151 172 152 void string_stream_destroy(struct string_stream *stream) 173 153 { 154 + KUNIT_STATIC_STUB_REDIRECT(string_stream_destroy, stream); 155 + 156 + if (!stream) 157 + return; 158 + 174 159 string_stream_clear(stream); 160 + kfree(stream); 161 + } 162 + 163 + static void resource_free_string_stream(void *p) 164 + { 165 + struct string_stream *stream = p; 166 + 167 + string_stream_destroy(stream); 168 + } 169 + 170 + struct string_stream *kunit_alloc_string_stream(struct kunit *test, gfp_t gfp) 171 + { 172 + struct string_stream *stream; 173 + 174 + stream = alloc_string_stream(gfp); 175 + if (IS_ERR(stream)) 176 + return stream; 177 + 178 + if (kunit_add_action_or_reset(test, resource_free_string_stream, stream) != 0) 179 + return ERR_PTR(-ENOMEM); 180 + 181 + return stream; 182 + } 183 + 184 + void kunit_free_string_stream(struct kunit *test, struct string_stream *stream) 185 + { 186 + kunit_release_action(test, resource_free_string_stream, (void *)stream); 175 187 }
+14 -2
lib/kunit/string-stream.h
··· 23 23 struct list_head fragments; 24 24 /* length and fragments are protected by this lock */ 25 25 spinlock_t lock; 26 - struct kunit *test; 27 26 gfp_t gfp; 27 + bool append_newlines; 28 28 }; 29 29 30 30 struct kunit; 31 31 32 - struct string_stream *alloc_string_stream(struct kunit *test, gfp_t gfp); 32 + struct string_stream *kunit_alloc_string_stream(struct kunit *test, gfp_t gfp); 33 + void kunit_free_string_stream(struct kunit *test, struct string_stream *stream); 34 + 35 + struct string_stream *alloc_string_stream(gfp_t gfp); 36 + void free_string_stream(struct string_stream *stream); 33 37 34 38 int __printf(2, 3) string_stream_add(struct string_stream *stream, 35 39 const char *fmt, ...); ··· 41 37 int __printf(2, 0) string_stream_vadd(struct string_stream *stream, 42 38 const char *fmt, 43 39 va_list args); 40 + 41 + void string_stream_clear(struct string_stream *stream); 44 42 45 43 char *string_stream_get_string(struct string_stream *stream); 46 44 ··· 52 46 bool string_stream_is_empty(struct string_stream *stream); 53 47 54 48 void string_stream_destroy(struct string_stream *stream); 49 + 50 + static inline void string_stream_set_append_newlines(struct string_stream *stream, 51 + bool append_newlines) 52 + { 53 + stream->append_newlines = append_newlines; 54 + } 55 55 56 56 #endif /* _KUNIT_STRING_STREAM_H */
+12 -44
lib/kunit/test.c
··· 109 109 stats.total); 110 110 } 111 111 112 - /** 113 - * kunit_log_newline() - Add newline to the end of log if one is not 114 - * already present. 115 - * @log: The log to add the newline to. 116 - */ 117 - static void kunit_log_newline(char *log) 118 - { 119 - int log_len, len_left; 120 - 121 - log_len = strlen(log); 122 - len_left = KUNIT_LOG_SIZE - log_len - 1; 123 - 124 - if (log_len > 0 && log[log_len - 1] != '\n') 125 - strncat(log, "\n", len_left); 126 - } 127 - 128 - /* 129 - * Append formatted message to log, size of which is limited to 130 - * KUNIT_LOG_SIZE bytes (including null terminating byte). 131 - */ 132 - void kunit_log_append(char *log, const char *fmt, ...) 112 + /* Append formatted message to log. */ 113 + void kunit_log_append(struct string_stream *log, const char *fmt, ...) 133 114 { 134 115 va_list args; 135 - int len, log_len, len_left; 136 116 137 117 if (!log) 138 118 return; 139 119 140 - log_len = strlen(log); 141 - len_left = KUNIT_LOG_SIZE - log_len - 1; 142 - if (len_left <= 0) 143 - return; 144 - 145 - /* Evaluate length of line to add to log */ 146 120 va_start(args, fmt); 147 - len = vsnprintf(NULL, 0, fmt, args) + 1; 121 + string_stream_vadd(log, fmt, args); 148 122 va_end(args); 149 - 150 - /* Print formatted line to the log */ 151 - va_start(args, fmt); 152 - vsnprintf(log + log_len, min(len, len_left), fmt, args); 153 - va_end(args); 154 - 155 - /* Add newline to end of log if not already present. */ 156 - kunit_log_newline(log); 157 123 } 158 124 EXPORT_SYMBOL_GPL(kunit_log_append); 159 125 ··· 262 296 kunit_err(test, "\n"); 263 297 } else { 264 298 kunit_err(test, "%s", buf); 265 - kunit_kfree(test, buf); 299 + kfree(buf); 266 300 } 267 301 } 268 302 ··· 274 308 275 309 kunit_set_failure(test); 276 310 277 - stream = alloc_string_stream(test, GFP_KERNEL); 311 + stream = kunit_alloc_string_stream(test, GFP_KERNEL); 278 312 if (IS_ERR(stream)) { 279 313 WARN(true, 280 314 "Could not allocate stream to print failed assertion in %s:%d\n", ··· 288 322 289 323 kunit_print_string_stream(test, stream); 290 324 291 - string_stream_destroy(stream); 325 + kunit_free_string_stream(test, stream); 292 326 } 293 327 294 328 void __noreturn __kunit_abort(struct kunit *test) ··· 325 359 } 326 360 EXPORT_SYMBOL_GPL(__kunit_do_failed_assertion); 327 361 328 - void kunit_init_test(struct kunit *test, const char *name, char *log) 362 + void kunit_init_test(struct kunit *test, const char *name, struct string_stream *log) 329 363 { 330 364 spin_lock_init(&test->lock); 331 365 INIT_LIST_HEAD(&test->resources); 332 366 test->name = name; 333 367 test->log = log; 334 368 if (test->log) 335 - test->log[0] = '\0'; 369 + string_stream_clear(log); 336 370 test->status = KUNIT_SUCCESS; 337 371 test->status_comment[0] = '\0'; 338 372 } ··· 614 648 param_desc, 615 649 test.status_comment); 616 650 651 + kunit_update_stats(&param_stats, test.status); 652 + 617 653 /* Get next param. */ 618 654 param_desc[0] = '\0'; 619 655 test.param_value = test_case->generate_params(test.param_value, param_desc); 620 656 test.param_index++; 621 - 622 - kunit_update_stats(&param_stats, test.status); 657 + test.status = KUNIT_SUCCESS; 658 + test.status_comment[0] = '\0'; 623 659 } 624 660 } 625 661