Commit | Line | Data |
---|---|---|
d8e2a76b BH |
1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* | |
3 | * KUnit test for struct string_stream. | |
4 | * | |
5 | * Copyright (C) 2019, Google LLC. | |
6 | * Author: Brendan Higgins <brendanhiggins@google.com> | |
7 | */ | |
8 | ||
d1a0d699 | 9 | #include <kunit/static_stub.h> |
d8e2a76b | 10 | #include <kunit/test.h> |
53568b72 | 11 | #include <linux/ktime.h> |
d8e2a76b | 12 | #include <linux/slab.h> |
53568b72 | 13 | #include <linux/timekeeping.h> |
d8e2a76b | 14 | |
109fb06f AM |
15 | #include "string-stream.h" |
16 | ||
d1a0d699 RF |
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(). */ | |
a96a3945 | 25 | KUNIT_DEFINE_ACTION_WRAPPER(kfree_wrapper, kfree, const void *); |
a3fdf784 | 26 | |
d1a0d699 | 27 | /* Avoids a cast warning if string_stream_destroy() is passed direct to kunit_add_action(). */ |
a96a3945 | 28 | KUNIT_DEFINE_ACTION_WRAPPER(cleanup_raw_stream, string_stream_destroy, struct string_stream *); |
d1a0d699 | 29 | |
4551caca | 30 | static char *get_concatenated_string(struct kunit *test, struct string_stream *stream) |
d8e2a76b | 31 | { |
4551caca | 32 | char *str = string_stream_get_string(stream); |
d8e2a76b | 33 | |
4551caca | 34 | KUNIT_ASSERT_NOT_ERR_OR_NULL(test, str); |
a3fdf784 | 35 | kunit_add_action(test, kfree_wrapper, (void *)str); |
4551caca RF |
36 | |
37 | return str; | |
38 | } | |
39 | ||
d1a0d699 RF |
40 | /* Managed string_stream object is initialized correctly. */ |
41 | static void string_stream_managed_init_test(struct kunit *test) | |
4551caca RF |
42 | { |
43 | struct string_stream *stream; | |
44 | ||
d1a0d699 | 45 | /* Resource-managed initialization. */ |
20631e15 | 46 | stream = kunit_alloc_string_stream(test, GFP_KERNEL); |
4551caca RF |
47 | KUNIT_ASSERT_NOT_ERR_OR_NULL(test, stream); |
48 | ||
49 | KUNIT_EXPECT_EQ(test, stream->length, 0); | |
50 | KUNIT_EXPECT_TRUE(test, list_empty(&stream->fragments)); | |
4551caca | 51 | KUNIT_EXPECT_TRUE(test, (stream->gfp == GFP_KERNEL)); |
1f58cdb1 | 52 | KUNIT_EXPECT_FALSE(test, stream->append_newlines); |
d8e2a76b BH |
53 | KUNIT_EXPECT_TRUE(test, string_stream_is_empty(stream)); |
54 | } | |
55 | ||
d1a0d699 RF |
56 | /* Unmanaged string_stream object is initialized correctly. */ |
57 | static void string_stream_unmanaged_init_test(struct kunit *test) | |
58 | { | |
59 | struct string_stream *stream; | |
60 | ||
61 | stream = alloc_string_stream(GFP_KERNEL); | |
62 | KUNIT_ASSERT_NOT_ERR_OR_NULL(test, stream); | |
63 | kunit_add_action(test, cleanup_raw_stream, stream); | |
64 | ||
65 | KUNIT_EXPECT_EQ(test, stream->length, 0); | |
66 | KUNIT_EXPECT_TRUE(test, list_empty(&stream->fragments)); | |
37f0d37f | 67 | KUNIT_EXPECT_TRUE(test, (stream->gfp == GFP_KERNEL)); |
d1a0d699 RF |
68 | KUNIT_EXPECT_FALSE(test, stream->append_newlines); |
69 | ||
70 | KUNIT_EXPECT_TRUE(test, string_stream_is_empty(stream)); | |
71 | } | |
72 | ||
73 | static void string_stream_destroy_stub(struct string_stream *stream) | |
74 | { | |
75 | struct kunit *fake_test = kunit_get_current_test(); | |
76 | struct string_stream_test_priv *priv = fake_test->priv; | |
77 | ||
78 | /* The kunit could own string_streams other than the one we are testing. */ | |
79 | if (stream == priv->expected_free_stream) { | |
80 | if (priv->stream_was_freed) | |
81 | priv->stream_free_again = true; | |
82 | else | |
83 | priv->stream_was_freed = true; | |
84 | } | |
85 | ||
86 | /* | |
87 | * Calling string_stream_destroy() will only call this function again | |
88 | * because the redirection stub is still active. | |
89 | * Avoid calling deactivate_static_stub() or changing current->kunit_test | |
90 | * during cleanup. | |
91 | */ | |
92 | string_stream_clear(stream); | |
93 | kfree(stream); | |
94 | } | |
95 | ||
96 | /* kunit_free_string_stream() calls string_stream_desrtoy() */ | |
97 | static void string_stream_managed_free_test(struct kunit *test) | |
98 | { | |
99 | struct string_stream_test_priv *priv = test->priv; | |
100 | ||
101 | priv->expected_free_stream = NULL; | |
102 | priv->stream_was_freed = false; | |
103 | priv->stream_free_again = false; | |
104 | ||
105 | kunit_activate_static_stub(test, | |
106 | string_stream_destroy, | |
107 | string_stream_destroy_stub); | |
108 | ||
109 | priv->expected_free_stream = kunit_alloc_string_stream(test, GFP_KERNEL); | |
110 | KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv->expected_free_stream); | |
111 | ||
112 | /* This should call the stub function. */ | |
113 | kunit_free_string_stream(test, priv->expected_free_stream); | |
114 | ||
115 | KUNIT_EXPECT_TRUE(test, priv->stream_was_freed); | |
116 | KUNIT_EXPECT_FALSE(test, priv->stream_free_again); | |
117 | } | |
118 | ||
119 | /* string_stream object is freed when test is cleaned up. */ | |
120 | static void string_stream_resource_free_test(struct kunit *test) | |
121 | { | |
122 | struct string_stream_test_priv *priv = test->priv; | |
123 | struct kunit *fake_test; | |
124 | ||
125 | fake_test = kunit_kzalloc(test, sizeof(*fake_test), GFP_KERNEL); | |
126 | KUNIT_ASSERT_NOT_ERR_OR_NULL(test, fake_test); | |
127 | ||
128 | kunit_init_test(fake_test, "string_stream_fake_test", NULL); | |
129 | fake_test->priv = priv; | |
130 | ||
131 | /* | |
132 | * Activate stub before creating string_stream so the | |
133 | * string_stream will be cleaned up first. | |
134 | */ | |
135 | priv->expected_free_stream = NULL; | |
136 | priv->stream_was_freed = false; | |
137 | priv->stream_free_again = false; | |
138 | ||
139 | kunit_activate_static_stub(fake_test, | |
140 | string_stream_destroy, | |
141 | string_stream_destroy_stub); | |
142 | ||
143 | priv->expected_free_stream = kunit_alloc_string_stream(fake_test, GFP_KERNEL); | |
144 | KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv->expected_free_stream); | |
145 | ||
146 | /* Set current->kunit_test to fake_test so the static stub will be called. */ | |
147 | current->kunit_test = fake_test; | |
148 | ||
149 | /* Cleanup test - the stub function should be called */ | |
150 | kunit_cleanup(fake_test); | |
151 | ||
152 | /* Set current->kunit_test back to current test. */ | |
153 | current->kunit_test = test; | |
154 | ||
155 | KUNIT_EXPECT_TRUE(test, priv->stream_was_freed); | |
156 | KUNIT_EXPECT_FALSE(test, priv->stream_free_again); | |
157 | } | |
158 | ||
4551caca RF |
159 | /* |
160 | * Add a series of lines to a string_stream. Check that all lines | |
161 | * appear in the correct order and no characters are dropped. | |
162 | */ | |
163 | static void string_stream_line_add_test(struct kunit *test) | |
164 | { | |
165 | struct string_stream *stream; | |
166 | char line[60]; | |
167 | char *concat_string, *pos, *string_end; | |
168 | size_t len, total_len; | |
169 | int num_lines, i; | |
170 | ||
20631e15 | 171 | stream = kunit_alloc_string_stream(test, GFP_KERNEL); |
4551caca RF |
172 | KUNIT_ASSERT_NOT_ERR_OR_NULL(test, stream); |
173 | ||
174 | /* Add series of sequence numbered lines */ | |
175 | total_len = 0; | |
176 | for (i = 0; i < 100; ++i) { | |
177 | len = snprintf(line, sizeof(line), | |
178 | "The quick brown fox jumps over the lazy penguin %d\n", i); | |
179 | ||
180 | /* Sanity-check that our test string isn't truncated */ | |
181 | KUNIT_ASSERT_LT(test, len, sizeof(line)); | |
182 | ||
183 | string_stream_add(stream, line); | |
184 | total_len += len; | |
185 | } | |
186 | num_lines = i; | |
187 | ||
188 | concat_string = get_concatenated_string(test, stream); | |
189 | KUNIT_EXPECT_NOT_ERR_OR_NULL(test, concat_string); | |
190 | KUNIT_EXPECT_EQ(test, strlen(concat_string), total_len); | |
191 | ||
192 | /* | |
193 | * Split the concatenated string at the newlines and check that | |
194 | * all the original added strings are present. | |
195 | */ | |
196 | pos = concat_string; | |
197 | for (i = 0; i < num_lines; ++i) { | |
198 | string_end = strchr(pos, '\n'); | |
199 | KUNIT_EXPECT_NOT_NULL(test, string_end); | |
200 | ||
201 | /* Convert to NULL-terminated string */ | |
202 | *string_end = '\0'; | |
203 | ||
204 | snprintf(line, sizeof(line), | |
205 | "The quick brown fox jumps over the lazy penguin %d", i); | |
206 | KUNIT_EXPECT_STREQ(test, pos, line); | |
207 | ||
208 | pos = string_end + 1; | |
209 | } | |
210 | ||
211 | /* There shouldn't be any more data after this */ | |
212 | KUNIT_EXPECT_EQ(test, strlen(pos), 0); | |
213 | } | |
214 | ||
215 | /* Add a series of lines of variable length to a string_stream. */ | |
216 | static void string_stream_variable_length_line_test(struct kunit *test) | |
217 | { | |
218 | static const char line[] = | |
219 | "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" | |
220 | " 0123456789!$%^&*()_-+={}[]:;@'~#<>,.?/|"; | |
221 | struct string_stream *stream; | |
222 | struct rnd_state rnd; | |
223 | char *concat_string, *pos, *string_end; | |
224 | size_t offset, total_len; | |
225 | int num_lines, i; | |
226 | ||
20631e15 | 227 | stream = kunit_alloc_string_stream(test, GFP_KERNEL); |
4551caca RF |
228 | KUNIT_ASSERT_NOT_ERR_OR_NULL(test, stream); |
229 | ||
230 | /* | |
231 | * Log many lines of varying lengths until we have created | |
232 | * many fragments. | |
233 | * The "randomness" must be repeatable. | |
234 | */ | |
235 | prandom_seed_state(&rnd, 3141592653589793238ULL); | |
236 | total_len = 0; | |
237 | for (i = 0; i < 100; ++i) { | |
238 | offset = prandom_u32_state(&rnd) % (sizeof(line) - 1); | |
239 | string_stream_add(stream, "%s\n", &line[offset]); | |
240 | total_len += sizeof(line) - offset; | |
241 | } | |
242 | num_lines = i; | |
243 | ||
244 | concat_string = get_concatenated_string(test, stream); | |
245 | KUNIT_EXPECT_NOT_ERR_OR_NULL(test, concat_string); | |
246 | KUNIT_EXPECT_EQ(test, strlen(concat_string), total_len); | |
247 | ||
248 | /* | |
249 | * Split the concatenated string at the newlines and check that | |
250 | * all the original added strings are present. | |
251 | */ | |
252 | prandom_seed_state(&rnd, 3141592653589793238ULL); | |
253 | pos = concat_string; | |
254 | for (i = 0; i < num_lines; ++i) { | |
255 | string_end = strchr(pos, '\n'); | |
256 | KUNIT_EXPECT_NOT_NULL(test, string_end); | |
257 | ||
258 | /* Convert to NULL-terminated string */ | |
259 | *string_end = '\0'; | |
260 | ||
261 | offset = prandom_u32_state(&rnd) % (sizeof(line) - 1); | |
262 | KUNIT_EXPECT_STREQ(test, pos, &line[offset]); | |
263 | ||
264 | pos = string_end + 1; | |
265 | } | |
266 | ||
267 | /* There shouldn't be any more data after this */ | |
268 | KUNIT_EXPECT_EQ(test, strlen(pos), 0); | |
269 | } | |
270 | ||
271 | /* Appending the content of one string stream to another. */ | |
272 | static void string_stream_append_test(struct kunit *test) | |
d8e2a76b | 273 | { |
4551caca RF |
274 | static const char * const strings_1[] = { |
275 | "one", "two", "three", "four", "five", "six", | |
276 | "seven", "eight", "nine", "ten", | |
277 | }; | |
278 | static const char * const strings_2[] = { | |
279 | "Apple", "Pear", "Orange", "Banana", "Grape", "Apricot", | |
280 | }; | |
281 | struct string_stream *stream_1, *stream_2; | |
282 | const char *stream1_content_before_append, *stream_2_content; | |
283 | char *combined_content; | |
284 | size_t combined_length; | |
285 | int i; | |
286 | ||
20631e15 | 287 | stream_1 = kunit_alloc_string_stream(test, GFP_KERNEL); |
4551caca RF |
288 | KUNIT_ASSERT_NOT_ERR_OR_NULL(test, stream_1); |
289 | ||
20631e15 | 290 | stream_2 = kunit_alloc_string_stream(test, GFP_KERNEL); |
4551caca RF |
291 | KUNIT_ASSERT_NOT_ERR_OR_NULL(test, stream_2); |
292 | ||
293 | /* Append content of empty stream to empty stream */ | |
294 | string_stream_append(stream_1, stream_2); | |
295 | KUNIT_EXPECT_EQ(test, strlen(get_concatenated_string(test, stream_1)), 0); | |
d8e2a76b | 296 | |
4551caca RF |
297 | /* Add some data to stream_1 */ |
298 | for (i = 0; i < ARRAY_SIZE(strings_1); ++i) | |
299 | string_stream_add(stream_1, "%s\n", strings_1[i]); | |
d8e2a76b | 300 | |
4551caca RF |
301 | stream1_content_before_append = get_concatenated_string(test, stream_1); |
302 | ||
303 | /* Append content of empty stream to non-empty stream */ | |
304 | string_stream_append(stream_1, stream_2); | |
305 | KUNIT_EXPECT_STREQ(test, get_concatenated_string(test, stream_1), | |
306 | stream1_content_before_append); | |
307 | ||
308 | /* Add some data to stream_2 */ | |
309 | for (i = 0; i < ARRAY_SIZE(strings_2); ++i) | |
310 | string_stream_add(stream_2, "%s\n", strings_2[i]); | |
311 | ||
312 | /* Append content of non-empty stream to non-empty stream */ | |
313 | string_stream_append(stream_1, stream_2); | |
314 | ||
315 | /* | |
316 | * End result should be the original content of stream_1 plus | |
317 | * the content of stream_2. | |
318 | */ | |
319 | stream_2_content = get_concatenated_string(test, stream_2); | |
320 | combined_length = strlen(stream1_content_before_append) + strlen(stream_2_content); | |
321 | combined_length++; /* for terminating \0 */ | |
322 | combined_content = kunit_kmalloc(test, combined_length, GFP_KERNEL); | |
323 | KUNIT_ASSERT_NOT_ERR_OR_NULL(test, combined_content); | |
324 | snprintf(combined_content, combined_length, "%s%s", | |
325 | stream1_content_before_append, stream_2_content); | |
326 | ||
327 | KUNIT_EXPECT_STREQ(test, get_concatenated_string(test, stream_1), combined_content); | |
328 | ||
329 | /* Append content of non-empty stream to empty stream */ | |
20631e15 | 330 | kunit_free_string_stream(test, stream_1); |
4551caca | 331 | |
20631e15 | 332 | stream_1 = kunit_alloc_string_stream(test, GFP_KERNEL); |
4551caca RF |
333 | KUNIT_ASSERT_NOT_ERR_OR_NULL(test, stream_1); |
334 | ||
335 | string_stream_append(stream_1, stream_2); | |
336 | KUNIT_EXPECT_STREQ(test, get_concatenated_string(test, stream_1), stream_2_content); | |
d8e2a76b BH |
337 | } |
338 | ||
1f58cdb1 RF |
339 | /* Appending the content of one string stream to one with auto-newlining. */ |
340 | static void string_stream_append_auto_newline_test(struct kunit *test) | |
341 | { | |
342 | struct string_stream *stream_1, *stream_2; | |
343 | ||
344 | /* Stream 1 has newline appending enabled */ | |
20631e15 | 345 | stream_1 = kunit_alloc_string_stream(test, GFP_KERNEL); |
1f58cdb1 RF |
346 | KUNIT_ASSERT_NOT_ERR_OR_NULL(test, stream_1); |
347 | string_stream_set_append_newlines(stream_1, true); | |
348 | KUNIT_EXPECT_TRUE(test, stream_1->append_newlines); | |
349 | ||
350 | /* Stream 2 does not append newlines */ | |
20631e15 | 351 | stream_2 = kunit_alloc_string_stream(test, GFP_KERNEL); |
1f58cdb1 RF |
352 | KUNIT_ASSERT_NOT_ERR_OR_NULL(test, stream_2); |
353 | ||
354 | /* Appending a stream with a newline should not add another newline */ | |
355 | string_stream_add(stream_1, "Original string\n"); | |
356 | string_stream_add(stream_2, "Appended content\n"); | |
357 | string_stream_add(stream_2, "More stuff\n"); | |
358 | string_stream_append(stream_1, stream_2); | |
359 | KUNIT_EXPECT_STREQ(test, get_concatenated_string(test, stream_1), | |
360 | "Original string\nAppended content\nMore stuff\n"); | |
361 | ||
20631e15 RF |
362 | kunit_free_string_stream(test, stream_2); |
363 | stream_2 = kunit_alloc_string_stream(test, GFP_KERNEL); | |
1f58cdb1 RF |
364 | KUNIT_ASSERT_NOT_ERR_OR_NULL(test, stream_2); |
365 | ||
366 | /* | |
367 | * Appending a stream without newline should add a final newline. | |
368 | * The appended string_stream is treated as a single string so newlines | |
369 | * should not be inserted between fragments. | |
370 | */ | |
371 | string_stream_add(stream_2, "Another"); | |
372 | string_stream_add(stream_2, "And again"); | |
373 | string_stream_append(stream_1, stream_2); | |
374 | KUNIT_EXPECT_STREQ(test, get_concatenated_string(test, stream_1), | |
375 | "Original string\nAppended content\nMore stuff\nAnotherAnd again\n"); | |
376 | } | |
377 | ||
4551caca RF |
378 | /* Adding an empty string should not create a fragment. */ |
379 | static void string_stream_append_empty_string_test(struct kunit *test) | |
d8e2a76b | 380 | { |
4551caca RF |
381 | struct string_stream *stream; |
382 | int original_frag_count; | |
383 | ||
20631e15 | 384 | stream = kunit_alloc_string_stream(test, GFP_KERNEL); |
4551caca RF |
385 | KUNIT_ASSERT_NOT_ERR_OR_NULL(test, stream); |
386 | ||
387 | /* Formatted empty string */ | |
388 | string_stream_add(stream, "%s", ""); | |
389 | KUNIT_EXPECT_TRUE(test, string_stream_is_empty(stream)); | |
390 | KUNIT_EXPECT_TRUE(test, list_empty(&stream->fragments)); | |
d8e2a76b | 391 | |
4551caca RF |
392 | /* Adding an empty string to a non-empty stream */ |
393 | string_stream_add(stream, "Add this line"); | |
394 | original_frag_count = list_count_nodes(&stream->fragments); | |
d8e2a76b | 395 | |
4551caca RF |
396 | string_stream_add(stream, "%s", ""); |
397 | KUNIT_EXPECT_EQ(test, list_count_nodes(&stream->fragments), original_frag_count); | |
398 | KUNIT_EXPECT_STREQ(test, get_concatenated_string(test, stream), "Add this line"); | |
d8e2a76b BH |
399 | } |
400 | ||
1f58cdb1 RF |
401 | /* Adding strings without automatic newline appending */ |
402 | static void string_stream_no_auto_newline_test(struct kunit *test) | |
403 | { | |
404 | struct string_stream *stream; | |
405 | ||
20631e15 | 406 | stream = kunit_alloc_string_stream(test, GFP_KERNEL); |
1f58cdb1 RF |
407 | KUNIT_ASSERT_NOT_ERR_OR_NULL(test, stream); |
408 | ||
409 | /* | |
410 | * Add some strings with and without newlines. All formatted newlines | |
411 | * should be preserved. It should not add any extra newlines. | |
412 | */ | |
413 | string_stream_add(stream, "One"); | |
414 | string_stream_add(stream, "Two\n"); | |
415 | string_stream_add(stream, "%s\n", "Three"); | |
416 | string_stream_add(stream, "%s", "Four\n"); | |
417 | string_stream_add(stream, "Five\n%s", "Six"); | |
418 | string_stream_add(stream, "Seven\n\n"); | |
419 | string_stream_add(stream, "Eight"); | |
420 | KUNIT_EXPECT_STREQ(test, get_concatenated_string(test, stream), | |
421 | "OneTwo\nThree\nFour\nFive\nSixSeven\n\nEight"); | |
422 | } | |
423 | ||
424 | /* Adding strings with automatic newline appending */ | |
425 | static void string_stream_auto_newline_test(struct kunit *test) | |
426 | { | |
427 | struct string_stream *stream; | |
428 | ||
20631e15 | 429 | stream = kunit_alloc_string_stream(test, GFP_KERNEL); |
1f58cdb1 RF |
430 | KUNIT_ASSERT_NOT_ERR_OR_NULL(test, stream); |
431 | ||
432 | string_stream_set_append_newlines(stream, true); | |
433 | KUNIT_EXPECT_TRUE(test, stream->append_newlines); | |
434 | ||
435 | /* | |
436 | * Add some strings with and without newlines. Newlines should | |
437 | * be appended to lines that do not end with \n, but newlines | |
438 | * resulting from the formatting should not be changed. | |
439 | */ | |
440 | string_stream_add(stream, "One"); | |
441 | string_stream_add(stream, "Two\n"); | |
442 | string_stream_add(stream, "%s\n", "Three"); | |
443 | string_stream_add(stream, "%s", "Four\n"); | |
444 | string_stream_add(stream, "Five\n%s", "Six"); | |
445 | string_stream_add(stream, "Seven\n\n"); | |
446 | string_stream_add(stream, "Eight"); | |
447 | KUNIT_EXPECT_STREQ(test, get_concatenated_string(test, stream), | |
448 | "One\nTwo\nThree\nFour\nFive\nSix\nSeven\n\nEight\n"); | |
449 | } | |
450 | ||
53568b72 RF |
451 | /* |
452 | * This doesn't actually "test" anything. It reports time taken | |
453 | * and memory used for logging a large number of lines. | |
454 | */ | |
455 | static void string_stream_performance_test(struct kunit *test) | |
456 | { | |
457 | struct string_stream_fragment *frag_container; | |
458 | struct string_stream *stream; | |
459 | char test_line[101]; | |
460 | ktime_t start_time, end_time; | |
461 | size_t len, bytes_requested, actual_bytes_used, total_string_length; | |
462 | int offset, i; | |
463 | ||
464 | stream = kunit_alloc_string_stream(test, GFP_KERNEL); | |
465 | KUNIT_ASSERT_NOT_ERR_OR_NULL(test, stream); | |
466 | ||
467 | memset(test_line, 'x', sizeof(test_line) - 1); | |
468 | test_line[sizeof(test_line) - 1] = '\0'; | |
469 | ||
470 | start_time = ktime_get(); | |
471 | for (i = 0; i < 10000; i++) { | |
472 | offset = i % (sizeof(test_line) - 1); | |
473 | string_stream_add(stream, "%s: %d\n", &test_line[offset], i); | |
474 | } | |
475 | end_time = ktime_get(); | |
476 | ||
477 | /* | |
478 | * Calculate memory used. This doesn't include invisible | |
479 | * overhead due to kernel allocator fragment size rounding. | |
480 | */ | |
481 | bytes_requested = sizeof(*stream); | |
482 | actual_bytes_used = ksize(stream); | |
483 | total_string_length = 0; | |
484 | ||
485 | list_for_each_entry(frag_container, &stream->fragments, node) { | |
486 | bytes_requested += sizeof(*frag_container); | |
487 | actual_bytes_used += ksize(frag_container); | |
488 | ||
489 | len = strlen(frag_container->fragment); | |
490 | total_string_length += len; | |
491 | bytes_requested += len + 1; /* +1 for '\0' */ | |
492 | actual_bytes_used += ksize(frag_container->fragment); | |
493 | } | |
494 | ||
495 | kunit_info(test, "Time elapsed: %lld us\n", | |
496 | ktime_us_delta(end_time, start_time)); | |
497 | kunit_info(test, "Total string length: %zu\n", total_string_length); | |
498 | kunit_info(test, "Bytes requested: %zu\n", bytes_requested); | |
499 | kunit_info(test, "Actual bytes allocated: %zu\n", actual_bytes_used); | |
500 | } | |
501 | ||
d1a0d699 RF |
502 | static int string_stream_test_init(struct kunit *test) |
503 | { | |
504 | struct string_stream_test_priv *priv; | |
505 | ||
506 | priv = kunit_kzalloc(test, sizeof(*priv), GFP_KERNEL); | |
507 | if (!priv) | |
508 | return -ENOMEM; | |
509 | ||
510 | test->priv = priv; | |
511 | ||
512 | return 0; | |
513 | } | |
514 | ||
d8e2a76b | 515 | static struct kunit_case string_stream_test_cases[] = { |
d1a0d699 RF |
516 | KUNIT_CASE(string_stream_managed_init_test), |
517 | KUNIT_CASE(string_stream_unmanaged_init_test), | |
518 | KUNIT_CASE(string_stream_managed_free_test), | |
519 | KUNIT_CASE(string_stream_resource_free_test), | |
4551caca RF |
520 | KUNIT_CASE(string_stream_line_add_test), |
521 | KUNIT_CASE(string_stream_variable_length_line_test), | |
522 | KUNIT_CASE(string_stream_append_test), | |
1f58cdb1 | 523 | KUNIT_CASE(string_stream_append_auto_newline_test), |
4551caca | 524 | KUNIT_CASE(string_stream_append_empty_string_test), |
1f58cdb1 RF |
525 | KUNIT_CASE(string_stream_no_auto_newline_test), |
526 | KUNIT_CASE(string_stream_auto_newline_test), | |
53568b72 | 527 | KUNIT_CASE(string_stream_performance_test), |
d8e2a76b BH |
528 | {} |
529 | }; | |
530 | ||
531 | static struct kunit_suite string_stream_test_suite = { | |
532 | .name = "string-stream-test", | |
d1a0d699 RF |
533 | .test_cases = string_stream_test_cases, |
534 | .init = string_stream_test_init, | |
d8e2a76b | 535 | }; |
c475c77d | 536 | kunit_test_suites(&string_stream_test_suite); |