Commit 5eda8f25 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'linux_kselftest-kunit-6.7-rc1' of...

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
parents 463f46e1 8040345f
......@@ -33,9 +33,7 @@
DECLARE_STATIC_KEY_FALSE(kunit_running);
struct kunit;
/* Size of log associated with test. */
#define KUNIT_LOG_SIZE 2048
struct string_stream;
/* Maximum size of parameter description string. */
#define KUNIT_PARAM_DESC_SIZE 128
......@@ -133,7 +131,7 @@ struct kunit_case {
/* private: internal use only. */
enum kunit_status status;
char *module_name;
char *log;
struct string_stream *log;
};
static inline char *kunit_status_to_ok_not_ok(enum kunit_status status)
......@@ -253,7 +251,7 @@ struct kunit_suite {
/* private: internal use only */
char status_comment[KUNIT_STATUS_COMMENT_SIZE];
struct dentry *debugfs;
char *log;
struct string_stream *log;
int suite_init_err;
};
......@@ -279,7 +277,7 @@ struct kunit {
/* private: internal use only. */
const char *name; /* Read only after initialization! */
char *log; /* Points at case log after initialization */
struct string_stream *log; /* Points at case log after initialization */
struct kunit_try_catch try_catch;
/* param_value is the current parameter value for a test case. */
const void *param_value;
......@@ -315,7 +313,7 @@ const char *kunit_filter_glob(void);
char *kunit_filter(void);
char *kunit_filter_action(void);
void kunit_init_test(struct kunit *test, const char *name, char *log);
void kunit_init_test(struct kunit *test, const char *name, struct string_stream *log);
int kunit_run_tests(struct kunit_suite *suite);
......@@ -473,7 +471,7 @@ static inline void *kunit_kcalloc(struct kunit *test, size_t n, size_t size, gfp
void kunit_cleanup(struct kunit *test);
void __printf(2, 3) kunit_log_append(char *log, const char *fmt, ...);
void __printf(2, 3) kunit_log_append(struct string_stream *log, const char *fmt, ...);
/**
* kunit_mark_skipped() - Marks @test_or_suite as skipped
......
......@@ -89,8 +89,7 @@ void kunit_ptr_not_err_assert_format(const struct kunit_assert *assert,
EXPORT_SYMBOL_GPL(kunit_ptr_not_err_assert_format);
/* Checks if `text` is a literal representing `value`, e.g. "5" and 5 */
static bool is_literal(struct kunit *test, const char *text, long long value,
gfp_t gfp)
static bool is_literal(const char *text, long long value)
{
char *buffer;
int len;
......@@ -100,14 +99,15 @@ static bool is_literal(struct kunit *test, const char *text, long long value,
if (strlen(text) != len)
return false;
buffer = kunit_kmalloc(test, len+1, gfp);
buffer = kmalloc(len+1, GFP_KERNEL);
if (!buffer)
return false;
snprintf(buffer, len+1, "%lld", value);
ret = strncmp(buffer, text, len) == 0;
kunit_kfree(test, buffer);
kfree(buffer);
return ret;
}
......@@ -125,14 +125,12 @@ void kunit_binary_assert_format(const struct kunit_assert *assert,
binary_assert->text->left_text,
binary_assert->text->operation,
binary_assert->text->right_text);
if (!is_literal(stream->test, binary_assert->text->left_text,
binary_assert->left_value, stream->gfp))
if (!is_literal(binary_assert->text->left_text, binary_assert->left_value))
string_stream_add(stream, KUNIT_SUBSUBTEST_INDENT "%s == %lld (0x%llx)\n",
binary_assert->text->left_text,
binary_assert->left_value,
binary_assert->left_value);
if (!is_literal(stream->test, binary_assert->text->right_text,
binary_assert->right_value, stream->gfp))
if (!is_literal(binary_assert->text->right_text, binary_assert->right_value))
string_stream_add(stream, KUNIT_SUBSUBTEST_INDENT "%s == %lld (0x%llx)",
binary_assert->text->right_text,
binary_assert->right_value,
......
......@@ -37,14 +37,21 @@ void kunit_debugfs_init(void)
debugfs_rootdir = debugfs_create_dir(KUNIT_DEBUGFS_ROOT, NULL);
}
static void debugfs_print_result(struct seq_file *seq,
struct kunit_suite *suite,
struct kunit_case *test_case)
static void debugfs_print_result(struct seq_file *seq, struct string_stream *log)
{
if (!test_case || !test_case->log)
struct string_stream_fragment *frag_container;
if (!log)
return;
seq_printf(seq, "%s", test_case->log);
/*
* Walk the fragments so we don't need to allocate a temporary
* buffer to hold the entire string.
*/
spin_lock(&log->lock);
list_for_each_entry(frag_container, &log->fragments, node)
seq_printf(seq, "%s", frag_container->fragment);
spin_unlock(&log->lock);
}
/*
......@@ -69,10 +76,9 @@ static int debugfs_print_results(struct seq_file *seq, void *v)
seq_printf(seq, KUNIT_SUBTEST_INDENT "1..%zd\n", kunit_suite_num_test_cases(suite));
kunit_suite_for_each_test_case(suite, test_case)
debugfs_print_result(seq, suite, test_case);
debugfs_print_result(seq, test_case->log);
if (suite->log)
seq_printf(seq, "%s", suite->log);
debugfs_print_result(seq, suite->log);
seq_printf(seq, "%s %d %s\n",
kunit_status_to_ok_not_ok(success), 1, suite->name);
......@@ -105,9 +111,13 @@ void kunit_debugfs_create_suite(struct kunit_suite *suite)
struct kunit_case *test_case;
/* Allocate logs before creating debugfs representation. */
suite->log = kzalloc(KUNIT_LOG_SIZE, GFP_KERNEL);
kunit_suite_for_each_test_case(suite, test_case)
test_case->log = kzalloc(KUNIT_LOG_SIZE, GFP_KERNEL);
suite->log = alloc_string_stream(GFP_KERNEL);
string_stream_set_append_newlines(suite->log, true);
kunit_suite_for_each_test_case(suite, test_case) {
test_case->log = alloc_string_stream(GFP_KERNEL);
string_stream_set_append_newlines(test_case->log, true);
}
suite->debugfs = debugfs_create_dir(suite->name, debugfs_rootdir);
......@@ -121,7 +131,7 @@ void kunit_debugfs_destroy_suite(struct kunit_suite *suite)
struct kunit_case *test_case;
debugfs_remove_recursive(suite->debugfs);
kfree(suite->log);
string_stream_destroy(suite->log);
kunit_suite_for_each_test_case(suite, test_case)
kfree(test_case->log);
string_stream_destroy(test_case->log);
}
......@@ -137,8 +137,10 @@ void kunit_free_suite_set(struct kunit_suite_set suite_set)
{
struct kunit_suite * const *suites;
for (suites = suite_set.start; suites < suite_set.end; suites++)
for (suites = suite_set.start; suites < suite_set.end; suites++) {
kfree((*suites)->test_cases);
kfree(*suites);
}
kfree(suite_set.start);
}
......@@ -155,10 +157,11 @@ kunit_filter_suites(const struct kunit_suite_set *suite_set,
struct kunit_suite_set filtered = {NULL, NULL};
struct kunit_glob_filter parsed_glob;
struct kunit_attr_filter *parsed_filters = NULL;
struct kunit_suite * const *suites;
const size_t max = suite_set->end - suite_set->start;
copy = kmalloc_array(max, sizeof(*filtered.start), GFP_KERNEL);
copy = kcalloc(max, sizeof(*filtered.start), GFP_KERNEL);
if (!copy) { /* won't be able to run anything, return an empty set */
return filtered;
}
......@@ -193,7 +196,7 @@ kunit_filter_suites(const struct kunit_suite_set *suite_set,
parsed_glob.test_glob);
if (IS_ERR(filtered_suite)) {
*err = PTR_ERR(filtered_suite);
goto free_parsed_filters;
goto free_filtered_suite;
}
}
if (filter_count > 0 && parsed_filters != NULL) {
......@@ -210,11 +213,11 @@ kunit_filter_suites(const struct kunit_suite_set *suite_set,
filtered_suite = new_filtered_suite;
if (*err)
goto free_parsed_filters;
goto free_filtered_suite;
if (IS_ERR(filtered_suite)) {
*err = PTR_ERR(filtered_suite);
goto free_parsed_filters;
goto free_filtered_suite;
}
if (!filtered_suite)
break;
......@@ -229,6 +232,14 @@ kunit_filter_suites(const struct kunit_suite_set *suite_set,
filtered.start = copy_start;
filtered.end = copy;
free_filtered_suite:
if (*err) {
for (suites = copy_start; suites < copy; suites++) {
kfree((*suites)->test_cases);
kfree(*suites);
}
}
free_parsed_filters:
if (filter_count)
kfree(parsed_filters);
......@@ -241,7 +252,7 @@ kunit_filter_suites(const struct kunit_suite_set *suite_set,
free_copy:
if (*err)
kfree(copy);
kfree(copy_start);
return filtered;
}
......
......@@ -9,7 +9,7 @@
#include <kunit/test.h>
#include <kunit/attributes.h>
static void kfree_at_end(struct kunit *test, const void *to_free);
static void free_suite_set_at_end(struct kunit *test, const void *to_free);
static struct kunit_suite *alloc_fake_suite(struct kunit *test,
const char *suite_name,
struct kunit_case *test_cases);
......@@ -56,7 +56,7 @@ static void filter_suites_test(struct kunit *test)
got = kunit_filter_suites(&suite_set, "suite2", NULL, NULL, &err);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, got.start);
KUNIT_ASSERT_EQ(test, err, 0);
kfree_at_end(test, got.start);
free_suite_set_at_end(test, &got);
/* Validate we just have suite2 */
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, got.start[0]);
......@@ -82,7 +82,7 @@ static void filter_suites_test_glob_test(struct kunit *test)
got = kunit_filter_suites(&suite_set, "suite2.test2", NULL, NULL, &err);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, got.start);
KUNIT_ASSERT_EQ(test, err, 0);
kfree_at_end(test, got.start);
free_suite_set_at_end(test, &got);
/* Validate we just have suite2 */
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, got.start[0]);
......@@ -109,7 +109,7 @@ static void filter_suites_to_empty_test(struct kunit *test)
got = kunit_filter_suites(&suite_set, "not_found", NULL, NULL, &err);
KUNIT_ASSERT_EQ(test, err, 0);
kfree_at_end(test, got.start); /* just in case */
free_suite_set_at_end(test, &got); /* just in case */
KUNIT_EXPECT_PTR_EQ_MSG(test, got.start, got.end,
"should be empty to indicate no match");
......@@ -172,7 +172,7 @@ static void filter_attr_test(struct kunit *test)
got = kunit_filter_suites(&suite_set, NULL, filter, NULL, &err);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, got.start);
KUNIT_ASSERT_EQ(test, err, 0);
kfree_at_end(test, got.start);
free_suite_set_at_end(test, &got);
/* Validate we just have normal_suite */
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, got.start[0]);
......@@ -200,7 +200,7 @@ static void filter_attr_empty_test(struct kunit *test)
got = kunit_filter_suites(&suite_set, NULL, filter, NULL, &err);
KUNIT_ASSERT_EQ(test, err, 0);
kfree_at_end(test, got.start); /* just in case */
free_suite_set_at_end(test, &got); /* just in case */
KUNIT_EXPECT_PTR_EQ_MSG(test, got.start, got.end,
"should be empty to indicate no match");
......@@ -222,7 +222,7 @@ static void filter_attr_skip_test(struct kunit *test)
got = kunit_filter_suites(&suite_set, NULL, filter, "skip", &err);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, got.start);
KUNIT_ASSERT_EQ(test, err, 0);
kfree_at_end(test, got.start);
free_suite_set_at_end(test, &got);
/* Validate we have both the slow and normal test */
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, got.start[0]->test_cases);
......@@ -256,18 +256,26 @@ kunit_test_suites(&executor_test_suite);
/* Test helpers */
/* Use the resource API to register a call to kfree(to_free).
static void free_suite_set(void *suite_set)
{
kunit_free_suite_set(*(struct kunit_suite_set *)suite_set);
kfree(suite_set);
}
/* Use the resource API to register a call to free_suite_set.
* Since we never actually use the resource, it's safe to use on const data.
*/
static void kfree_at_end(struct kunit *test, const void *to_free)
static void free_suite_set_at_end(struct kunit *test, const void *to_free)
{
/* kfree() handles NULL already, but avoid allocating a no-op cleanup. */
if (IS_ERR_OR_NULL(to_free))
struct kunit_suite_set *free;
if (!((struct kunit_suite_set *)to_free)->start)
return;
kunit_add_action(test,
(kunit_action_t *)kfree,
(void *)to_free);
free = kzalloc(sizeof(struct kunit_suite_set), GFP_KERNEL);
*free = *(struct kunit_suite_set *)to_free;
kunit_add_action(test, free_suite_set, (void *)free);
}
static struct kunit_suite *alloc_fake_suite(struct kunit *test,
......
......@@ -190,6 +190,7 @@ static void example_static_stub_test(struct kunit *test)
static const struct example_param {
int value;
} example_params_array[] = {
{ .value = 3, },
{ .value = 2, },
{ .value = 1, },
{ .value = 0, },
......@@ -213,8 +214,8 @@ static void example_params_test(struct kunit *test)
KUNIT_ASSERT_NOT_NULL(test, param);
/* Test can be skipped on unsupported param values */
if (!param->value)
kunit_skip(test, "unsupported param value");
if (!is_power_of_2(param->value))
kunit_skip(test, "unsupported param value %d", param->value);
/* You can use param values for parameterized testing */
KUNIT_EXPECT_EQ(test, param->value % param->value, 0);
......
......@@ -8,6 +8,7 @@
#include <kunit/test.h>
#include <kunit/test-bug.h>
#include "string-stream.h"
#include "try-catch-impl.h"
struct kunit_try_catch_test_context {
......@@ -530,12 +531,27 @@ static struct kunit_suite kunit_resource_test_suite = {
.test_cases = kunit_resource_test_cases,
};
/*
* Log tests call string_stream functions, which aren't exported. So only
* build this code if this test is built-in.
*/
#if IS_BUILTIN(CONFIG_KUNIT_TEST)
/* This avoids a cast warning if kfree() is passed direct to kunit_add_action(). */
static void kfree_wrapper(void *p)
{
kfree(p);
}
static void kunit_log_test(struct kunit *test)
{
struct kunit_suite suite;
suite.log = kunit_kzalloc(test, KUNIT_LOG_SIZE, GFP_KERNEL);
#ifdef CONFIG_KUNIT_DEBUGFS
char *full_log;
#endif
suite.log = kunit_alloc_string_stream(test, GFP_KERNEL);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, suite.log);
string_stream_set_append_newlines(suite.log, true);
kunit_log(KERN_INFO, test, "put this in log.");
kunit_log(KERN_INFO, test, "this too.");
......@@ -543,14 +559,21 @@ static void kunit_log_test(struct kunit *test)
kunit_log(KERN_INFO, &suite, "along with this.");
#ifdef CONFIG_KUNIT_DEBUGFS
KUNIT_EXPECT_TRUE(test, test->log->append_newlines);
full_log = string_stream_get_string(test->log);
kunit_add_action(test, (kunit_action_t *)kfree, full_log);
KUNIT_EXPECT_NOT_ERR_OR_NULL(test,
strstr(test->log, "put this in log."));
strstr(full_log, "put this in log."));
KUNIT_EXPECT_NOT_ERR_OR_NULL(test,
strstr(test->log, "this too."));
strstr(full_log, "this too."));
full_log = string_stream_get_string(suite.log);
kunit_add_action(test, kfree_wrapper, full_log);
KUNIT_EXPECT_NOT_ERR_OR_NULL(test,
strstr(suite.log, "add to suite log."));
strstr(full_log, "add to suite log."));
KUNIT_EXPECT_NOT_ERR_OR_NULL(test,
strstr(suite.log, "along with this."));
strstr(full_log, "along with this."));
#else
KUNIT_EXPECT_NULL(test, test->log);
#endif
......@@ -558,15 +581,30 @@ static void kunit_log_test(struct kunit *test)
static void kunit_log_newline_test(struct kunit *test)
{
char *full_log;
kunit_info(test, "Add newline\n");
if (test->log) {
KUNIT_ASSERT_NOT_NULL_MSG(test, strstr(test->log, "Add newline\n"),
"Missing log line, full log:\n%s", test->log);
KUNIT_EXPECT_NULL(test, strstr(test->log, "Add newline\n\n"));
full_log = string_stream_get_string(test->log);
kunit_add_action(test, kfree_wrapper, full_log);
KUNIT_ASSERT_NOT_NULL_MSG(test, strstr(full_log, "Add newline\n"),
"Missing log line, full log:\n%s", full_log);
KUNIT_EXPECT_NULL(test, strstr(full_log, "Add newline\n\n"));
} else {
kunit_skip(test, "only useful when debugfs is enabled");
}
}
#else
static void kunit_log_test(struct kunit *test)
{
kunit_skip(test, "Log tests only run when built-in");
}
static void kunit_log_newline_test(struct kunit *test)
{
kunit_skip(test, "Log tests only run when built-in");
}
#endif /* IS_BUILTIN(CONFIG_KUNIT_TEST) */
static struct kunit_case kunit_log_test_cases[] = {
KUNIT_CASE(kunit_log_test),
......
This diff is collapsed.
......@@ -6,6 +6,7 @@
* Author: Brendan Higgins <brendanhiggins@google.com>
*/
#include <kunit/static_stub.h>
#include <kunit/test.h>
#include <linux/list.h>
#include <linux/slab.h>
......@@ -13,30 +14,28 @@
#include "string-stream.h"
static struct string_stream_fragment *alloc_string_stream_fragment(
struct kunit *test, int len, gfp_t gfp)
static struct string_stream_fragment *alloc_string_stream_fragment(int len, gfp_t gfp)
{
struct string_stream_fragment *frag;
frag = kunit_kzalloc(test, sizeof(*frag), gfp);
frag = kzalloc(sizeof(*frag), gfp);
if (!frag)
return ERR_PTR(-ENOMEM);
frag->fragment = kunit_kmalloc(test, len, gfp);
frag->fragment = kmalloc(len, gfp);
if (!frag->fragment) {
kunit_kfree(test, frag);
kfree(frag);
return ERR_PTR(-ENOMEM);
}
return frag;
}
static void string_stream_fragment_destroy(struct kunit *test,
struct string_stream_fragment *frag)
static void string_stream_fragment_destroy(struct string_stream_fragment *frag)
{
list_del(&frag->node);
kunit_kfree(test, frag->fragment);
kunit_kfree(test, frag);
kfree(frag->fragment);
kfree(frag);
}
int string_stream_vadd(struct string_stream *stream,
......@@ -44,26 +43,44 @@ int string_stream_vadd(struct string_stream *stream,
va_list args)
{
struct string_stream_fragment *frag_container;
int len;
int buf_len, result_len;
va_list args_for_counting;
/* Make a copy because `vsnprintf` could change it */
va_copy(args_for_counting, args);
/* Need space for null byte. */
len = vsnprintf(NULL, 0, fmt, args_for_counting) + 1;
/* Evaluate length of formatted string */
buf_len = vsnprintf(NULL, 0, fmt, args_for_counting);
va_end(args_for_counting);
frag_container = alloc_string_stream_fragment(stream->test,
len,
stream->gfp);
if (buf_len == 0)
return 0;
/* Reserve one extra for possible appended newline. */
if (stream->append_newlines)
buf_len++;
/* Need space for null byte. */
buf_len++;
frag_container = alloc_string_stream_fragment(buf_len, stream->gfp);
if (IS_ERR(frag_container))
return PTR_ERR(frag_container);
len = vsnprintf(frag_container->fragment, len, fmt, args);
if (stream->append_newlines) {
/* Don't include reserved newline byte in writeable length. */
result_len = vsnprintf(frag_container->fragment, buf_len - 1, fmt, args);
/* Append newline if necessary. */
if (frag_container->fragment[result_len - 1] != '\n')
result_len = strlcat(frag_container->fragment, "\n", buf_len);
} else {
result_len = vsnprintf(frag_container->fragment, buf_len, fmt, args);
}
spin_lock(&stream->lock);
stream->length += len;
stream->length += result_len;
list_add_tail(&frag_container->node, &stream->fragments);
spin_unlock(&stream->lock);
......@@ -82,7 +99,7 @@ int string_stream_add(struct string_stream *stream, const char *fmt, ...)
return result;
}
static void string_stream_clear(struct string_stream *stream)
void string_stream_clear(struct string_stream *stream)
{
struct string_stream_fragment *frag_container, *frag_container_safe;
......@@ -91,7 +108,7 @@ static void string_stream_clear(struct string_stream *stream)
frag_container_safe,
&stream->fragments,
node) {
string_stream_fragment_destroy(stream->test, frag_container);
string_stream_fragment_destroy(frag_container);
}
stream->length = 0;
spin_unlock(&stream->lock);
......@@ -103,7 +120,7 @@ char *string_stream_get_string(struct string_stream *stream)
size_t buf_len = stream->length + 1; /* +1 for null byte. */
char *buf;
buf = kunit_kzalloc(stream->test, buf_len, stream->gfp);
buf = kzalloc(buf_len, stream->gfp);
if (!buf)
return NULL;
......@@ -119,13 +136,17 @@ int string_stream_append(struct string_stream *stream,
struct string_stream *other)
{
const char *other_content;
int ret;
other_content = string_stream_get_string(other);
if (!other_content)
return -ENOMEM;
return string_stream_add(stream, other_content);
ret = string_stream_add(stream, other_content);
kfree(other_content);
return ret;
}
bool string_stream_is_empty(struct string_stream *stream)
......@@ -133,16 +154,15 @@ bool string_stream_is_empty(struct string_stream *stream)
return list_empty(&stream->fragments);
}
struct string_stream *alloc_string_stream(struct kunit *test, gfp_t gfp)
struct string_stream *alloc_string_stream(gfp_t gfp)
{
struct string_stream *stream;
stream = kunit_kzalloc(test, sizeof(*stream), gfp);
stream = kzalloc(sizeof(*stream), gfp);
if (!stream)
return ERR_PTR(-ENOMEM);
stream->gfp = gfp;
stream->test = test;
INIT_LIST_HEAD(&stream->fragments);
spin_lock_init(&stream->lock);
......@@ -151,5 +171,37 @@ struct string_stream *alloc_string_stream(struct kunit *test, gfp_t gfp)
void string_stream_destroy(struct string_stream *stream)
{
KUNIT_STATIC_STUB_REDIRECT(string_stream_destroy, stream);
if (!stream)
return;
string_stream_clear(stream);
kfree(stream);
}
static void resource_free_string_stream(void *p)
{
struct string_stream *stream = p;
string_stream_destroy(stream);
}
struct string_stream *kunit_alloc_string_stream(struct kunit *test, gfp_t gfp)
{
struct string_stream *stream;
stream = alloc_string_stream(gfp);
if (IS_ERR(stream))
return stream;
if (kunit_add_action_or_reset(test, resource_free_string_stream, stream) != 0)
return ERR_PTR(-ENOMEM);
return stream;
}
void kunit_free_string_stream(struct kunit *test, struct string_stream *stream)
{
kunit_release_action(test, resource_free_string_stream, (void *)stream);
}
......@@ -23,13 +23,17 @@ struct string_stream {
struct list_head fragments;
/* length and fragments are protected by this lock */
spinlock_t lock;
struct kunit *test;
gfp_t gfp;
bool append_newlines;
};
struct kunit;
struct string_stream *alloc_string_stream(struct kunit *test, gfp_t gfp);
struct string_stream *kunit_alloc_string_stream(struct kunit *test, gfp_t gfp);
void kunit_free_string_stream(struct kunit *test, struct string_stream *stream);
struct string_stream *alloc_string_stream(gfp_t gfp);
void free_string_stream(struct string_stream *stream);
int __printf(2, 3) string_stream_add(struct string_stream *stream,
const char *fmt, ...);
......@@ -38,6 +42,8 @@ int __printf(2, 0) string_stream_vadd(struct string_stream *stream,
const char *fmt,
va_list args);
void string_stream_clear(struct string_stream *stream);
char *string_stream_get_string(struct string_stream *stream);
int string_stream_append(struct string_stream *stream,
......@@ -47,4 +53,10 @@ bool string_stream_is_empty(struct string_stream *stream);
void string_stream_destroy(struct string_stream *stream);
static inline void string_stream_set_append_newlines(struct string_stream *stream,
bool append_newlines)
{
stream->append_newlines = append_newlines;
}
#endif /* _KUNIT_STRING_STREAM_H */
......@@ -109,51 +109,17 @@ static void kunit_print_test_stats(struct kunit *test,
stats.total);
}
/**
* kunit_log_newline() - Add newline to the end of log if one is not
* already present.
* @log: The log to add the newline to.
*/
static void kunit_log_newline(char *log)
{
int log_len, len_left;
log_len = strlen(log);
len_left = KUNIT_LOG_SIZE - log_len - 1;
if (log_len > 0 && log[log_len - 1] != '\n')
strncat(log, "\n", len_left);
}
/*
* Append formatted message to log, size of which is limited to
* KUNIT_LOG_SIZE bytes (including null terminating byte).
*/
void kunit_log_append(char *log, const char *fmt, ...)
/* Append formatted message to log. */
void kunit_log_append(struct string_stream *log, const char *fmt, ...)
{
va_list args;
int len, log_len, len_left;
if (!log)
return;
log_len = strlen(log);
len_left = KUNIT_LOG_SIZE - log_len - 1;
if (len_left <= 0)
return;
/* Evaluate length of line to add to log */
va_start(args, fmt);
len = vsnprintf(NULL, 0, fmt, args) + 1;
string_stream_vadd(log, fmt, args);
va_end(args);
/* Print formatted line to the log */
va_start(args, fmt);
vsnprintf(log + log_len, min(len, len_left), fmt, args);
va_end(args);
/* Add newline to end of log if not already present. */
kunit_log_newline(log);
}
EXPORT_SYMBOL_GPL(kunit_log_append);
......@@ -296,7 +262,7 @@ static void kunit_print_string_stream(struct kunit *test,
kunit_err(test, "\n");
} else {
kunit_err(test, "%s", buf);
kunit_kfree(test, buf);
kfree(buf);
}
}
......@@ -308,7 +274,7 @@ static void kunit_fail(struct kunit *test, const struct kunit_loc *loc,
kunit_set_failure(test);
stream = alloc_string_stream(test, GFP_KERNEL);
stream = kunit_alloc_string_stream(test, GFP_KERNEL);
if (IS_ERR(stream)) {
WARN(true,
"Could not allocate stream to print failed assertion in %s:%d\n",
......@@ -322,7 +288,7 @@ static void kunit_fail(struct kunit *test, const struct kunit_loc *loc,
kunit_print_string_stream(test, stream);
string_stream_destroy(stream);
kunit_free_string_stream(test, stream);
}
void __noreturn __kunit_abort(struct kunit *test)
......@@ -359,14 +325,14 @@ void __kunit_do_failed_assertion(struct kunit *test,
}
EXPORT_SYMBOL_GPL(__kunit_do_failed_assertion);
void kunit_init_test(struct kunit *test, const char *name, char *log)
void kunit_init_test(struct kunit *test, const char *name, struct string_stream *log)
{
spin_lock_init(&test->lock);
INIT_LIST_HEAD(&test->resources);
test->name = name;
test->log = log;
if (test->log)
test->log[0] = '\0';
string_stream_clear(log);
test->status = KUNIT_SUCCESS;
test->status_comment[0] = '\0';
}
......@@ -648,12 +614,14 @@ int kunit_run_tests(struct kunit_suite *suite)
param_desc,
test.status_comment);
kunit_update_stats(&param_stats, test.status);
/* Get next param. */
param_desc[0] = '\0';
test.param_value = test_case->generate_params(test.param_value, param_desc);
test.param_index++;
kunit_update_stats(&param_stats, test.status);
test.status = KUNIT_SUCCESS;
test.status_comment[0] = '\0';
}
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment