162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Assertion and expectation serialization API. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2019, Google LLC. 662306a36Sopenharmony_ci * Author: Brendan Higgins <brendanhiggins@google.com> 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci#include <kunit/assert.h> 962306a36Sopenharmony_ci#include <kunit/test.h> 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include "string-stream.h" 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_civoid kunit_assert_prologue(const struct kunit_loc *loc, 1462306a36Sopenharmony_ci enum kunit_assert_type type, 1562306a36Sopenharmony_ci struct string_stream *stream) 1662306a36Sopenharmony_ci{ 1762306a36Sopenharmony_ci const char *expect_or_assert = NULL; 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci switch (type) { 2062306a36Sopenharmony_ci case KUNIT_EXPECTATION: 2162306a36Sopenharmony_ci expect_or_assert = "EXPECTATION"; 2262306a36Sopenharmony_ci break; 2362306a36Sopenharmony_ci case KUNIT_ASSERTION: 2462306a36Sopenharmony_ci expect_or_assert = "ASSERTION"; 2562306a36Sopenharmony_ci break; 2662306a36Sopenharmony_ci } 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci string_stream_add(stream, "%s FAILED at %s:%d\n", 2962306a36Sopenharmony_ci expect_or_assert, loc->file, loc->line); 3062306a36Sopenharmony_ci} 3162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(kunit_assert_prologue); 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_cistatic void kunit_assert_print_msg(const struct va_format *message, 3462306a36Sopenharmony_ci struct string_stream *stream) 3562306a36Sopenharmony_ci{ 3662306a36Sopenharmony_ci if (message->fmt) 3762306a36Sopenharmony_ci string_stream_add(stream, "\n%pV", message); 3862306a36Sopenharmony_ci} 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_civoid kunit_fail_assert_format(const struct kunit_assert *assert, 4162306a36Sopenharmony_ci const struct va_format *message, 4262306a36Sopenharmony_ci struct string_stream *stream) 4362306a36Sopenharmony_ci{ 4462306a36Sopenharmony_ci string_stream_add(stream, "%pV", message); 4562306a36Sopenharmony_ci} 4662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(kunit_fail_assert_format); 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_civoid kunit_unary_assert_format(const struct kunit_assert *assert, 4962306a36Sopenharmony_ci const struct va_format *message, 5062306a36Sopenharmony_ci struct string_stream *stream) 5162306a36Sopenharmony_ci{ 5262306a36Sopenharmony_ci struct kunit_unary_assert *unary_assert; 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci unary_assert = container_of(assert, struct kunit_unary_assert, assert); 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci if (unary_assert->expected_true) 5762306a36Sopenharmony_ci string_stream_add(stream, 5862306a36Sopenharmony_ci KUNIT_SUBTEST_INDENT "Expected %s to be true, but is false\n", 5962306a36Sopenharmony_ci unary_assert->condition); 6062306a36Sopenharmony_ci else 6162306a36Sopenharmony_ci string_stream_add(stream, 6262306a36Sopenharmony_ci KUNIT_SUBTEST_INDENT "Expected %s to be false, but is true\n", 6362306a36Sopenharmony_ci unary_assert->condition); 6462306a36Sopenharmony_ci kunit_assert_print_msg(message, stream); 6562306a36Sopenharmony_ci} 6662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(kunit_unary_assert_format); 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_civoid kunit_ptr_not_err_assert_format(const struct kunit_assert *assert, 6962306a36Sopenharmony_ci const struct va_format *message, 7062306a36Sopenharmony_ci struct string_stream *stream) 7162306a36Sopenharmony_ci{ 7262306a36Sopenharmony_ci struct kunit_ptr_not_err_assert *ptr_assert; 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci ptr_assert = container_of(assert, struct kunit_ptr_not_err_assert, 7562306a36Sopenharmony_ci assert); 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci if (!ptr_assert->value) { 7862306a36Sopenharmony_ci string_stream_add(stream, 7962306a36Sopenharmony_ci KUNIT_SUBTEST_INDENT "Expected %s is not null, but is\n", 8062306a36Sopenharmony_ci ptr_assert->text); 8162306a36Sopenharmony_ci } else if (IS_ERR(ptr_assert->value)) { 8262306a36Sopenharmony_ci string_stream_add(stream, 8362306a36Sopenharmony_ci KUNIT_SUBTEST_INDENT "Expected %s is not error, but is: %ld\n", 8462306a36Sopenharmony_ci ptr_assert->text, 8562306a36Sopenharmony_ci PTR_ERR(ptr_assert->value)); 8662306a36Sopenharmony_ci } 8762306a36Sopenharmony_ci kunit_assert_print_msg(message, stream); 8862306a36Sopenharmony_ci} 8962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(kunit_ptr_not_err_assert_format); 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci/* Checks if `text` is a literal representing `value`, e.g. "5" and 5 */ 9262306a36Sopenharmony_cistatic bool is_literal(struct kunit *test, const char *text, long long value, 9362306a36Sopenharmony_ci gfp_t gfp) 9462306a36Sopenharmony_ci{ 9562306a36Sopenharmony_ci char *buffer; 9662306a36Sopenharmony_ci int len; 9762306a36Sopenharmony_ci bool ret; 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci len = snprintf(NULL, 0, "%lld", value); 10062306a36Sopenharmony_ci if (strlen(text) != len) 10162306a36Sopenharmony_ci return false; 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci buffer = kunit_kmalloc(test, len+1, gfp); 10462306a36Sopenharmony_ci if (!buffer) 10562306a36Sopenharmony_ci return false; 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci snprintf(buffer, len+1, "%lld", value); 10862306a36Sopenharmony_ci ret = strncmp(buffer, text, len) == 0; 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci kunit_kfree(test, buffer); 11162306a36Sopenharmony_ci return ret; 11262306a36Sopenharmony_ci} 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_civoid kunit_binary_assert_format(const struct kunit_assert *assert, 11562306a36Sopenharmony_ci const struct va_format *message, 11662306a36Sopenharmony_ci struct string_stream *stream) 11762306a36Sopenharmony_ci{ 11862306a36Sopenharmony_ci struct kunit_binary_assert *binary_assert; 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci binary_assert = container_of(assert, struct kunit_binary_assert, 12162306a36Sopenharmony_ci assert); 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci string_stream_add(stream, 12462306a36Sopenharmony_ci KUNIT_SUBTEST_INDENT "Expected %s %s %s, but\n", 12562306a36Sopenharmony_ci binary_assert->text->left_text, 12662306a36Sopenharmony_ci binary_assert->text->operation, 12762306a36Sopenharmony_ci binary_assert->text->right_text); 12862306a36Sopenharmony_ci if (!is_literal(stream->test, binary_assert->text->left_text, 12962306a36Sopenharmony_ci binary_assert->left_value, stream->gfp)) 13062306a36Sopenharmony_ci string_stream_add(stream, KUNIT_SUBSUBTEST_INDENT "%s == %lld (0x%llx)\n", 13162306a36Sopenharmony_ci binary_assert->text->left_text, 13262306a36Sopenharmony_ci binary_assert->left_value, 13362306a36Sopenharmony_ci binary_assert->left_value); 13462306a36Sopenharmony_ci if (!is_literal(stream->test, binary_assert->text->right_text, 13562306a36Sopenharmony_ci binary_assert->right_value, stream->gfp)) 13662306a36Sopenharmony_ci string_stream_add(stream, KUNIT_SUBSUBTEST_INDENT "%s == %lld (0x%llx)", 13762306a36Sopenharmony_ci binary_assert->text->right_text, 13862306a36Sopenharmony_ci binary_assert->right_value, 13962306a36Sopenharmony_ci binary_assert->right_value); 14062306a36Sopenharmony_ci kunit_assert_print_msg(message, stream); 14162306a36Sopenharmony_ci} 14262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(kunit_binary_assert_format); 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_civoid kunit_binary_ptr_assert_format(const struct kunit_assert *assert, 14562306a36Sopenharmony_ci const struct va_format *message, 14662306a36Sopenharmony_ci struct string_stream *stream) 14762306a36Sopenharmony_ci{ 14862306a36Sopenharmony_ci struct kunit_binary_ptr_assert *binary_assert; 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci binary_assert = container_of(assert, struct kunit_binary_ptr_assert, 15162306a36Sopenharmony_ci assert); 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci string_stream_add(stream, 15462306a36Sopenharmony_ci KUNIT_SUBTEST_INDENT "Expected %s %s %s, but\n", 15562306a36Sopenharmony_ci binary_assert->text->left_text, 15662306a36Sopenharmony_ci binary_assert->text->operation, 15762306a36Sopenharmony_ci binary_assert->text->right_text); 15862306a36Sopenharmony_ci string_stream_add(stream, KUNIT_SUBSUBTEST_INDENT "%s == %px\n", 15962306a36Sopenharmony_ci binary_assert->text->left_text, 16062306a36Sopenharmony_ci binary_assert->left_value); 16162306a36Sopenharmony_ci string_stream_add(stream, KUNIT_SUBSUBTEST_INDENT "%s == %px", 16262306a36Sopenharmony_ci binary_assert->text->right_text, 16362306a36Sopenharmony_ci binary_assert->right_value); 16462306a36Sopenharmony_ci kunit_assert_print_msg(message, stream); 16562306a36Sopenharmony_ci} 16662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(kunit_binary_ptr_assert_format); 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci/* Checks if KUNIT_EXPECT_STREQ() args were string literals. 16962306a36Sopenharmony_ci * Note: `text` will have ""s where as `value` will not. 17062306a36Sopenharmony_ci */ 17162306a36Sopenharmony_cistatic bool is_str_literal(const char *text, const char *value) 17262306a36Sopenharmony_ci{ 17362306a36Sopenharmony_ci int len; 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci len = strlen(text); 17662306a36Sopenharmony_ci if (len < 2) 17762306a36Sopenharmony_ci return false; 17862306a36Sopenharmony_ci if (text[0] != '\"' || text[len - 1] != '\"') 17962306a36Sopenharmony_ci return false; 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci return strncmp(text + 1, value, len - 2) == 0; 18262306a36Sopenharmony_ci} 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_civoid kunit_binary_str_assert_format(const struct kunit_assert *assert, 18562306a36Sopenharmony_ci const struct va_format *message, 18662306a36Sopenharmony_ci struct string_stream *stream) 18762306a36Sopenharmony_ci{ 18862306a36Sopenharmony_ci struct kunit_binary_str_assert *binary_assert; 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci binary_assert = container_of(assert, struct kunit_binary_str_assert, 19162306a36Sopenharmony_ci assert); 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci string_stream_add(stream, 19462306a36Sopenharmony_ci KUNIT_SUBTEST_INDENT "Expected %s %s %s, but\n", 19562306a36Sopenharmony_ci binary_assert->text->left_text, 19662306a36Sopenharmony_ci binary_assert->text->operation, 19762306a36Sopenharmony_ci binary_assert->text->right_text); 19862306a36Sopenharmony_ci if (!is_str_literal(binary_assert->text->left_text, binary_assert->left_value)) 19962306a36Sopenharmony_ci string_stream_add(stream, KUNIT_SUBSUBTEST_INDENT "%s == \"%s\"\n", 20062306a36Sopenharmony_ci binary_assert->text->left_text, 20162306a36Sopenharmony_ci binary_assert->left_value); 20262306a36Sopenharmony_ci if (!is_str_literal(binary_assert->text->right_text, binary_assert->right_value)) 20362306a36Sopenharmony_ci string_stream_add(stream, KUNIT_SUBSUBTEST_INDENT "%s == \"%s\"", 20462306a36Sopenharmony_ci binary_assert->text->right_text, 20562306a36Sopenharmony_ci binary_assert->right_value); 20662306a36Sopenharmony_ci kunit_assert_print_msg(message, stream); 20762306a36Sopenharmony_ci} 20862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(kunit_binary_str_assert_format); 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci/* Adds a hexdump of a buffer to a string_stream comparing it with 21162306a36Sopenharmony_ci * a second buffer. The different bytes are marked with <>. 21262306a36Sopenharmony_ci */ 21362306a36Sopenharmony_cistatic void kunit_assert_hexdump(struct string_stream *stream, 21462306a36Sopenharmony_ci const void *buf, 21562306a36Sopenharmony_ci const void *compared_buf, 21662306a36Sopenharmony_ci const size_t len) 21762306a36Sopenharmony_ci{ 21862306a36Sopenharmony_ci size_t i; 21962306a36Sopenharmony_ci const u8 *buf1 = buf; 22062306a36Sopenharmony_ci const u8 *buf2 = compared_buf; 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci string_stream_add(stream, KUNIT_SUBSUBTEST_INDENT); 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci for (i = 0; i < len; ++i) { 22562306a36Sopenharmony_ci if (!(i % 16) && i) 22662306a36Sopenharmony_ci string_stream_add(stream, "\n" KUNIT_SUBSUBTEST_INDENT); 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci if (buf1[i] != buf2[i]) 22962306a36Sopenharmony_ci string_stream_add(stream, "<%02x>", buf1[i]); 23062306a36Sopenharmony_ci else 23162306a36Sopenharmony_ci string_stream_add(stream, " %02x ", buf1[i]); 23262306a36Sopenharmony_ci } 23362306a36Sopenharmony_ci} 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_civoid kunit_mem_assert_format(const struct kunit_assert *assert, 23662306a36Sopenharmony_ci const struct va_format *message, 23762306a36Sopenharmony_ci struct string_stream *stream) 23862306a36Sopenharmony_ci{ 23962306a36Sopenharmony_ci struct kunit_mem_assert *mem_assert; 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci mem_assert = container_of(assert, struct kunit_mem_assert, 24262306a36Sopenharmony_ci assert); 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci if (!mem_assert->left_value) { 24562306a36Sopenharmony_ci string_stream_add(stream, 24662306a36Sopenharmony_ci KUNIT_SUBTEST_INDENT "Expected %s is not null, but is\n", 24762306a36Sopenharmony_ci mem_assert->text->left_text); 24862306a36Sopenharmony_ci } else if (!mem_assert->right_value) { 24962306a36Sopenharmony_ci string_stream_add(stream, 25062306a36Sopenharmony_ci KUNIT_SUBTEST_INDENT "Expected %s is not null, but is\n", 25162306a36Sopenharmony_ci mem_assert->text->right_text); 25262306a36Sopenharmony_ci } else { 25362306a36Sopenharmony_ci string_stream_add(stream, 25462306a36Sopenharmony_ci KUNIT_SUBTEST_INDENT "Expected %s %s %s, but\n", 25562306a36Sopenharmony_ci mem_assert->text->left_text, 25662306a36Sopenharmony_ci mem_assert->text->operation, 25762306a36Sopenharmony_ci mem_assert->text->right_text); 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci string_stream_add(stream, KUNIT_SUBSUBTEST_INDENT "%s ==\n", 26062306a36Sopenharmony_ci mem_assert->text->left_text); 26162306a36Sopenharmony_ci kunit_assert_hexdump(stream, mem_assert->left_value, 26262306a36Sopenharmony_ci mem_assert->right_value, mem_assert->size); 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci string_stream_add(stream, "\n"); 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci string_stream_add(stream, KUNIT_SUBSUBTEST_INDENT "%s ==\n", 26762306a36Sopenharmony_ci mem_assert->text->right_text); 26862306a36Sopenharmony_ci kunit_assert_hexdump(stream, mem_assert->right_value, 26962306a36Sopenharmony_ci mem_assert->left_value, mem_assert->size); 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci kunit_assert_print_msg(message, stream); 27262306a36Sopenharmony_ci } 27362306a36Sopenharmony_ci} 27462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(kunit_mem_assert_format); 275