All of lore.kernel.org
 help / color / mirror / Atom feed
From: Jarkko Sakkinen <jarkko@kernel.org>
To: keyrings@vger.kernel.org,
	Brendan Higgins <brendan.higgins@linux.dev>,
	David Gow <david@davidgow.net>
Cc: Jarkko Sakkinen <jarkko@kernel.org>,
	Andrew Morton <akpm@linux-foundation.org>,
	Rae Moar <raemoar63@gmail.com>,
	Ryota Sakamoto <sakamo.ryota@gmail.com>,
	Kuan-Wei Chiu <visitorckw@gmail.com>,
	Andy Shevchenko <andriy.shevchenko@linux.intel.com>,
	Pasha Tatashin <pasha.tatashin@soleen.com>,
	Kir Chou <note351@hotmail.com>, Petr Mladek <pmladek@suse.com>,
	Dmitry Antipov <dmantipov@yandex.ru>,
	Guan-Chun Wu <409411716@gms.tku.edu.tw>,
	linux-kernel@vger.kernel.org (open list),
	linux-kselftest@vger.kernel.org (open list:KERNEL UNIT TESTING
	FRAMEWORK (KUnit)),
	kunit-dev@googlegroups.com (open list:KERNEL UNIT TESTING
	FRAMEWORK (KUnit))
Subject: [PATCH] lib/tests: kunit for associative array
Date: Wed, 14 Oct 2026 19:01:38 +0300	[thread overview]
Message-ID: <20261014160144.1835860-1-jarkko@kernel.org> (raw)

This is a kunit test for lib/assoc_array.c, which maintains a shadow model
across assoc_array operations, and checks its integrity after every
operation.

I wrote a draft version so that I could properly test 'assoc-array-fixes'
tag at Linus' tree, and spent today rewriting a new more polished version
with as good description as I could possibly could on how the seeded test
keys were cherry-picked. Along the way I also tweaked the numbers to be
a bit less messier set than in my original version.

The transcripts that follow were executed with this command-line:

    ./tools/testing/kunit/kunit.py run --raw_output assoc_array

With 'assoc-array-fixes' commits and its subsequent tag iterations all
eight tests pass, and without them all of them fail.

Signed-off-by: Jarkko Sakkinen <jarkko@kernel.org>
---
 lib/Kconfig.debug             |  15 +
 lib/tests/Makefile            |   1 +
 lib/tests/assoc_array_kunit.c | 570 ++++++++++++++++++++++++++++++++++
 3 files changed, 586 insertions(+)
 create mode 100644 lib/tests/assoc_array_kunit.c

diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index 6b24a2c89b84..3e8d3852f53c 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -2857,6 +2857,21 @@ config HASHTABLE_KUNIT_TEST

 	  If unsure, say N.

+config ASSOC_ARRAY_KUNIT_TEST
+	tristate "KUnit test for assoc_array" if !KUNIT_ALL_TESTS
+	depends on KUNIT
+	default KUNIT_ALL_TESTS
+	select ASSOCIATIVE_ARRAY
+	help
+	  This builds the assoc_array KUnit test suite.
+	  It tests the basic functionality of the API defined in
+	  include/linux/assoc_array.h.
+
+	  For more information on KUnit and unit tests in general please refer
+	  to the KUnit documentation in Documentation/dev-tools/kunit/.
+
+	  If unsure, say N.
+
 config LINEAR_RANGES_TEST
 	tristate "KUnit test for linear_ranges"
 	depends on KUNIT
diff --git a/lib/tests/Makefile b/lib/tests/Makefile
index 3cac3b63a752..107e16b4ebc1 100644
--- a/lib/tests/Makefile
+++ b/lib/tests/Makefile
@@ -4,6 +4,7 @@

 # KUnit tests
 CFLAGS_bitfield_kunit.o := $(DISABLE_STRUCTLEAK_PLUGIN)
+obj-$(CONFIG_ASSOC_ARRAY_KUNIT_TEST) += assoc_array_kunit.o
 obj-$(CONFIG_BASE64_KUNIT) += base64_kunit.o
 obj-$(CONFIG_BITOPS_KUNIT) += bitops_kunit.o
 obj-$(CONFIG_BITFIELD_KUNIT) += bitfield_kunit.o
