| // 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)) |
| 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) |
| { |
| int ret; |
| |
| ret = string_stream_append(kstream->internal_stream, |
| other->internal_stream); |
| |
| if (ret) |
| kunit_err(kstream->test, |
| "Failed to append other stream: %d\n", ret); |
| } |
| |
| 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"); |
| } else { |
| kunit_printk(kstream->level, test, buf); |
| } |
| |
| kunit_stream_clear(kstream); |
| } |
| |
| struct kunit_stream_alloc_context { |
| struct kunit *test; |
| const char *level; |
| gfp_t gfp; |
| }; |
| |
| static int kunit_stream_init(struct kunit_resource *res, void *context) |
| { |
| struct kunit_stream_alloc_context *ctx = context; |
| struct kunit_stream *stream; |
| |
| stream = kunit_kzalloc(ctx->test, sizeof(*stream), ctx->gfp); |
| if (!stream) |
| return -ENOMEM; |
| |
| res->allocation = stream; |
| stream->test = ctx->test; |
| stream->level = ctx->level; |
| stream->internal_stream = alloc_string_stream(ctx->test, ctx->gfp); |
| |
| if (!stream->internal_stream) |
| return -ENOMEM; |
| |
| return 0; |
| } |
| |
| static void kunit_stream_free(struct kunit_resource *res) |
| { |
| /* Do nothing because cleanup is handled by KUnit managed resources */ |
| } |
| |
| struct kunit_stream *alloc_kunit_stream(struct kunit *test, |
| const char *level, |
| gfp_t gfp) |
| { |
| struct kunit_stream_alloc_context ctx = { |
| .test = test, |
| .level = level, |
| .gfp = gfp |
| }; |
| |
| return kunit_alloc_resource(test, |
| kunit_stream_init, |
| kunit_stream_free, |
| gfp, |
| &ctx); |
| } |