| // SPDX-License-Identifier: GPL-2.0 |
| /* |
| * C++ stream style string formatter and printer used in KUnit for outputting |
| * KUnit messages. |
| * |
| * Copyright (C) 2019, Google LLC. |
| * Author: Brendan Higgins <brendanhiggins@google.com> |
| */ |
| |
| #include <kunit/test.h> |
| #include <kunit/kunit-stream.h> |
| #include <kunit/string-stream.h> |
| |
| void kunit_stream_add(struct kunit_stream *kstream, const char *fmt, ...) |
| { |
| va_list args; |
| struct string_stream *stream = kstream->internal_stream; |
| |
| va_start(args, fmt); |
| |
| if (string_stream_vadd(stream, fmt, args) < 0) |
| kunit_err(kstream->test, |
| "Failed to allocate fragment: %s\n", |
| fmt); |
| |
| va_end(args); |
| } |
| |
| void kunit_stream_append(struct kunit_stream *kstream, |
| struct kunit_stream *other) |
| { |
| struct string_stream *other_stream = other->internal_stream; |
| const char *other_content; |
| |
| other_content = string_stream_get_string(other_stream); |
| |
| if (!other_content) { |
| kunit_err(kstream->test, |
| "Failed to get string from second argument for appending\n"); |
| return; |
| } |
| |
| kunit_stream_add(kstream, other_content); |
| } |
| |
| void kunit_stream_clear(struct kunit_stream *kstream) |
| { |
| string_stream_clear(kstream->internal_stream); |
| } |
| |
| void kunit_stream_commit(struct kunit_stream *kstream) |
| { |
| struct string_stream *stream = kstream->internal_stream; |
| struct string_stream_fragment *fragment; |
| struct kunit *test = kstream->test; |
| char *buf; |
| |
| buf = string_stream_get_string(stream); |
| if (!buf) { |
| kunit_err(test, |
| "Could not allocate buffer, dumping stream:\n"); |
| list_for_each_entry(fragment, &stream->fragments, node) { |
| kunit_err(test, fragment->fragment); |
| } |
| kunit_err(test, "\n"); |
| goto cleanup; |
| } |
| |
| kunit_printk(kstream->level, test, buf); |
| kfree(buf); |
| |
| cleanup: |
| kunit_stream_clear(kstream); |
| } |
| |
| static int kunit_stream_init(struct kunit_resource *res, void *context) |
| { |
| struct kunit *test = context; |
| struct kunit_stream *stream; |
| |
| stream = kzalloc(sizeof(*stream), GFP_KERNEL); |
| if (!stream) |
| return -ENOMEM; |
| |
| res->allocation = stream; |
| stream->test = test; |
| stream->internal_stream = alloc_string_stream(test); |
| |
| if (!stream->internal_stream) |
| return -ENOMEM; |
| |
| return 0; |
| } |
| |
| static void kunit_stream_free(struct kunit_resource *res) |
| { |
| struct kunit_stream *stream = res->allocation; |
| |
| if (!string_stream_is_empty(stream->internal_stream)) { |
| kunit_err(stream->test, |
| "End of test case reached with uncommitted stream entries\n"); |
| kunit_stream_commit(stream); |
| } |
| } |
| |
| struct kunit_stream *alloc_kunit_stream(struct kunit *test, const char *level) |
| { |
| struct kunit_stream *kstream; |
| struct kunit_resource *res; |
| |
| res = kunit_alloc_resource(test, |
| kunit_stream_init, |
| kunit_stream_free, |
| test); |
| |
| if (!res) |
| return NULL; |
| |
| kstream = res->allocation; |
| kstream->level = level; |
| |
| return kstream; |
| } |