diff --git a/lib/tests/assoc_array_kunit.c b/lib/tests/assoc_array_kunit.c
new file mode 100644
index 000000000000..aeaab366daac
--- /dev/null
+++ b/lib/tests/assoc_array_kunit.c
@@ -0,0 +1,570 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2026 Jarkko Sakinen
+ *
+ * This is a model based test and has a model invariant that is called after each
+ * and every operation accessing an associative array.
+ */
+
+#include <kunit/test.h>
+#include <linux/assoc_array.h>
+#include <linux/bitmap.h>
+#include <linux/rcupdate.h>
+#include <linux/refcount.h>
+#include <linux/slab.h>
+
+#define ASSOC_ARRAY_TEST_NR_KEYS	64
+#define ASSOC_ARRAY_TEST_STOP_AFTER	5
+#define ASSOC_ARRAY_TEST_STOP_STATUS	123
+
+/*
+ * As a quick remainder, these are the basic building blocks of an associative
+ * array:
+ *
+ * - struct assoc_array_node: a tree node representing a nibble of the search
+ *   key.
+ * - struct assoc_array_shortcut: a tree node representing a sequence of nibbles
+ *   shared by multiple search keys with no divergence among them.
+ *
+ * The keys in array will be created in order in tests, and is a constructed in
+ * a way that splits reach the level 8:
+ *
+ * - 0..16:  Share prefix 0x21 at levels 0 and 4.
+ * - 17:     Splits root shortcut at level 4.
+ * - 18..34: Share chunk 0.
+ * - 35:     Splits shortcut at chunk boundary.
+ * - 36..46: Share prefix 0xbeef at levels 0..12.
+ * - 47:     Splits shortcut at level 8.
+ * - 48..63: Distinct leaves at level 0.
+ *
+ * The numbers were picked partly based on trial and error, and partly trying to
+ * find smallest possible numbers reaching the level 8.
+ */
+static const unsigned long assoc_array_test_keys[ASSOC_ARRAY_TEST_NR_KEYS * 2] = {
+	0x0000000000000121UL, 0x0000000000000000UL,
+	0x0000000000000221UL, 0x0000000000000000UL,
+	0x0000000000000321UL, 0x0000000000000000UL,
+	0x0000000000000421UL, 0x0000000000000000UL,
+	0x0000000000000521UL, 0x0000000000000000UL,
+	0x0000000000000621UL, 0x0000000000000000UL,
+	0x0000000000000721UL, 0x0000000000000000UL,
+	0x0000000000000821UL, 0x0000000000000000UL,
+	0x0000000000000921UL, 0x0000000000000000UL,
+	0x0000000000000a21UL, 0x0000000000000000UL,
+	0x0000000000000b21UL, 0x0000000000000000UL,
+	0x0000000000000c21UL, 0x0000000000000000UL,
+	0x0000000000000d21UL, 0x0000000000000000UL,
+	0x0000000000000e21UL, 0x0000000000000000UL,
+	0x0000000000000f21UL, 0x0000000000000000UL,
+	0x0000000000001021UL, 0x0000000000000000UL,
+	0x0000000000001121UL, 0x0000000000000000UL,
+	0x0000000000000001UL, 0x0000000000000000UL,
+	0xdeadbeefcafebabeUL, 0x0000000000000010UL,
+	0xdeadbeefcafebabeUL, 0x0000000000000020UL,
+	0xdeadbeefcafebabeUL, 0x0000000000000030UL,
+	0xdeadbeefcafebabeUL, 0x0000000000000040UL,
+	0xdeadbeefcafebabeUL, 0x0000000000000050UL,
+	0xdeadbeefcafebabeUL, 0x0000000000000060UL,
+	0xdeadbeefcafebabeUL, 0x0000000000000070UL,
+	0xdeadbeefcafebabeUL, 0x0000000000000080UL,
+	0xdeadbeefcafebabeUL, 0x0000000000000090UL,
+	0xdeadbeefcafebabeUL, 0x00000000000000a0UL,
+	0xdeadbeefcafebabeUL, 0x00000000000000b0UL,
+	0xdeadbeefcafebabeUL, 0x00000000000000c0UL,
+	0xdeadbeefcafebabeUL, 0x00000000000000d0UL,
+	0xdeadbeefcafebabeUL, 0x00000000000000e0UL,
+	0xdeadbeefcafebabeUL, 0x00000000000000f0UL,
+	0xdeadbeefcafebabeUL, 0x0000000000000100UL,
+	0xdeadbeefcafebabeUL, 0x0000000000000110UL,
+	0xdeadbeefcafebabeUL, 0x0000000000000001UL,
+	0x000000000001beefUL, 0x0000000000000000UL,
+	0x000000000002beefUL, 0x0000000000000000UL,
+	0x000000000003beefUL, 0x0000000000000000UL,
+	0x000000000004beefUL, 0x0000000000000000UL,
+	0x000000000005beefUL, 0x0000000000000000UL,
+	0x000000000006beefUL, 0x0000000000000000UL,
+	0x000000000007beefUL, 0x0000000000000000UL,
+	0x000000000008beefUL, 0x0000000000000000UL,
+	0x000000000009beefUL, 0x0000000000000000UL,
+	0x00000000000abeefUL, 0x0000000000000000UL,
+	0x00000000000bbeefUL, 0x0000000000000000UL,
+	0x00000000000000efUL, 0x0000000000000000UL,
+	0x0000000000001000UL, 0x0000000000000000UL,
+	0x0000000000001001UL, 0x0000000000000000UL,
+	0x0000000000001002UL, 0x0000000000000000UL,
+	0x0000000000001003UL, 0x0000000000000000UL,
+	0x0000000000001004UL, 0x0000000000000000UL,
+	0x0000000000001005UL, 0x0000000000000000UL,
+	0x0000000000001006UL, 0x0000000000000000UL,
+	0x0000000000001007UL, 0x0000000000000000UL,
+	0x0000000000001008UL, 0x0000000000000000UL,
+	0x0000000000001009UL, 0x0000000000000000UL,
+	0x000000000000100aUL, 0x0000000000000000UL,
+	0x000000000000100bUL, 0x0000000000000000UL,
+	0x000000000000100cUL, 0x0000000000000000UL,
+	0x000000000000100dUL, 0x0000000000000000UL,
+	0x000000000000100eUL, 0x0000000000000000UL,
+	0x000000000000100fUL, 0x0000000000000000UL,
+};
+
+struct assoc_array_test_object {
+	unsigned long key[2];
+	unsigned long value;
+	refcount_t usage;
+};
+
+static unsigned long assoc_array_test_get_key_chunk(const void *index_key, int level)
+{
+	const unsigned long *key = index_key;
+	int chunk = level / ASSOC_ARRAY_KEY_CHUNK_SIZE;
+
+	return chunk < 2 ? key[chunk] : 0;
+}
+
+static unsigned long assoc_array_test_get_object_key_chunk(const void *object, int level)
+{
+	const struct assoc_array_test_object *obj = object;
+
+	return assoc_array_test_get_key_chunk(obj->key, level);
+}
+
+static bool assoc_array_test_compare_object(const void *object, const void *index_key)
+{
+	const struct assoc_array_test_object *obj = object;
+
+	return !memcmp(obj->key, index_key, sizeof(obj->key));
+}
+
+static int assoc_array_test_diff_objects(const void *object, const void *index_key)
+{
+	const struct assoc_array_test_object *obj = object;
+	const unsigned long *key = index_key;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(obj->key); i++) {
+		unsigned long diff = obj->key[i] ^ key[i];
+
+		if (diff)
+			return i * ASSOC_ARRAY_KEY_CHUNK_SIZE + __ffs(diff);
+	}
+
+	return -1;
+}
+
+static void assoc_array_test_free_object(void *object)
+{
+	struct assoc_array_test_object *obj = object;
+
+	if (refcount_dec_and_test(&obj->usage))
+		kfree(obj);
+}
+
+static const struct assoc_array_ops assoc_array_test_ops = {
+	.get_key_chunk = assoc_array_test_get_key_chunk,
+	.get_object_key_chunk = assoc_array_test_get_object_key_chunk,
+	.compare_object = assoc_array_test_compare_object,
+	.diff_objects = assoc_array_test_diff_objects,
+	.free_object = assoc_array_test_free_object,
+};
+
+struct assoc_array_test_model {
+	struct kunit *test;
+	struct assoc_array array;
+	unsigned long values[ASSOC_ARRAY_TEST_NR_KEYS];
+	bool present[ASSOC_ARRAY_TEST_NR_KEYS];
+	int nr_present;
+};
+
+struct assoc_array_test_iter {
+	const struct assoc_array_test_model *m;
+	DECLARE_BITMAP(visited, ASSOC_ARRAY_TEST_NR_KEYS);
+	int count;
+	int bad;
+};
+
+static void assoc_array_test_model_release(void *data)
+{
+	struct assoc_array_test_model *m = data;
+
+	assoc_array_destroy(&m->array, &assoc_array_test_ops);
+	rcu_barrier();
+}
+
+static int assoc_array_test_model_iterate(const void *object, void *data)
+{
+	const struct assoc_array_test_object *obj = object;
+	struct assoc_array_test_iter *it = data;
+	int i;
+
+	it->count++;
+	for (i = 0; i < ASSOC_ARRAY_TEST_NR_KEYS; i++) {
+		if (!assoc_array_test_compare_object(obj, &assoc_array_test_keys[i * 2]))
+			continue;
+		if (it->m->present[i] && obj->value == it->m->values[i] &&
+		    !__test_and_set_bit(i, it->visited))
+			return 0;
+		break;
+	}
+
+	it->bad++;
+	return 0;
+}
+
+static void assoc_array_test_invariant(struct assoc_array_test_model *m)
+{
+	struct assoc_array_test_iter it = { .m = m };
+	const struct assoc_array_test_object *obj;
+	int i;
+
+	KUNIT_EXPECT_EQ(m->test, m->array.nr_leaves_on_tree, m->nr_present);
+
+	for (i = 0; i < ASSOC_ARRAY_TEST_NR_KEYS; i++) {
+		obj = assoc_array_find(&m->array, &assoc_array_test_ops,
+				       &assoc_array_test_keys[i * 2]);
+		if (!m->present[i]) {
+			KUNIT_EXPECT_NULL(m->test, obj);
+			continue;
+		}
+
+		KUNIT_EXPECT_NOT_NULL(m->test, obj);
+		if (obj)
+			KUNIT_EXPECT_EQ(m->test, obj->value, m->values[i]);
+	}
+
+	KUNIT_EXPECT_EQ(m->test,
+			assoc_array_iterate(&m->array, assoc_array_test_model_iterate, &it),
+			0);
+	KUNIT_EXPECT_EQ(m->test, it.count, m->nr_present);
+	KUNIT_EXPECT_EQ(m->test, it.bad, 0);
+}
+
+static struct assoc_array_test_model *assoc_array_test_model_create(struct kunit *test)
+{
+	struct assoc_array_test_model *m;
+	int ret;
+
+	m = kunit_kzalloc(test, sizeof(*m), GFP_KERNEL);
+	KUNIT_ASSERT_NOT_NULL(test, m);
+	m->test = test;
+	assoc_array_init(&m->array);
+
+	ret = kunit_add_action_or_reset(test, assoc_array_test_model_release, m);
+	KUNIT_ASSERT_EQ(test, ret, 0);
+	assoc_array_test_invariant(m);
+
+	return m;
+}
+
+static void assoc_array_test_model_insert(struct assoc_array_test_model *m,
+					  int i, unsigned long value)
+{
+	struct assoc_array_edit *edit;
+	struct assoc_array_test_object *obj;
+
+	obj = kzalloc_obj(*obj, GFP_KERNEL);
+	KUNIT_ASSERT_NOT_NULL(m->test, obj);
+	memcpy(obj->key, &assoc_array_test_keys[i * 2], sizeof(obj->key));
+	obj->value = value;
+	refcount_set(&obj->usage, 1);
+
+	edit = assoc_array_insert(&m->array, &assoc_array_test_ops, obj->key, obj);
+	if (IS_ERR_OR_NULL(edit)) {
+		kfree(obj);
+		KUNIT_FAIL_AND_ABORT(m->test, "insert failed: %ld", PTR_ERR(edit));
+	}
+	assoc_array_apply_edit(edit);
+
+	if (!m->present[i]) {
+		m->present[i] = true;
+		m->nr_present++;
+	}
+	m->values[i] = value;
+
+	assoc_array_test_invariant(m);
+}
+
+static void assoc_array_test_model_delete(struct assoc_array_test_model *m, int i)
+{
+	struct assoc_array_edit *edit;
+
+	edit = assoc_array_delete(&m->array, &assoc_array_test_ops,
+				  &assoc_array_test_keys[i * 2]);
+	KUNIT_ASSERT_FALSE(m->test, IS_ERR(edit));
+
+	if (edit)
+		assoc_array_apply_edit(edit);
+	if (m->present[i]) {
+		m->present[i] = false;
+		m->nr_present--;
+	}
+
+	assoc_array_test_invariant(m);
+}
+
+static void assoc_array_test_model_clear(struct assoc_array_test_model *m)
+{
+	struct assoc_array_edit *edit;
+
+	edit = assoc_array_clear(&m->array, &assoc_array_test_ops);
+	KUNIT_ASSERT_FALSE(m->test, IS_ERR(edit));
+
+	if (edit)
+		assoc_array_apply_edit(edit);
+
+	memset(m->present, 0, sizeof(m->present));
+	m->nr_present = 0;
+
+	assoc_array_test_invariant(m);
+}
+
+static void assoc_array_test_model_destroy(struct assoc_array_test_model *m)
+{
+	assoc_array_destroy(&m->array, &assoc_array_test_ops);
+	assoc_array_init(&m->array);
+
+	memset(m->present, 0, sizeof(m->present));
+	m->nr_present = 0;
+
+	assoc_array_test_invariant(m);
+}
+
+static void assoc_array_test_model_fill(struct assoc_array_test_model *m)
+{
+	int i;
+
+	for (i = 0; i < ASSOC_ARRAY_TEST_NR_KEYS; i++)
+		assoc_array_test_model_insert(m, i, i);
+}
+
+struct assoc_array_test_gc_ctx {
+	bool (*keep)(const struct assoc_array_test_object *obj, void *data);
+	void *data;
+};
+
+static bool assoc_array_test_model_gc_filter(void *object, void *data)
+{
+	struct assoc_array_test_object *obj = object;
+	struct assoc_array_test_gc_ctx *ctx = data;
+
+	if (!ctx->keep(obj, ctx->data))
+		return false;
+	refcount_inc(&obj->usage);
+	return true;
+}
+
+static void assoc_array_test_model_gc(struct assoc_array_test_model *m,
+				      bool (*keep)(const struct assoc_array_test_object *obj,
+						   void *data),
+				      void *data)
+{
+	struct assoc_array_test_gc_ctx ctx = { .keep = keep, .data = data };
+	int i, ret;
+
+	ret = assoc_array_gc(&m->array, &assoc_array_test_ops,
+			     assoc_array_test_model_gc_filter, &ctx);
+	KUNIT_ASSERT_EQ(m->test, ret, 0);
+
+	for (i = 0; i < ASSOC_ARRAY_TEST_NR_KEYS; i++) {
+		if (m->present[i]) {
+			struct assoc_array_test_object obj = {
+				.value = m->values[i],
+			};
+
+			memcpy(obj.key, &assoc_array_test_keys[i * 2], sizeof(obj.key));
+
+			if (!keep(&obj, data)) {
+				m->present[i] = false;
+				m->nr_present--;
+			}
+		}
+	}
+
+	assoc_array_test_invariant(m);
+}
+
+static void assoc_array_test_model_cancel_insert(struct assoc_array_test_model *m,
+						 int i, unsigned long value)
+{
+	struct assoc_array_edit *edit;
+	struct assoc_array_test_object *obj;
+
+	obj = kzalloc_obj(*obj, GFP_KERNEL);
+	KUNIT_ASSERT_NOT_NULL(m->test, obj);
+	memcpy(obj->key, &assoc_array_test_keys[i * 2], sizeof(obj->key));
+	obj->value = value;
+	refcount_set(&obj->usage, 1);
+
+	edit = assoc_array_insert(&m->array, &assoc_array_test_ops, obj->key, obj);
+	if (IS_ERR_OR_NULL(edit)) {
+		kfree(obj);
+		KUNIT_FAIL_AND_ABORT(m->test, "insert failed: %ld", PTR_ERR(edit));
+	}
+	assoc_array_cancel_edit(edit);
+	kfree(obj);
+
+	assoc_array_test_invariant(m);
+}
+
+static void assoc_array_test_model_cancel_delete(struct assoc_array_test_model *m, int i)
+{
+	struct assoc_array_edit *edit;
+
+	edit = assoc_array_delete(&m->array, &assoc_array_test_ops,
+				  &assoc_array_test_keys[i * 2]);
+	KUNIT_ASSERT_FALSE(m->test, IS_ERR(edit));
+
+	if (edit)
+		assoc_array_cancel_edit(edit);
+
+	assoc_array_test_invariant(m);
+}
+
+static void assoc_array_test_model_cancel_clear(struct assoc_array_test_model *m)
+{
+	struct assoc_array_edit *edit;
+
+	edit = assoc_array_clear(&m->array, &assoc_array_test_ops);
+	KUNIT_ASSERT_FALSE(m->test, IS_ERR(edit));
+
+	if (edit)
+		assoc_array_cancel_edit(edit);
+
+	assoc_array_test_invariant(m);
+}
+
+static int assoc_array_test_stop_iterator(const void *object, void *data)
+{
+	int *count = data;
+
+	if (++(*count) == ASSOC_ARRAY_TEST_STOP_AFTER)
+		return ASSOC_ARRAY_TEST_STOP_STATUS;
+
+	return 0;
+}
+
+static void assoc_array_test_model_iterate_stop(struct assoc_array_test_model *m)
+{
+	int count = 0;
+
+	KUNIT_EXPECT_EQ(m->test,
+			assoc_array_iterate(&m->array, assoc_array_test_stop_iterator, &count),
+			ASSOC_ARRAY_TEST_STOP_STATUS);
+	KUNIT_EXPECT_EQ(m->test, count, ASSOC_ARRAY_TEST_STOP_AFTER);
+
+	assoc_array_test_invariant(m);
+}
+
+static bool assoc_array_test_keep_even(const struct assoc_array_test_object *obj, void *data)
+{
+	return !(obj->value & 1);
+}
+
+static bool assoc_array_test_keep_none(const struct assoc_array_test_object *obj, void *data)
+{
+	return false;
+}
+
+static void assoc_array_test_fill_and_drain(struct kunit *test)
+{
+	struct assoc_array_test_model *m = assoc_array_test_model_create(test);
+	int i;
+
+	assoc_array_test_model_fill(m);
+
+	for (i = ASSOC_ARRAY_TEST_NR_KEYS - 1; i >= 0; i--)
+		assoc_array_test_model_delete(m, i);
+}
+
+static void assoc_array_test_replace(struct kunit *test)
+{
+	struct assoc_array_test_model *m = assoc_array_test_model_create(test);
+	int i;
+
+	assoc_array_test_model_fill(m);
+
+	for (i = 0; i < ASSOC_ARRAY_TEST_NR_KEYS; i++)
+		assoc_array_test_model_insert(m, i, i + ASSOC_ARRAY_TEST_NR_KEYS);
+}
+
+static void assoc_array_test_collapse(struct kunit *test)
+{
+	struct assoc_array_test_model *m = assoc_array_test_model_create(test);
+	int i;
+
+	assoc_array_test_model_fill(m);
+
+	for (i = ASSOC_ARRAY_TEST_NR_KEYS - 1; i >= 16; i--)
+		assoc_array_test_model_delete(m, i);
+
+	for (i = 16; i < 32; i++)
+		assoc_array_test_model_insert(m, i, i * 2);
+}
+
+static void assoc_array_test_iterate_stop(struct kunit *test)
+{
+	struct assoc_array_test_model *m = assoc_array_test_model_create(test);
+
+	assoc_array_test_model_fill(m);
+	assoc_array_test_model_iterate_stop(m);
+}
+
+static void assoc_array_test_gc(struct kunit *test)
+{
+	struct assoc_array_test_model *m = assoc_array_test_model_create(test);
+
+	assoc_array_test_model_fill(m);
+	assoc_array_test_model_gc(m, assoc_array_test_keep_even, NULL);
+	assoc_array_test_model_gc(m, assoc_array_test_keep_none, NULL);
+}
+
+static void assoc_array_test_cancel(struct kunit *test)
+{
+	struct assoc_array_test_model *m = assoc_array_test_model_create(test);
+
+	assoc_array_test_model_fill(m);
+
+	assoc_array_test_model_delete(m, 0);
+	assoc_array_test_model_cancel_insert(m, 0, 999);
+	assoc_array_test_model_cancel_delete(m, 1);
+	assoc_array_test_model_cancel_clear(m);
+}
+
+static void assoc_array_test_clear(struct kunit *test)
+{
+	struct assoc_array_test_model *m = assoc_array_test_model_create(test);
+
+	assoc_array_test_model_fill(m);
+	assoc_array_test_model_clear(m);
+	assoc_array_test_model_fill(m);
+}
+
+static void assoc_array_test_destroy(struct kunit *test)
+{
+	struct assoc_array_test_model *m = assoc_array_test_model_create(test);
+
+	assoc_array_test_model_fill(m);
+	assoc_array_test_model_destroy(m);
+	assoc_array_test_model_fill(m);
+}
+
+static struct kunit_case assoc_array_test_cases[] = {
+	KUNIT_CASE(assoc_array_test_fill_and_drain),
+	KUNIT_CASE(assoc_array_test_replace),
+	KUNIT_CASE(assoc_array_test_collapse),
+	KUNIT_CASE(assoc_array_test_iterate_stop),
+	KUNIT_CASE(assoc_array_test_gc),
+	KUNIT_CASE(assoc_array_test_cancel),
+	KUNIT_CASE(assoc_array_test_clear),
+	KUNIT_CASE(assoc_array_test_destroy),
+	{}
+};
+
+static struct kunit_suite assoc_array_test_suite = {
+	.name = "assoc_array",
+	.test_cases = assoc_array_test_cases,
+};
+
+kunit_test_suites(&assoc_array_test_suite);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("KUnit test for assoc_array");
--
2.47.3


             reply	other threads:[~2026-10-14 16:01 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-14 16:01 Jarkko Sakkinen [this message]
2026-10-14 16:35 ` [PATCH] lib/tests: kunit for associative array Eric Biggers
2026-10-14 16:56   ` Jarkko Sakkinen
2026-10-14 17:03     ` Jarkko Sakkinen
2026-10-14 17:32       ` Jarkko Sakkinen
2026-10-14 17:01   ` Linus Torvalds

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20261014160144.1835860-1-jarkko@kernel.org \
    --to=jarkko@kernel.org \
    --cc=409411716@gms.tku.edu.tw \
    --cc=akpm@linux-foundation.org \
    --cc=andriy.shevchenko@linux.intel.com \
    --cc=brendan.higgins@linux.dev \
    --cc=david@davidgow.net \
    --cc=dmantipov@yandex.ru \
    --cc=keyrings@vger.kernel.org \
    --cc=kunit-dev@googlegroups.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-kselftest@vger.kernel.org \
    --cc=note351@hotmail.com \
    --cc=pasha.tatashin@soleen.com \
    --cc=pmladek@suse.com \
    --cc=raemoar63@gmail.com \
    --cc=sakamo.ryota@gmail.com \
    --cc=visitorckw@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.