* [PATCH v2 0/1] Add KUnit tests for llist
@ 2024-09-03 21:40 Artur Alves
2024-09-03 21:40 ` [PATCH v2 1/1] lib/llist_kunit.c: add " Artur Alves
0 siblings, 1 reply; 4+ messages in thread
From: Artur Alves @ 2024-09-03 21:40 UTC (permalink / raw)
To: Andrew Morton, linux-kernel, Brendan Higgins, David Gow, Rae Moar,
linux-kselftest, kunit-dev
Cc: n, andrealmeid, vinicius, diego.daniel.professional
Hi all,
This is part of a hackathon organized by LKCAMP[1], focused on writing
tests using KUnit. We reached out a while ago asking for advice on what
would be a useful contribution[2] and ended up choosing data structures
that did not yet have tests.
This patch adds tests for the llist data structure, defined in
include/linux/llist.h, and is inspired by the KUnit tests for the doubly
linked list in lib/list-test.c[3].
It is important to note that this patch depends on the patch referenced
in [4], as it utilizes the newly created lib/tests/ subdirectory.
[1] https://lkcamp.dev/about/
[2] https://lore.kernel.org/all/Zktnt7rjKryTh9-N@arch/
[3] https://elixir.bootlin.com/linux/latest/source/lib/list-test.c
[4] https://lore.kernel.org/all/20240720181025.work.002-kees@kernel.org/
---
Changes in v2:
- Add MODULE_DESCRIPTION()
- Move the tests from lib/llist_kunit.c to lib/tests/llist_kunit.c
- Change the license from "GPL v2" to "GPL"
Artur Alves (1):
lib/llist_kunit.c: add KUnit tests for llist
lib/Kconfig.debug | 11 ++
lib/tests/Makefile | 1 +
lib/tests/llist_kunit.c | 361 ++++++++++++++++++++++++++++++++++++++++
3 files changed, 373 insertions(+)
create mode 100644 lib/tests/llist_kunit.c
--
2.46.0
^ permalink raw reply [flat|nested] 4+ messages in thread
* [PATCH v2 1/1] lib/llist_kunit.c: add KUnit tests for llist
2024-09-03 21:40 [PATCH v2 0/1] Add KUnit tests for llist Artur Alves
@ 2024-09-03 21:40 ` Artur Alves
2024-09-05 20:51 ` Rae Moar
0 siblings, 1 reply; 4+ messages in thread
From: Artur Alves @ 2024-09-03 21:40 UTC (permalink / raw)
To: Andrew Morton, linux-kernel, Brendan Higgins, David Gow, Rae Moar,
linux-kselftest, kunit-dev
Cc: n, andrealmeid, vinicius, diego.daniel.professional
Add KUnit tests for the llist data structure. They test the vast
majority of methods and macros defined in include/linux/llist.h.
These are inspired by the existing tests for the 'list' doubly
linked in lib/list-test.c [1]. Each test case (llist_test_x)
tests the behaviour of the llist function/macro 'x'.
[1] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/lib/list-test.c?h=v6.11-rc6
Signed-off-by: Artur Alves <arturacb@gmail.com>
---
lib/Kconfig.debug | 11 ++
lib/tests/Makefile | 1 +
lib/tests/llist_kunit.c | 361 ++++++++++++++++++++++++++++++++++++++++
3 files changed, 373 insertions(+)
create mode 100644 lib/tests/llist_kunit.c
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index a30c03a66172..b2725daccc52 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -2813,6 +2813,17 @@ config USERCOPY_KUNIT_TEST
on the copy_to/from_user infrastructure, making sure basic
user/kernel boundary testing is working.
+config LLIST_KUNIT_TEST
+ tristate "KUnit tests for lib/llist" if !KUNIT_ALL_TESTS
+ depends on KUNIT
+ default KUNIT_ALL_TESTS
+ help
+ This option builds the "llist_kunit" test module that
+ helps to verify the correctness of the functions and
+ macros defined in (<linux/llist.h>).
+
+ If unsure, say N.
+
config TEST_UDELAY
tristate "udelay test driver"
help
diff --git a/lib/tests/Makefile b/lib/tests/Makefile
index c6a14cc8663e..8d7c40a73110 100644
--- a/lib/tests/Makefile
+++ b/lib/tests/Makefile
@@ -34,4 +34,5 @@ CFLAGS_stackinit_kunit.o += $(call cc-disable-warning, switch-unreachable)
obj-$(CONFIG_STACKINIT_KUNIT_TEST) += stackinit_kunit.o
obj-$(CONFIG_STRING_KUNIT_TEST) += string_kunit.o
obj-$(CONFIG_STRING_HELPERS_KUNIT_TEST) += string_helpers_kunit.o
+obj-$(CONFIG_LLIST_KUNIT_TEST) += llist_kunit.o
diff --git a/lib/tests/llist_kunit.c b/lib/tests/llist_kunit.c
new file mode 100644
index 000000000000..f273c0d175c7
--- /dev/null
+++ b/lib/tests/llist_kunit.c
@@ -0,0 +1,361 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * KUnit test for the Kernel lock-less linked-list structure.
+ *
+ * Author: Artur Alves <arturacb@gmail.com>
+ */
+
+#include <kunit/test.h>
+#include <linux/llist.h>
+
+#define ENTRIES_SIZE 3
+
+struct llist_test_struct {
+ int data;
+ struct llist_node node;
+};
+
+static void llist_test_init_llist(struct kunit *test)
+{
+ /* test if the llist is correctly initialized */
+ struct llist_head llist1 = LLIST_HEAD_INIT(llist1);
+ LLIST_HEAD(llist2);
+ struct llist_head llist3, *llist4, *llist5;
+
+ KUNIT_EXPECT_TRUE(test, llist_empty(&llist1));
+
+ KUNIT_EXPECT_TRUE(test, llist_empty(&llist2));
+
+ init_llist_head(&llist3);
+ KUNIT_EXPECT_TRUE(test, llist_empty(&llist3));
+
+ llist4 = kzalloc(sizeof(*llist4), GFP_KERNEL | __GFP_NOFAIL);
+ init_llist_head(llist4);
+ KUNIT_EXPECT_TRUE(test, llist_empty(llist4));
+ kfree(llist4);
+
+ llist5 = kmalloc(sizeof(*llist5), GFP_KERNEL | __GFP_NOFAIL);
+ memset(llist5, 0xFF, sizeof(*llist5));
+ init_llist_head(llist5);
+ KUNIT_EXPECT_TRUE(test, llist_empty(llist5));
+ kfree(llist5);
+}
+
+static void llist_test_init_llist_node(struct kunit *test)
+{
+ struct llist_node a;
+
+ init_llist_node(&a);
+
+ KUNIT_EXPECT_PTR_EQ(test, a.next, &a);
+}
+
+static void llist_test_llist_entry(struct kunit *test)
+{
+ struct llist_test_struct test_struct, *aux;
+ struct llist_node *llist = &test_struct.node;
+
+ aux = llist_entry(llist, struct llist_test_struct, node);
+ KUNIT_EXPECT_PTR_EQ(test, &test_struct, aux);
+}
+
+static void llist_test_add(struct kunit *test)
+{
+ struct llist_node a, b;
+ LLIST_HEAD(llist);
+
+ init_llist_node(&a);
+ init_llist_node(&b);
+
+ /* The first assertion must be true, given that llist is empty */
+ KUNIT_EXPECT_TRUE(test, llist_add(&a, &llist));
+ KUNIT_EXPECT_FALSE(test, llist_add(&b, &llist));
+
+ /* Should be [List] -> b -> a */
+ KUNIT_EXPECT_PTR_EQ(test, llist.first, &b);
+ KUNIT_EXPECT_PTR_EQ(test, b.next, &a);
+}
+
+static void llist_test_add_batch(struct kunit *test)
+{
+ struct llist_node a, b, c;
+ LLIST_HEAD(llist);
+ LLIST_HEAD(llist2);
+
+ init_llist_node(&a);
+ init_llist_node(&b);
+ init_llist_node(&c);
+
+ llist_add(&a, &llist2);
+ llist_add(&b, &llist2);
+ llist_add(&c, &llist2);
+
+ /* This assertion must be true, given that llist is empty */
+ KUNIT_EXPECT_TRUE(test, llist_add_batch(&c, &a, &llist));
+
+ /* should be [List] -> c -> b -> a */
+ KUNIT_EXPECT_PTR_EQ(test, llist.first, &c);
+ KUNIT_EXPECT_PTR_EQ(test, c.next, &b);
+ KUNIT_EXPECT_PTR_EQ(test, b.next, &a);
+}
+
+static void llist_test_llist_next(struct kunit *test)
+{
+ struct llist_node a, b;
+ LLIST_HEAD(llist);
+
+ init_llist_node(&a);
+ init_llist_node(&b);
+
+ llist_add(&a, &llist);
+ llist_add(&b, &llist);
+
+ /* should be [List] -> b -> a */
+ KUNIT_EXPECT_PTR_EQ(test, llist_next(&b), &a);
+ KUNIT_EXPECT_NULL(test, llist_next(&a));
+}
+
+static void llist_test_empty_llist(struct kunit *test)
+{
+ struct llist_head llist = LLIST_HEAD_INIT(llist);
+ struct llist_node a;
+
+ KUNIT_EXPECT_TRUE(test, llist_empty(&llist));
+
+ llist_add(&a, &llist);
+
+ KUNIT_EXPECT_FALSE(test, llist_empty(&llist));
+}
+
+static void llist_test_llist_on_list(struct kunit *test)
+{
+ struct llist_node a, b;
+ LLIST_HEAD(llist);
+
+ init_llist_node(&a);
+ init_llist_node(&b);
+
+ llist_add(&a, &llist);
+
+ /* should be [List] -> a */
+ KUNIT_EXPECT_TRUE(test, llist_on_list(&a));
+ KUNIT_EXPECT_FALSE(test, llist_on_list(&b));
+}
+
+static void llist_test_del_first(struct kunit *test)
+{
+ struct llist_node a, b, *c;
+ LLIST_HEAD(llist);
+
+ llist_add(&a, &llist);
+ llist_add(&b, &llist);
+
+ /* before: [List] -> b -> a */
+ c = llist_del_first(&llist);
+
+ /* should be [List] -> a */
+ KUNIT_EXPECT_PTR_EQ(test, llist.first, &a);
+
+ /* del must return a pointer to llist_node b
+ * the returned pointer must be marked on list
+ */
+ KUNIT_EXPECT_PTR_EQ(test, c, &b);
+ KUNIT_EXPECT_TRUE(test, llist_on_list(c));
+}
+
+static void llist_test_del_first_init(struct kunit *test)
+{
+ struct llist_node a, *b;
+ LLIST_HEAD(llist);
+
+ llist_add(&a, &llist);
+
+ b = llist_del_first_init(&llist);
+
+ /* should be [List] */
+ KUNIT_EXPECT_TRUE(test, llist_empty(&llist));
+
+ /* the returned pointer must be marked out of the list */
+ KUNIT_EXPECT_FALSE(test, llist_on_list(b));
+}
+
+static void llist_test_del_first_this(struct kunit *test)
+{
+ struct llist_node a, b;
+ LLIST_HEAD(llist);
+
+ llist_add(&a, &llist);
+ llist_add(&b, &llist);
+
+ llist_del_first_this(&llist, &a);
+
+ /* before: [List] -> b -> a */
+
+ // should remove only if is the first node in the llist
+ KUNIT_EXPECT_FALSE(test, llist_del_first_this(&llist, &a));
+
+ KUNIT_EXPECT_TRUE(test, llist_del_first_this(&llist, &b));
+
+ /* should be [List] -> a */
+ KUNIT_EXPECT_PTR_EQ(test, llist.first, &a);
+}
+
+static void llist_test_del_all(struct kunit *test)
+{
+ struct llist_node a, b;
+ LLIST_HEAD(llist);
+ LLIST_HEAD(empty_llist);
+
+ llist_add(&a, &llist);
+ llist_add(&b, &llist);
+
+ /* deleting from a empty llist should return NULL */
+ KUNIT_EXPECT_NULL(test, llist_del_all(&empty_llist));
+
+ llist_del_all(&llist);
+
+ KUNIT_EXPECT_TRUE(test, llist_empty(&llist));
+}
+
+static void llist_test_for_each(struct kunit *test)
+{
+ struct llist_node entries[ENTRIES_SIZE] = { 0 };
+ struct llist_node *pos, *deleted_nodes;
+ LLIST_HEAD(llist);
+ int i = 0;
+
+ for (int i = ENTRIES_SIZE - 1; i >= 0; i--)
+ llist_add(&entries[i], &llist);
+
+ /* before [List] -> entries[0] -> ... -> entries[ENTRIES_SIZE - 1] */
+ llist_for_each(pos, llist.first) {
+ KUNIT_EXPECT_PTR_EQ(test, pos, &entries[i++]);
+ }
+
+ KUNIT_EXPECT_EQ(test, ENTRIES_SIZE, i);
+
+ i = 0;
+
+ /* traversing deleted nodes */
+ deleted_nodes = llist_del_all(&llist);
+
+ llist_for_each(pos, deleted_nodes) {
+ KUNIT_EXPECT_PTR_EQ(test, pos, &entries[i++]);
+ }
+
+ KUNIT_EXPECT_EQ(test, ENTRIES_SIZE, i);
+}
+
+static void llist_test_for_each_safe(struct kunit *test)
+{
+ struct llist_node entries[ENTRIES_SIZE] = { 0 };
+ struct llist_node *pos, *n;
+ LLIST_HEAD(llist);
+ int i = 0;
+
+ for (int i = ENTRIES_SIZE - 1; i >= 0; i--)
+ llist_add(&entries[i], &llist);
+
+ llist_for_each_safe(pos, n, llist.first) {
+ KUNIT_EXPECT_PTR_EQ(test, pos, &entries[i++]);
+ llist_del_first(&llist);
+ }
+
+ KUNIT_EXPECT_EQ(test, ENTRIES_SIZE, i);
+ KUNIT_EXPECT_TRUE(test, llist_empty(&llist));
+}
+
+static void llist_test_for_each_entry(struct kunit *test)
+{
+ struct llist_test_struct entries[ENTRIES_SIZE], *pos;
+ LLIST_HEAD(llist);
+ int i = 0;
+
+ for (int i = ENTRIES_SIZE - 1; i >= 0; --i) {
+ entries[i].data = i;
+ llist_add(&entries[i].node, &llist);
+ }
+
+ i = 0;
+
+ llist_for_each_entry(pos, llist.first, node) {
+ KUNIT_EXPECT_EQ(test, pos->data, i);
+ i++;
+ }
+
+ KUNIT_EXPECT_EQ(test, ENTRIES_SIZE, i);
+}
+
+static void llist_test_for_each_entry_safe(struct kunit *test)
+{
+ struct llist_test_struct entries[ENTRIES_SIZE], *pos, *n;
+ LLIST_HEAD(llist);
+ int i = 0;
+
+ for (int i = ENTRIES_SIZE - 1; i >= 0; --i) {
+ entries[i].data = i;
+ llist_add(&entries[i].node, &llist);
+ }
+
+ i = 0;
+
+ llist_for_each_entry_safe(pos, n, llist.first, node) {
+ KUNIT_EXPECT_EQ(test, pos->data, i++);
+ llist_del_first(&llist);
+ }
+
+ KUNIT_EXPECT_EQ(test, ENTRIES_SIZE, i);
+ KUNIT_EXPECT_TRUE(test, llist_empty(&llist));
+}
+
+static void llist_test_reverse_order(struct kunit *test)
+{
+ struct llist_node entries[3], *pos, *reversed_llist;
+ LLIST_HEAD(llist);
+ int i = 0;
+
+ llist_add(&entries[0], &llist);
+ llist_add(&entries[1], &llist);
+ llist_add(&entries[2], &llist);
+
+ /* before [List] -> entries[2] -> entries[1] -> entries[0] */
+ reversed_llist = llist_reverse_order(llist_del_first(&llist));
+
+ /* should be [List] -> entries[0] -> entries[1] -> entrires[2] */
+ llist_for_each(pos, reversed_llist) {
+ KUNIT_EXPECT_PTR_EQ(test, pos, &entries[i++]);
+ }
+
+ KUNIT_EXPECT_EQ(test, 3, i);
+}
+
+static struct kunit_case llist_test_cases[] = {
+ KUNIT_CASE(llist_test_init_llist),
+ KUNIT_CASE(llist_test_init_llist_node),
+ KUNIT_CASE(llist_test_llist_entry),
+ KUNIT_CASE(llist_test_add),
+ KUNIT_CASE(llist_test_add_batch),
+ KUNIT_CASE(llist_test_llist_next),
+ KUNIT_CASE(llist_test_empty_llist),
+ KUNIT_CASE(llist_test_llist_on_list),
+ KUNIT_CASE(llist_test_del_first),
+ KUNIT_CASE(llist_test_del_first_init),
+ KUNIT_CASE(llist_test_del_first_this),
+ KUNIT_CASE(llist_test_del_all),
+ KUNIT_CASE(llist_test_for_each),
+ KUNIT_CASE(llist_test_for_each_safe),
+ KUNIT_CASE(llist_test_for_each_entry),
+ KUNIT_CASE(llist_test_for_each_entry_safe),
+ KUNIT_CASE(llist_test_reverse_order),
+ {}
+};
+
+static struct kunit_suite llist_test_suite = {
+ .name = "llist",
+ .test_cases = llist_test_cases,
+};
+
+kunit_test_suite(llist_test_suite);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("KUnit tests for the llist data structure.");
--
2.46.0
^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: [PATCH v2 1/1] lib/llist_kunit.c: add KUnit tests for llist
2024-09-03 21:40 ` [PATCH v2 1/1] lib/llist_kunit.c: add " Artur Alves
@ 2024-09-05 20:51 ` Rae Moar
2024-09-09 21:04 ` Artur Alves Cavalcante de Barros
0 siblings, 1 reply; 4+ messages in thread
From: Rae Moar @ 2024-09-05 20:51 UTC (permalink / raw)
To: Artur Alves
Cc: Andrew Morton, linux-kernel, Brendan Higgins, David Gow,
linux-kselftest, kunit-dev, n, andrealmeid, vinicius,
diego.daniel.professional
On Tue, Sep 3, 2024 at 5:40 PM Artur Alves <arturacb@gmail.com> wrote:
>
> Add KUnit tests for the llist data structure. They test the vast
> majority of methods and macros defined in include/linux/llist.h.
>
> These are inspired by the existing tests for the 'list' doubly
> linked in lib/list-test.c [1]. Each test case (llist_test_x)
> tests the behaviour of the llist function/macro 'x'.
>
> [1] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/lib/list-test.c?h=v6.11-rc6
>
> Signed-off-by: Artur Alves <arturacb@gmail.com>
Hello!
Thanks for creating this new test! It looks really good and is passing
all the tests.
My main comment is that this patch is causing some checkpatch warnings:
WARNING: Prefer a maximum 75 chars per line (possible unwrapped
commit description?)
#13:
[1] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/lib/list-test.c?h=v6.11-rc6
It's probably fine to ignore this warning as it is a link. But I might
remove the link because it is not absolutely necessary in this case.
WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
#58:
new file mode 100644
ERROR: that open brace { should be on the previous line
#306: FILE: lib/llist_kunit.c:249:
+static void llist_test_for_each_safe(struct kunit *test)
+{
ERROR: that open brace { should be on the previous line
#325: FILE: lib/llist_kunit.c:268:
+static void llist_test_for_each_entry(struct kunit *test)
+{
ERROR: that open brace { should be on the previous line
#346: FILE: lib/llist_kunit.c:289:
+static void llist_test_for_each_entry_safe(struct kunit *test)
+{
These checkpatch errors are mistaken since the open brace should be
where it is. I believe this is getting picked up because of the
"for_each" in the test name. This was fixed for me by rewriting the
test names: from "llist_test_for_each_safe" -> to
"llist_test_safe_for_each", and so on for the other tests with errors.
Sorry it's a pain to change this but I think it is a better fix than
changing the checkpatch script.
> ---
> lib/Kconfig.debug | 11 ++
> lib/tests/Makefile | 1 +
> lib/tests/llist_kunit.c | 361 ++++++++++++++++++++++++++++++++++++++++
> 3 files changed, 373 insertions(+)
> create mode 100644 lib/tests/llist_kunit.c
>
> diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
> index a30c03a66172..b2725daccc52 100644
> --- a/lib/Kconfig.debug
> +++ b/lib/Kconfig.debug
> @@ -2813,6 +2813,17 @@ config USERCOPY_KUNIT_TEST
> on the copy_to/from_user infrastructure, making sure basic
> user/kernel boundary testing is working.
>
> +config LLIST_KUNIT_TEST
> + tristate "KUnit tests for lib/llist" if !KUNIT_ALL_TESTS
> + depends on KUNIT
> + default KUNIT_ALL_TESTS
> + help
> + This option builds the "llist_kunit" test module that
> + helps to verify the correctness of the functions and
> + macros defined in (<linux/llist.h>).
Also, I think I would prefer if this description was a bit tweaked.
Saying it builds the "module" is confusing since this test might be
run built-in instead. So maybe something more similar to :
This builds the llist (lock-less list) KUnit test suite. It tests the
API and basic functionality of the macros and functions defined in
<linux/llish.h>.
> +
> + If unsure, say N.
> +
> config TEST_UDELAY
> tristate "udelay test driver"
> help
> diff --git a/lib/tests/Makefile b/lib/tests/Makefile
> index c6a14cc8663e..8d7c40a73110 100644
> --- a/lib/tests/Makefile
> +++ b/lib/tests/Makefile
> @@ -34,4 +34,5 @@ CFLAGS_stackinit_kunit.o += $(call cc-disable-warning, switch-unreachable)
> obj-$(CONFIG_STACKINIT_KUNIT_TEST) += stackinit_kunit.o
> obj-$(CONFIG_STRING_KUNIT_TEST) += string_kunit.o
> obj-$(CONFIG_STRING_HELPERS_KUNIT_TEST) += string_helpers_kunit.o
> +obj-$(CONFIG_LLIST_KUNIT_TEST) += llist_kunit.o
>
> diff --git a/lib/tests/llist_kunit.c b/lib/tests/llist_kunit.c
> new file mode 100644
> index 000000000000..f273c0d175c7
> --- /dev/null
> +++ b/lib/tests/llist_kunit.c
> @@ -0,0 +1,361 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * KUnit test for the Kernel lock-less linked-list structure.
> + *
> + * Author: Artur Alves <arturacb@gmail.com>
> + */
> +
> +#include <kunit/test.h>
> +#include <linux/llist.h>
> +
> +#define ENTRIES_SIZE 3
> +
> +struct llist_test_struct {
> + int data;
> + struct llist_node node;
> +};
> +
> +static void llist_test_init_llist(struct kunit *test)
> +{
> + /* test if the llist is correctly initialized */
> + struct llist_head llist1 = LLIST_HEAD_INIT(llist1);
> + LLIST_HEAD(llist2);
> + struct llist_head llist3, *llist4, *llist5;
> +
> + KUNIT_EXPECT_TRUE(test, llist_empty(&llist1));
> +
> + KUNIT_EXPECT_TRUE(test, llist_empty(&llist2));
> +
> + init_llist_head(&llist3);
> + KUNIT_EXPECT_TRUE(test, llist_empty(&llist3));
> +
> + llist4 = kzalloc(sizeof(*llist4), GFP_KERNEL | __GFP_NOFAIL);
> + init_llist_head(llist4);
> + KUNIT_EXPECT_TRUE(test, llist_empty(llist4));
> + kfree(llist4);
> +
> + llist5 = kmalloc(sizeof(*llist5), GFP_KERNEL | __GFP_NOFAIL);
> + memset(llist5, 0xFF, sizeof(*llist5));
> + init_llist_head(llist5);
> + KUNIT_EXPECT_TRUE(test, llist_empty(llist5));
> + kfree(llist5);
> +}
> +
> +static void llist_test_init_llist_node(struct kunit *test)
> +{
> + struct llist_node a;
> +
> + init_llist_node(&a);
> +
> + KUNIT_EXPECT_PTR_EQ(test, a.next, &a);
> +}
> +
> +static void llist_test_llist_entry(struct kunit *test)
> +{
> + struct llist_test_struct test_struct, *aux;
> + struct llist_node *llist = &test_struct.node;
> +
> + aux = llist_entry(llist, struct llist_test_struct, node);
> + KUNIT_EXPECT_PTR_EQ(test, &test_struct, aux);
> +}
> +
> +static void llist_test_add(struct kunit *test)
> +{
> + struct llist_node a, b;
> + LLIST_HEAD(llist);
> +
> + init_llist_node(&a);
> + init_llist_node(&b);
> +
> + /* The first assertion must be true, given that llist is empty */
> + KUNIT_EXPECT_TRUE(test, llist_add(&a, &llist));
> + KUNIT_EXPECT_FALSE(test, llist_add(&b, &llist));
> +
> + /* Should be [List] -> b -> a */
> + KUNIT_EXPECT_PTR_EQ(test, llist.first, &b);
> + KUNIT_EXPECT_PTR_EQ(test, b.next, &a);
> +}
> +
> +static void llist_test_add_batch(struct kunit *test)
> +{
> + struct llist_node a, b, c;
> + LLIST_HEAD(llist);
> + LLIST_HEAD(llist2);
> +
> + init_llist_node(&a);
> + init_llist_node(&b);
> + init_llist_node(&c);
> +
> + llist_add(&a, &llist2);
> + llist_add(&b, &llist2);
> + llist_add(&c, &llist2);
> +
> + /* This assertion must be true, given that llist is empty */
> + KUNIT_EXPECT_TRUE(test, llist_add_batch(&c, &a, &llist));
> +
> + /* should be [List] -> c -> b -> a */
> + KUNIT_EXPECT_PTR_EQ(test, llist.first, &c);
> + KUNIT_EXPECT_PTR_EQ(test, c.next, &b);
> + KUNIT_EXPECT_PTR_EQ(test, b.next, &a);
> +}
> +
> +static void llist_test_llist_next(struct kunit *test)
> +{
> + struct llist_node a, b;
> + LLIST_HEAD(llist);
> +
> + init_llist_node(&a);
> + init_llist_node(&b);
> +
> + llist_add(&a, &llist);
> + llist_add(&b, &llist);
> +
> + /* should be [List] -> b -> a */
> + KUNIT_EXPECT_PTR_EQ(test, llist_next(&b), &a);
> + KUNIT_EXPECT_NULL(test, llist_next(&a));
> +}
> +
> +static void llist_test_empty_llist(struct kunit *test)
> +{
> + struct llist_head llist = LLIST_HEAD_INIT(llist);
> + struct llist_node a;
> +
> + KUNIT_EXPECT_TRUE(test, llist_empty(&llist));
> +
> + llist_add(&a, &llist);
> +
> + KUNIT_EXPECT_FALSE(test, llist_empty(&llist));
> +}
> +
> +static void llist_test_llist_on_list(struct kunit *test)
> +{
> + struct llist_node a, b;
> + LLIST_HEAD(llist);
> +
> + init_llist_node(&a);
> + init_llist_node(&b);
> +
> + llist_add(&a, &llist);
> +
> + /* should be [List] -> a */
> + KUNIT_EXPECT_TRUE(test, llist_on_list(&a));
> + KUNIT_EXPECT_FALSE(test, llist_on_list(&b));
> +}
> +
> +static void llist_test_del_first(struct kunit *test)
> +{
> + struct llist_node a, b, *c;
> + LLIST_HEAD(llist);
> +
> + llist_add(&a, &llist);
> + llist_add(&b, &llist);
> +
> + /* before: [List] -> b -> a */
> + c = llist_del_first(&llist);
> +
> + /* should be [List] -> a */
> + KUNIT_EXPECT_PTR_EQ(test, llist.first, &a);
> +
> + /* del must return a pointer to llist_node b
> + * the returned pointer must be marked on list
> + */
> + KUNIT_EXPECT_PTR_EQ(test, c, &b);
> + KUNIT_EXPECT_TRUE(test, llist_on_list(c));
> +}
> +
> +static void llist_test_del_first_init(struct kunit *test)
> +{
> + struct llist_node a, *b;
> + LLIST_HEAD(llist);
> +
> + llist_add(&a, &llist);
> +
> + b = llist_del_first_init(&llist);
> +
> + /* should be [List] */
> + KUNIT_EXPECT_TRUE(test, llist_empty(&llist));
> +
> + /* the returned pointer must be marked out of the list */
> + KUNIT_EXPECT_FALSE(test, llist_on_list(b));
> +}
> +
> +static void llist_test_del_first_this(struct kunit *test)
> +{
> + struct llist_node a, b;
> + LLIST_HEAD(llist);
> +
> + llist_add(&a, &llist);
> + llist_add(&b, &llist);
> +
> + llist_del_first_this(&llist, &a);
> +
> + /* before: [List] -> b -> a */
> +
> + // should remove only if is the first node in the llist
> + KUNIT_EXPECT_FALSE(test, llist_del_first_this(&llist, &a));
> +
> + KUNIT_EXPECT_TRUE(test, llist_del_first_this(&llist, &b));
> +
> + /* should be [List] -> a */
> + KUNIT_EXPECT_PTR_EQ(test, llist.first, &a);
> +}
> +
> +static void llist_test_del_all(struct kunit *test)
> +{
> + struct llist_node a, b;
> + LLIST_HEAD(llist);
> + LLIST_HEAD(empty_llist);
> +
> + llist_add(&a, &llist);
> + llist_add(&b, &llist);
> +
> + /* deleting from a empty llist should return NULL */
> + KUNIT_EXPECT_NULL(test, llist_del_all(&empty_llist));
> +
> + llist_del_all(&llist);
> +
> + KUNIT_EXPECT_TRUE(test, llist_empty(&llist));
> +}
> +
> +static void llist_test_for_each(struct kunit *test)
> +{
> + struct llist_node entries[ENTRIES_SIZE] = { 0 };
> + struct llist_node *pos, *deleted_nodes;
> + LLIST_HEAD(llist);
> + int i = 0;
> +
> + for (int i = ENTRIES_SIZE - 1; i >= 0; i--)
> + llist_add(&entries[i], &llist);
> +
> + /* before [List] -> entries[0] -> ... -> entries[ENTRIES_SIZE - 1] */
> + llist_for_each(pos, llist.first) {
> + KUNIT_EXPECT_PTR_EQ(test, pos, &entries[i++]);
> + }
> +
> + KUNIT_EXPECT_EQ(test, ENTRIES_SIZE, i);
> +
> + i = 0;
This is super nitpicky but I think I would prefer if you set two
variables to zero at the beginning rather than reusing "i". So: int i
= 0, j = 0;
> +
> + /* traversing deleted nodes */
> + deleted_nodes = llist_del_all(&llist);
> +
> + llist_for_each(pos, deleted_nodes) {
> + KUNIT_EXPECT_PTR_EQ(test, pos, &entries[i++]);
> + }
> +
> + KUNIT_EXPECT_EQ(test, ENTRIES_SIZE, i);
> +}
> +
> +static void llist_test_for_each_safe(struct kunit *test)
> +{
> + struct llist_node entries[ENTRIES_SIZE] = { 0 };
I'm not sure if it is necessary to initialize this to be zeros.
> + struct llist_node *pos, *n;
> + LLIST_HEAD(llist);
> + int i = 0;
> +
> + for (int i = ENTRIES_SIZE - 1; i >= 0; i--)
> + llist_add(&entries[i], &llist);
> +
> + llist_for_each_safe(pos, n, llist.first) {
> + KUNIT_EXPECT_PTR_EQ(test, pos, &entries[i++]);
> + llist_del_first(&llist);
> + }
> +
> + KUNIT_EXPECT_EQ(test, ENTRIES_SIZE, i);
> + KUNIT_EXPECT_TRUE(test, llist_empty(&llist));
> +}
> +
> +static void llist_test_for_each_entry(struct kunit *test)
> +{
> + struct llist_test_struct entries[ENTRIES_SIZE], *pos;
> + LLIST_HEAD(llist);
> + int i = 0;
> +
> + for (int i = ENTRIES_SIZE - 1; i >= 0; --i) {
> + entries[i].data = i;
> + llist_add(&entries[i].node, &llist);
> + }
> +
> + i = 0;
> +
> + llist_for_each_entry(pos, llist.first, node) {
> + KUNIT_EXPECT_EQ(test, pos->data, i);
> + i++;
> + }
> +
> + KUNIT_EXPECT_EQ(test, ENTRIES_SIZE, i);
> +}
> +
> +static void llist_test_for_each_entry_safe(struct kunit *test)
> +{
> + struct llist_test_struct entries[ENTRIES_SIZE], *pos, *n;
> + LLIST_HEAD(llist);
> + int i = 0;
> +
> + for (int i = ENTRIES_SIZE - 1; i >= 0; --i) {
> + entries[i].data = i;
> + llist_add(&entries[i].node, &llist);
> + }
> +
> + i = 0;
> +
> + llist_for_each_entry_safe(pos, n, llist.first, node) {
> + KUNIT_EXPECT_EQ(test, pos->data, i++);
> + llist_del_first(&llist);
> + }
> +
> + KUNIT_EXPECT_EQ(test, ENTRIES_SIZE, i);
> + KUNIT_EXPECT_TRUE(test, llist_empty(&llist));
> +}
> +
> +static void llist_test_reverse_order(struct kunit *test)
> +{
> + struct llist_node entries[3], *pos, *reversed_llist;
Rather than using the "3" here I would prefer using the ENTRIES_SIZE.
> + LLIST_HEAD(llist);
> + int i = 0;
> +
> + llist_add(&entries[0], &llist);
> + llist_add(&entries[1], &llist);
> + llist_add(&entries[2], &llist);
> +
> + /* before [List] -> entries[2] -> entries[1] -> entries[0] */
> + reversed_llist = llist_reverse_order(llist_del_first(&llist));
> +
> + /* should be [List] -> entries[0] -> entries[1] -> entrires[2] */
Small typo in this comment: "entries"
> + llist_for_each(pos, reversed_llist) {
> + KUNIT_EXPECT_PTR_EQ(test, pos, &entries[i++]);
> + }
> +
> + KUNIT_EXPECT_EQ(test, 3, i);
Same here with the use of the "3".
> +}
> +
> +static struct kunit_case llist_test_cases[] = {
> + KUNIT_CASE(llist_test_init_llist),
> + KUNIT_CASE(llist_test_init_llist_node),
> + KUNIT_CASE(llist_test_llist_entry),
> + KUNIT_CASE(llist_test_add),
> + KUNIT_CASE(llist_test_add_batch),
> + KUNIT_CASE(llist_test_llist_next),
> + KUNIT_CASE(llist_test_empty_llist),
> + KUNIT_CASE(llist_test_llist_on_list),
> + KUNIT_CASE(llist_test_del_first),
> + KUNIT_CASE(llist_test_del_first_init),
> + KUNIT_CASE(llist_test_del_first_this),
> + KUNIT_CASE(llist_test_del_all),
> + KUNIT_CASE(llist_test_for_each),
> + KUNIT_CASE(llist_test_for_each_safe),
> + KUNIT_CASE(llist_test_for_each_entry),
> + KUNIT_CASE(llist_test_for_each_entry_safe),
> + KUNIT_CASE(llist_test_reverse_order),
> + {}
> +};
> +
> +static struct kunit_suite llist_test_suite = {
> + .name = "llist",
> + .test_cases = llist_test_cases,
> +};
> +
> +kunit_test_suite(llist_test_suite);
> +
> +MODULE_LICENSE("GPL");
> +MODULE_DESCRIPTION("KUnit tests for the llist data structure.");
> --
> 2.46.0
>
> --
> You received this message because you are subscribed to the Google Groups "KUnit Development" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to kunit-dev+unsubscribe@googlegroups.com.
> To view this discussion on the web visit https://groups.google.com/d/msgid/kunit-dev/20240903214027.77533-2-arturacb%40gmail.com.
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH v2 1/1] lib/llist_kunit.c: add KUnit tests for llist
2024-09-05 20:51 ` Rae Moar
@ 2024-09-09 21:04 ` Artur Alves Cavalcante de Barros
0 siblings, 0 replies; 4+ messages in thread
From: Artur Alves Cavalcante de Barros @ 2024-09-09 21:04 UTC (permalink / raw)
To: Rae Moar
Cc: Andrew Morton, linux-kernel, Brendan Higgins, David Gow,
linux-kselftest, kunit-dev, n, andrealmeid, vinicius,
diego.daniel.professional
On 9/5/24 5:51 PM, Rae Moar wrote:
> On Tue, Sep 3, 2024 at 5:40 PM Artur Alves <arturacb@gmail.com> wrote:
>>
>> Add KUnit tests for the llist data structure. They test the vast
>> majority of methods and macros defined in include/linux/llist.h.
>>
>> These are inspired by the existing tests for the 'list' doubly
>> linked in lib/list-test.c [1]. Each test case (llist_test_x)
>> tests the behaviour of the llist function/macro 'x'.
>>
>> [1] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/lib/list-test.c?h=v6.11-rc6
>>
>> Signed-off-by: Artur Alves <arturacb@gmail.com>
>
> Hello!
>
> Thanks for creating this new test! It looks really good and is passing
> all the tests.
>
> My main comment is that this patch is causing some checkpatch warnings:
>
> WARNING: Prefer a maximum 75 chars per line (possible unwrapped
> commit description?)
> #13:
> [1] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/lib/list-test.c?h=v6.11-rc6
>
> It's probably fine to ignore this warning as it is a link. But I might
> remove the link because it is not absolutely necessary in this case.
>
> WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
> #58:
> new file mode 100644
>
> ERROR: that open brace { should be on the previous line
> #306: FILE: lib/llist_kunit.c:249:
> +static void llist_test_for_each_safe(struct kunit *test)
> +{
>
> ERROR: that open brace { should be on the previous line
> #325: FILE: lib/llist_kunit.c:268:
> +static void llist_test_for_each_entry(struct kunit *test)
> +{
>
> ERROR: that open brace { should be on the previous line
> #346: FILE: lib/llist_kunit.c:289:
> +static void llist_test_for_each_entry_safe(struct kunit *test)
> +{
>
> These checkpatch errors are mistaken since the open brace should be
> where it is. I believe this is getting picked up because of the
> "for_each" in the test name. This was fixed for me by rewriting the
> test names: from "llist_test_for_each_safe" -> to
> "llist_test_safe_for_each", and so on for the other tests with errors.
> Sorry it's a pain to change this but I think it is a better fix than
> changing the checkpatch script.
>
>> ---
>> lib/Kconfig.debug | 11 ++
>> lib/tests/Makefile | 1 +
>> lib/tests/llist_kunit.c | 361 ++++++++++++++++++++++++++++++++++++++++
>> 3 files changed, 373 insertions(+)
>> create mode 100644 lib/tests/llist_kunit.c
>>
>> diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
>> index a30c03a66172..b2725daccc52 100644
>> --- a/lib/Kconfig.debug
>> +++ b/lib/Kconfig.debug
>> @@ -2813,6 +2813,17 @@ config USERCOPY_KUNIT_TEST
>> on the copy_to/from_user infrastructure, making sure basic
>> user/kernel boundary testing is working.
>>
>> +config LLIST_KUNIT_TEST
>> + tristate "KUnit tests for lib/llist" if !KUNIT_ALL_TESTS
>> + depends on KUNIT
>> + default KUNIT_ALL_TESTS
>> + help
>> + This option builds the "llist_kunit" test module that
>> + helps to verify the correctness of the functions and
>> + macros defined in (<linux/llist.h>).
>
> Also, I think I would prefer if this description was a bit tweaked.
> Saying it builds the "module" is confusing since this test might be
> run built-in instead. So maybe something more similar to :
>
> This builds the llist (lock-less list) KUnit test suite. It tests the
> API and basic functionality of the macros and functions defined in
> <linux/llish.h>.
>
>> +
>> + If unsure, say N.
>> +
>> config TEST_UDELAY
>> tristate "udelay test driver"
>> help
>> diff --git a/lib/tests/Makefile b/lib/tests/Makefile
>> index c6a14cc8663e..8d7c40a73110 100644
>> --- a/lib/tests/Makefile
>> +++ b/lib/tests/Makefile
>> @@ -34,4 +34,5 @@ CFLAGS_stackinit_kunit.o += $(call cc-disable-warning, switch-unreachable)
>> obj-$(CONFIG_STACKINIT_KUNIT_TEST) += stackinit_kunit.o
>> obj-$(CONFIG_STRING_KUNIT_TEST) += string_kunit.o
>> obj-$(CONFIG_STRING_HELPERS_KUNIT_TEST) += string_helpers_kunit.o
>> +obj-$(CONFIG_LLIST_KUNIT_TEST) += llist_kunit.o
>>
>> diff --git a/lib/tests/llist_kunit.c b/lib/tests/llist_kunit.c
>> new file mode 100644
>> index 000000000000..f273c0d175c7
>> --- /dev/null
>> +++ b/lib/tests/llist_kunit.c
>> @@ -0,0 +1,361 @@
>> +// SPDX-License-Identifier: GPL-2.0
>> +/*
>> + * KUnit test for the Kernel lock-less linked-list structure.
>> + *
>> + * Author: Artur Alves <arturacb@gmail.com>
>> + */
>> +
>> +#include <kunit/test.h>
>> +#include <linux/llist.h>
>> +
>> +#define ENTRIES_SIZE 3
>> +
>> +struct llist_test_struct {
>> + int data;
>> + struct llist_node node;
>> +};
>> +
>> +static void llist_test_init_llist(struct kunit *test)
>> +{
>> + /* test if the llist is correctly initialized */
>> + struct llist_head llist1 = LLIST_HEAD_INIT(llist1);
>> + LLIST_HEAD(llist2);
>> + struct llist_head llist3, *llist4, *llist5;
>> +
>> + KUNIT_EXPECT_TRUE(test, llist_empty(&llist1));
>> +
>> + KUNIT_EXPECT_TRUE(test, llist_empty(&llist2));
>> +
>> + init_llist_head(&llist3);
>> + KUNIT_EXPECT_TRUE(test, llist_empty(&llist3));
>> +
>> + llist4 = kzalloc(sizeof(*llist4), GFP_KERNEL | __GFP_NOFAIL);
>> + init_llist_head(llist4);
>> + KUNIT_EXPECT_TRUE(test, llist_empty(llist4));
>> + kfree(llist4);
>> +
>> + llist5 = kmalloc(sizeof(*llist5), GFP_KERNEL | __GFP_NOFAIL);
>> + memset(llist5, 0xFF, sizeof(*llist5));
>> + init_llist_head(llist5);
>> + KUNIT_EXPECT_TRUE(test, llist_empty(llist5));
>> + kfree(llist5);
>> +}
>> +
>> +static void llist_test_init_llist_node(struct kunit *test)
>> +{
>> + struct llist_node a;
>> +
>> + init_llist_node(&a);
>> +
>> + KUNIT_EXPECT_PTR_EQ(test, a.next, &a);
>> +}
>> +
>> +static void llist_test_llist_entry(struct kunit *test)
>> +{
>> + struct llist_test_struct test_struct, *aux;
>> + struct llist_node *llist = &test_struct.node;
>> +
>> + aux = llist_entry(llist, struct llist_test_struct, node);
>> + KUNIT_EXPECT_PTR_EQ(test, &test_struct, aux);
>> +}
>> +
>> +static void llist_test_add(struct kunit *test)
>> +{
>> + struct llist_node a, b;
>> + LLIST_HEAD(llist);
>> +
>> + init_llist_node(&a);
>> + init_llist_node(&b);
>> +
>> + /* The first assertion must be true, given that llist is empty */
>> + KUNIT_EXPECT_TRUE(test, llist_add(&a, &llist));
>> + KUNIT_EXPECT_FALSE(test, llist_add(&b, &llist));
>> +
>> + /* Should be [List] -> b -> a */
>> + KUNIT_EXPECT_PTR_EQ(test, llist.first, &b);
>> + KUNIT_EXPECT_PTR_EQ(test, b.next, &a);
>> +}
>> +
>> +static void llist_test_add_batch(struct kunit *test)
>> +{
>> + struct llist_node a, b, c;
>> + LLIST_HEAD(llist);
>> + LLIST_HEAD(llist2);
>> +
>> + init_llist_node(&a);
>> + init_llist_node(&b);
>> + init_llist_node(&c);
>> +
>> + llist_add(&a, &llist2);
>> + llist_add(&b, &llist2);
>> + llist_add(&c, &llist2);
>> +
>> + /* This assertion must be true, given that llist is empty */
>> + KUNIT_EXPECT_TRUE(test, llist_add_batch(&c, &a, &llist));
>> +
>> + /* should be [List] -> c -> b -> a */
>> + KUNIT_EXPECT_PTR_EQ(test, llist.first, &c);
>> + KUNIT_EXPECT_PTR_EQ(test, c.next, &b);
>> + KUNIT_EXPECT_PTR_EQ(test, b.next, &a);
>> +}
>> +
>> +static void llist_test_llist_next(struct kunit *test)
>> +{
>> + struct llist_node a, b;
>> + LLIST_HEAD(llist);
>> +
>> + init_llist_node(&a);
>> + init_llist_node(&b);
>> +
>> + llist_add(&a, &llist);
>> + llist_add(&b, &llist);
>> +
>> + /* should be [List] -> b -> a */
>> + KUNIT_EXPECT_PTR_EQ(test, llist_next(&b), &a);
>> + KUNIT_EXPECT_NULL(test, llist_next(&a));
>> +}
>> +
>> +static void llist_test_empty_llist(struct kunit *test)
>> +{
>> + struct llist_head llist = LLIST_HEAD_INIT(llist);
>> + struct llist_node a;
>> +
>> + KUNIT_EXPECT_TRUE(test, llist_empty(&llist));
>> +
>> + llist_add(&a, &llist);
>> +
>> + KUNIT_EXPECT_FALSE(test, llist_empty(&llist));
>> +}
>> +
>> +static void llist_test_llist_on_list(struct kunit *test)
>> +{
>> + struct llist_node a, b;
>> + LLIST_HEAD(llist);
>> +
>> + init_llist_node(&a);
>> + init_llist_node(&b);
>> +
>> + llist_add(&a, &llist);
>> +
>> + /* should be [List] -> a */
>> + KUNIT_EXPECT_TRUE(test, llist_on_list(&a));
>> + KUNIT_EXPECT_FALSE(test, llist_on_list(&b));
>> +}
>> +
>> +static void llist_test_del_first(struct kunit *test)
>> +{
>> + struct llist_node a, b, *c;
>> + LLIST_HEAD(llist);
>> +
>> + llist_add(&a, &llist);
>> + llist_add(&b, &llist);
>> +
>> + /* before: [List] -> b -> a */
>> + c = llist_del_first(&llist);
>> +
>> + /* should be [List] -> a */
>> + KUNIT_EXPECT_PTR_EQ(test, llist.first, &a);
>> +
>> + /* del must return a pointer to llist_node b
>> + * the returned pointer must be marked on list
>> + */
>> + KUNIT_EXPECT_PTR_EQ(test, c, &b);
>> + KUNIT_EXPECT_TRUE(test, llist_on_list(c));
>> +}
>> +
>> +static void llist_test_del_first_init(struct kunit *test)
>> +{
>> + struct llist_node a, *b;
>> + LLIST_HEAD(llist);
>> +
>> + llist_add(&a, &llist);
>> +
>> + b = llist_del_first_init(&llist);
>> +
>> + /* should be [List] */
>> + KUNIT_EXPECT_TRUE(test, llist_empty(&llist));
>> +
>> + /* the returned pointer must be marked out of the list */
>> + KUNIT_EXPECT_FALSE(test, llist_on_list(b));
>> +}
>> +
>> +static void llist_test_del_first_this(struct kunit *test)
>> +{
>> + struct llist_node a, b;
>> + LLIST_HEAD(llist);
>> +
>> + llist_add(&a, &llist);
>> + llist_add(&b, &llist);
>> +
>> + llist_del_first_this(&llist, &a);
>> +
>> + /* before: [List] -> b -> a */
>> +
>> + // should remove only if is the first node in the llist
>> + KUNIT_EXPECT_FALSE(test, llist_del_first_this(&llist, &a));
>> +
>> + KUNIT_EXPECT_TRUE(test, llist_del_first_this(&llist, &b));
>> +
>> + /* should be [List] -> a */
>> + KUNIT_EXPECT_PTR_EQ(test, llist.first, &a);
>> +}
>> +
>> +static void llist_test_del_all(struct kunit *test)
>> +{
>> + struct llist_node a, b;
>> + LLIST_HEAD(llist);
>> + LLIST_HEAD(empty_llist);
>> +
>> + llist_add(&a, &llist);
>> + llist_add(&b, &llist);
>> +
>> + /* deleting from a empty llist should return NULL */
>> + KUNIT_EXPECT_NULL(test, llist_del_all(&empty_llist));
>> +
>> + llist_del_all(&llist);
>> +
>> + KUNIT_EXPECT_TRUE(test, llist_empty(&llist));
>> +}
>> +
>> +static void llist_test_for_each(struct kunit *test)
>> +{
>> + struct llist_node entries[ENTRIES_SIZE] = { 0 };
>> + struct llist_node *pos, *deleted_nodes;
>> + LLIST_HEAD(llist);
>> + int i = 0;
>> +
>> + for (int i = ENTRIES_SIZE - 1; i >= 0; i--)
>> + llist_add(&entries[i], &llist);
>> +
>> + /* before [List] -> entries[0] -> ... -> entries[ENTRIES_SIZE - 1] */
>> + llist_for_each(pos, llist.first) {
>> + KUNIT_EXPECT_PTR_EQ(test, pos, &entries[i++]);
>> + }
>> +
>> + KUNIT_EXPECT_EQ(test, ENTRIES_SIZE, i);
>> +
>> + i = 0;
>
> This is super nitpicky but I think I would prefer if you set two
> variables to zero at the beginning rather than reusing "i". So: int i
> = 0, j = 0;
>
>> +
>> + /* traversing deleted nodes */
>> + deleted_nodes = llist_del_all(&llist);
>> +
>> + llist_for_each(pos, deleted_nodes) {
>> + KUNIT_EXPECT_PTR_EQ(test, pos, &entries[i++]);
>> + }
>> +
>> + KUNIT_EXPECT_EQ(test, ENTRIES_SIZE, i);
>> +}
>> +
>> +static void llist_test_for_each_safe(struct kunit *test)
>> +{
>> + struct llist_node entries[ENTRIES_SIZE] = { 0 };
>
> I'm not sure if it is necessary to initialize this to be zeros.
>
>> + struct llist_node *pos, *n;
>> + LLIST_HEAD(llist);
>> + int i = 0;
>> +
>> + for (int i = ENTRIES_SIZE - 1; i >= 0; i--)
>> + llist_add(&entries[i], &llist);
>> +
>> + llist_for_each_safe(pos, n, llist.first) {
>> + KUNIT_EXPECT_PTR_EQ(test, pos, &entries[i++]);
>> + llist_del_first(&llist);
>> + }
>> +
>> + KUNIT_EXPECT_EQ(test, ENTRIES_SIZE, i);
>> + KUNIT_EXPECT_TRUE(test, llist_empty(&llist));
>> +}
>> +
>> +static void llist_test_for_each_entry(struct kunit *test)
>> +{
>> + struct llist_test_struct entries[ENTRIES_SIZE], *pos;
>> + LLIST_HEAD(llist);
>> + int i = 0;
>> +
>> + for (int i = ENTRIES_SIZE - 1; i >= 0; --i) {
>> + entries[i].data = i;
>> + llist_add(&entries[i].node, &llist);
>> + }
>> +
>> + i = 0;
>> +
>> + llist_for_each_entry(pos, llist.first, node) {
>> + KUNIT_EXPECT_EQ(test, pos->data, i);
>> + i++;
>> + }
>> +
>> + KUNIT_EXPECT_EQ(test, ENTRIES_SIZE, i);
>> +}
>> +
>> +static void llist_test_for_each_entry_safe(struct kunit *test)
>> +{
>> + struct llist_test_struct entries[ENTRIES_SIZE], *pos, *n;
>> + LLIST_HEAD(llist);
>> + int i = 0;
>> +
>> + for (int i = ENTRIES_SIZE - 1; i >= 0; --i) {
>> + entries[i].data = i;
>> + llist_add(&entries[i].node, &llist);
>> + }
>> +
>> + i = 0;
>> +
>> + llist_for_each_entry_safe(pos, n, llist.first, node) {
>> + KUNIT_EXPECT_EQ(test, pos->data, i++);
>> + llist_del_first(&llist);
>> + }
>> +
>> + KUNIT_EXPECT_EQ(test, ENTRIES_SIZE, i);
>> + KUNIT_EXPECT_TRUE(test, llist_empty(&llist));
>> +}
>> +
>> +static void llist_test_reverse_order(struct kunit *test)
>> +{
>> + struct llist_node entries[3], *pos, *reversed_llist;
>
> Rather than using the "3" here I would prefer using the ENTRIES_SIZE.
>
>> + LLIST_HEAD(llist);
>> + int i = 0;
>> +
>> + llist_add(&entries[0], &llist);
>> + llist_add(&entries[1], &llist);
>> + llist_add(&entries[2], &llist);
>> +
>> + /* before [List] -> entries[2] -> entries[1] -> entries[0] */
>> + reversed_llist = llist_reverse_order(llist_del_first(&llist));
>> +
>> + /* should be [List] -> entries[0] -> entries[1] -> entrires[2] */
>
> Small typo in this comment: "entries"
>
>> + llist_for_each(pos, reversed_llist) {
>> + KUNIT_EXPECT_PTR_EQ(test, pos, &entries[i++]);
>> + }
>> +
>> + KUNIT_EXPECT_EQ(test, 3, i);
>
> Same here with the use of the "3".
>
>> +}
>> +
>> +static struct kunit_case llist_test_cases[] = {
>> + KUNIT_CASE(llist_test_init_llist),
>> + KUNIT_CASE(llist_test_init_llist_node),
>> + KUNIT_CASE(llist_test_llist_entry),
>> + KUNIT_CASE(llist_test_add),
>> + KUNIT_CASE(llist_test_add_batch),
>> + KUNIT_CASE(llist_test_llist_next),
>> + KUNIT_CASE(llist_test_empty_llist),
>> + KUNIT_CASE(llist_test_llist_on_list),
>> + KUNIT_CASE(llist_test_del_first),
>> + KUNIT_CASE(llist_test_del_first_init),
>> + KUNIT_CASE(llist_test_del_first_this),
>> + KUNIT_CASE(llist_test_del_all),
>> + KUNIT_CASE(llist_test_for_each),
>> + KUNIT_CASE(llist_test_for_each_safe),
>> + KUNIT_CASE(llist_test_for_each_entry),
>> + KUNIT_CASE(llist_test_for_each_entry_safe),
>> + KUNIT_CASE(llist_test_reverse_order),
>> + {}
>> +};
>> +
>> +static struct kunit_suite llist_test_suite = {
>> + .name = "llist",
>> + .test_cases = llist_test_cases,
>> +};
>> +
>> +kunit_test_suite(llist_test_suite);
>> +
>> +MODULE_LICENSE("GPL");
>> +MODULE_DESCRIPTION("KUnit tests for the llist data structure.");
>> --
>> 2.46.0
>>
>> --
>> You received this message because you are subscribed to the Google Groups "KUnit Development" group.
>> To unsubscribe from this group and stop receiving emails from it, send an email to kunit-dev+unsubscribe@googlegroups.com.
>> To view this discussion on the web visit https://groups.google.com/d/msgid/kunit-dev/20240903214027.77533-2-arturacb%40gmail.com.
Hi!
Thanks for the reply! I'm going to address these issues ASAP :)
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2024-09-09 21:04 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-09-03 21:40 [PATCH v2 0/1] Add KUnit tests for llist Artur Alves
2024-09-03 21:40 ` [PATCH v2 1/1] lib/llist_kunit.c: add " Artur Alves
2024-09-05 20:51 ` Rae Moar
2024-09-09 21:04 ` Artur Alves Cavalcante de Barros
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox