xref: /kernel/linux/linux-6.6/lib/kunit/assert.c (revision 62306a36)
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