// SPDX-License-Identifier: GPL-2.0 /* * Assertion and expectation serialization API. * * Copyright (C) 2019, Google LLC. * Author: Brendan Higgins */ #include #include #include "string-stream.h" void kunit_assert_prologue(const struct kunit_loc *loc, enum kunit_assert_type type, struct string_stream *stream) { const char *expect_or_assert = NULL; switch (type) { case KUNIT_EXPECTATION: expect_or_assert = "EXPECTATION"; break; case KUNIT_ASSERTION: expect_or_assert = "ASSERTION"; break; } string_stream_add(stream, "%s FAILED at %s:%d\n", expect_or_assert, loc->file, loc->line); } EXPORT_SYMBOL_GPL(kunit_assert_prologue); static void kunit_assert_print_msg(const struct va_format *message, struct string_stream *stream) { if (message->fmt) string_stream_add(stream, "\n%pV", message); } void kunit_fail_assert_format(const struct kunit_assert *assert, const struct va_format *message, struct string_stream *stream) { string_stream_add(stream, "%pV", message); } EXPORT_SYMBOL_GPL(kunit_fail_assert_format); void kunit_unary_assert_format(const struct kunit_assert *assert, const struct va_format *message, struct string_stream *stream) { struct kunit_unary_assert *unary_assert; unary_assert = container_of(assert, struct kunit_unary_assert, assert); if (unary_assert->expected_true) string_stream_add(stream, KUNIT_SUBTEST_INDENT "Expected %s to be true, but is false\n", unary_assert->condition); else string_stream_add(stream, KUNIT_SUBTEST_INDENT "Expected %s to be false, but is true\n", unary_assert->condition); kunit_assert_print_msg(message, stream); } EXPORT_SYMBOL_GPL(kunit_unary_assert_format); void kunit_ptr_not_err_assert_format(const struct kunit_assert *assert, const struct va_format *message, struct string_stream *stream) { struct kunit_ptr_not_err_assert *ptr_assert; ptr_assert = container_of(assert, struct kunit_ptr_not_err_assert, assert); if (!ptr_assert->value) { string_stream_add(stream, KUNIT_SUBTEST_INDENT "Expected %s is not null, but is\n", ptr_assert->text); } else if (IS_ERR(ptr_assert->value)) { string_stream_add(stream, KUNIT_SUBTEST_INDENT "Expected %s is not error, but is: %ld\n", ptr_assert->text, PTR_ERR(ptr_assert->value)); } kunit_assert_print_msg(message, stream); } 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(const char *text, long long value) { char *buffer; int len; bool ret; len = snprintf(NULL, 0, "%lld", value); if (strlen(text) != len) return false; buffer = kmalloc(len+1, GFP_KERNEL); if (!buffer) return false; snprintf(buffer, len+1, "%lld", value); ret = strncmp(buffer, text, len) == 0; kfree(buffer); return ret; } void kunit_binary_assert_format(const struct kunit_assert *assert, const struct va_format *message, struct string_stream *stream) { struct kunit_binary_assert *binary_assert; binary_assert = container_of(assert, struct kunit_binary_assert, assert); string_stream_add(stream, KUNIT_SUBTEST_INDENT "Expected %s %s %s, but\n", binary_assert->text->left_text, binary_assert->text->operation, binary_assert->text->right_text); 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(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, binary_assert->right_value); kunit_assert_print_msg(message, stream); } EXPORT_SYMBOL_GPL(kunit_binary_assert_format); void kunit_binary_ptr_assert_format(const struct kunit_assert *assert, const struct va_format *message, struct string_stream *stream) { struct kunit_binary_ptr_assert *binary_assert; binary_assert = container_of(assert, struct kunit_binary_ptr_assert, assert); string_stream_add(stream, KUNIT_SUBTEST_INDENT "Expected %s %s %s, but\n", binary_assert->text->left_text, binary_assert->text->operation, binary_assert->text->right_text); string_stream_add(stream, KUNIT_SUBSUBTEST_INDENT "%s == %px\n", binary_assert->text->left_text, binary_assert->left_value); string_stream_add(stream, KUNIT_SUBSUBTEST_INDENT "%s == %px", binary_assert->text->right_text, binary_assert->right_value); kunit_assert_print_msg(message, stream); } EXPORT_SYMBOL_GPL(kunit_binary_ptr_assert_format); /* Checks if KUNIT_EXPECT_STREQ() args were string literals. * Note: `text` will have ""s where as `value` will not. */ static bool is_str_literal(const char *text, const char *value) { int len; len = strlen(text); if (len < 2) return false; if (text[0] != '\"' || text[len - 1] != '\"') return false; return strncmp(text + 1, value, len - 2) == 0; } void kunit_binary_str_assert_format(const struct kunit_assert *assert, const struct va_format *message, struct string_stream *stream) { struct kunit_binary_str_assert *binary_assert; binary_assert = container_of(assert, struct kunit_binary_str_assert, assert); string_stream_add(stream, KUNIT_SUBTEST_INDENT "Expected %s %s %s, but\n", binary_assert->text->left_text, binary_assert->text->operation, binary_assert->text->right_text); if (!is_str_literal(binary_assert->text->left_text, binary_assert->left_value)) string_stream_add(stream, KUNIT_SUBSUBTEST_INDENT "%s == \"%s\"\n", binary_assert->text->left_text, binary_assert->left_value); if (!is_str_literal(binary_assert->text->right_text, binary_assert->right_value)) string_stream_add(stream, KUNIT_SUBSUBTEST_INDENT "%s == \"%s\"", binary_assert->text->right_text, binary_assert->right_value); kunit_assert_print_msg(message, stream); } EXPORT_SYMBOL_GPL(kunit_binary_str_assert_format); /* Adds a hexdump of a buffer to a string_stream comparing it with * a second buffer. The different bytes are marked with <>. */ static void kunit_assert_hexdump(struct string_stream *stream, const void *buf, const void *compared_buf, const size_t len) { size_t i; const u8 *buf1 = buf; const u8 *buf2 = compared_buf; string_stream_add(stream, KUNIT_SUBSUBTEST_INDENT); for (i = 0; i < len; ++i) { if (!(i % 16) && i) string_stream_add(stream, "\n" KUNIT_SUBSUBTEST_INDENT); if (buf1[i] != buf2[i]) string_stream_add(stream, "<%02x>", buf1[i]); else string_stream_add(stream, " %02x ", buf1[i]); } } void kunit_mem_assert_format(const struct kunit_assert *assert, const struct va_format *message, struct string_stream *stream) { struct kunit_mem_assert *mem_assert; mem_assert = container_of(assert, struct kunit_mem_assert, assert); if (!mem_assert->left_value) { string_stream_add(stream, KUNIT_SUBTEST_INDENT "Expected %s is not null, but is\n", mem_assert->text->left_text); } else if (!mem_assert->right_value) { string_stream_add(stream, KUNIT_SUBTEST_INDENT "Expected %s is not null, but is\n", mem_assert->text->right_text); } else { string_stream_add(stream, KUNIT_SUBTEST_INDENT "Expected %s %s %s, but\n", mem_assert->text->left_text, mem_assert->text->operation, mem_assert->text->right_text); string_stream_add(stream, KUNIT_SUBSUBTEST_INDENT "%s ==\n", mem_assert->text->left_text); kunit_assert_hexdump(stream, mem_assert->left_value, mem_assert->right_value, mem_assert->size); string_stream_add(stream, "\n"); string_stream_add(stream, KUNIT_SUBSUBTEST_INDENT "%s ==\n", mem_assert->text->right_text); kunit_assert_hexdump(stream, mem_assert->right_value, mem_assert->left_value, mem_assert->size); kunit_assert_print_msg(message, stream); } } EXPORT_SYMBOL_GPL(kunit_mem_assert_format);