git: 4fa275a5f357 - main - queue(3): Add simple tests for some macros for all list/tailq types
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Tue, 29 Apr 2025 07:47:24 UTC
The branch main has been updated by olce:
URL: https://cgit.FreeBSD.org/src/commit/?id=4fa275a5f35742a5d662db7106d20819329dc8f2
commit 4fa275a5f35742a5d662db7106d20819329dc8f2
Author: Olivier Certner <olce@FreeBSD.org>
AuthorDate: 2025-04-08 11:42:27 +0000
Commit: Olivier Certner <olce@FreeBSD.org>
CommitDate: 2025-04-29 07:47:02 +0000
queue(3): Add simple tests for some macros for all list/tailq types
These essentially test building a list/tailq of 100 elements with
_INSERT_HEAD(), iterating over them with _FOREACH(), splitting it with
_SPLIT_AFTER() and concatenating back the results with _CONCAT(),
checking that the lists/tailqs at each step have the right number of
elements and at the expected positions.
Reviewed by: markj
MFC after: 2 days
Sponsored by: The FreeBSD Foundation
Differential Revision: https://reviews.freebsd.org/D49975
---
tests/sys/sys/Makefile | 1 +
tests/sys/sys/queue_test.c | 235 +++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 236 insertions(+)
diff --git a/tests/sys/sys/Makefile b/tests/sys/sys/Makefile
index 40060911856f..a1b4e3234e1c 100644
--- a/tests/sys/sys/Makefile
+++ b/tests/sys/sys/Makefile
@@ -7,6 +7,7 @@ ATF_TESTS_C= arb_test \
bitstring_test \
buf_ring_test \
qmath_test \
+ queue_test \
rb_test \
splay_test \
time_test
diff --git a/tests/sys/sys/queue_test.c b/tests/sys/sys/queue_test.c
new file mode 100644
index 000000000000..75974ad8d792
--- /dev/null
+++ b/tests/sys/sys/queue_test.c
@@ -0,0 +1,235 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2025 The FreeBSD Foundation
+ *
+ * This software was developed by Olivier Certner <olce@FreeBSD.org> at
+ * Kumacom SARL under sponsorship from the FreeBSD Foundation.
+ */
+
+#include <sys/types.h>
+#define QUEUE_MACRO_DEBUG_ASSERTIONS
+#include <sys/queue.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <atf-c.h>
+
+/*
+ * General utilities.
+ */
+#define DIAG(fmt, ...) do { \
+ fprintf(stderr, "%s(): " fmt "\n", __func__, ##__VA_ARGS__); \
+} while (0)
+
+/*
+ * Common definitions and utilities.
+ *
+ * 'type' should be tailq, stailq, list or slist. 'TYPE' is 'type' in
+ * uppercase.
+ */
+
+#define QUEUE_TESTS_COMMON(type, TYPE) \
+/* \
+ * Definitions and utilities. \
+ */ \
+ \
+struct type ## _id_elem { \
+ TYPE ## _ENTRY(type ## _id_elem) ie_entry; \
+ u_int ie_id; \
+}; \
+ \
+TYPE ## _HEAD(type ## _ids, type ## _id_elem); \
+ \
+static void \
+type ## _check(const struct type ## _ids *const type, \
+ const u_int nb, const u_int id_shift); \
+ \
+/* \
+ * Creates a tailq/list with 'nb' elements with contiguous IDs \
+ * in ascending order starting at 'id_shift'. \
+ */ \
+static struct type ## _ids * \
+type ## _create(const u_int nb, const u_int id_shift) \
+{ \
+ struct type ## _ids *const type = \
+ malloc(sizeof(*type)); \
+ \
+ ATF_REQUIRE_MSG(type != NULL, \
+ "Cannot malloc " #type " head"); \
+ \
+ TYPE ## _INIT(type); \
+ for (u_int i = 0; i < nb; ++i) { \
+ struct type ## _id_elem *const e = \
+ malloc(sizeof(*e)); \
+ \
+ ATF_REQUIRE_MSG(e != NULL, \
+ "Cannot malloc " #type " element %u", i); \
+ e->ie_id = nb - 1 - i + id_shift; \
+ TYPE ## _INSERT_HEAD(type, e, ie_entry); \
+ } \
+ \
+ DIAG("Created " #type " %p with %u elements", \
+ type, nb); \
+ type ## _check(type, nb, id_shift); \
+ return (type); \
+} \
+ \
+/* Performs no check. */ \
+static void \
+type ## _destroy(struct type ## _ids *const type) \
+{ \
+ struct type ## _id_elem *e, *tmp_e; \
+ \
+ DIAG("Destroying " #type" %p", type); \
+ TYPE ## _FOREACH_SAFE(e, type, ie_entry, \
+ tmp_e) { \
+ free(e); \
+ } \
+ free(type); \
+} \
+ \
+ \
+/* Checks that some tailq/list is as produced by *_create(). */ \
+static void \
+type ## _check(const struct type ## _ids *const type, \
+ const u_int nb, const u_int id_shift) \
+{ \
+ struct type ## _id_elem *e; \
+ u_int i = 0; \
+ \
+ TYPE ## _FOREACH(e, type, ie_entry) { \
+ ATF_REQUIRE_MSG(i + 1 <= nb, \
+ #type " %p has more than %u elements", \
+ type, nb); \
+ ATF_REQUIRE_MSG(e->ie_id == i + id_shift, \
+ #type " %p element %p: Found ID %u, " \
+ "expected %u", \
+ type, e, e->ie_id, i + id_shift); \
+ ++i; \
+ } \
+ ATF_REQUIRE_MSG(i == nb, \
+ #type " %p has only %u elements, expected %u", \
+ type, i, nb); \
+} \
+ \
+/* Returns NULL if not enough elements. */ \
+static struct type ## _id_elem * \
+type ## _nth(const struct type ## _ids *const type, \
+ const u_int idx) \
+{ \
+ struct type ## _id_elem *e; \
+ u_int i = 0; \
+ \
+ TYPE ## _FOREACH(e, type, ie_entry) { \
+ if (i == idx) { \
+ DIAG(#type " %p has element %p " \
+ "(ID %u) at index %u", \
+ type, e, e->ie_id, idx); \
+ return (e); \
+ } \
+ ++i; \
+ } \
+ DIAG(#type " %p: Only %u elements, no index %u", \
+ type, i, idx); \
+ return (NULL); \
+} \
+ \
+/* \
+ * Tests. \
+ */ \
+ \
+ATF_TC(type ## _split_after_and_concat); \
+ATF_TC_HEAD(type ## _split_after_and_concat, tc) \
+{ \
+ atf_tc_set_md_var(tc, "descr", \
+ "Test " #TYPE "_SPLIT_AFTER() followed by " \
+ #TYPE "_CONCAT()"); \
+} \
+ATF_TC_BODY(type ## _split_after_and_concat, tc) \
+{ \
+ struct type ## _ids *const type = \
+ type ## _create(100, 0); \
+ struct type ## _ids rest; \
+ struct type ## _id_elem *e; \
+ \
+ e = type ## _nth(type, 49); \
+ TYPE ## _SPLIT_AFTER(type, e, &rest, ie_entry); \
+ type ## _check(type, 50, 0); \
+ type ## _check(&rest, 50, 50); \
+ QUEUE_TESTS_ ## TYPE ## _CONCAT(type, &rest); \
+ ATF_REQUIRE_MSG(TYPE ## _EMPTY(&rest), \
+ "'rest' not empty after concat"); \
+ type ## _check(type, 100, 0); \
+ type ## _destroy(type); \
+}
+
+/*
+ * Paper over the *_CONCAT() signature differences.
+ */
+
+#define QUEUE_TESTS_TAILQ_CONCAT(first, second) \
+ TAILQ_CONCAT(first, second, ie_entry)
+
+#define QUEUE_TESTS_LIST_CONCAT(first, second) \
+ LIST_CONCAT(first, second, list_id_elem, ie_entry)
+
+#define QUEUE_TESTS_STAILQ_CONCAT(first, second) \
+ STAILQ_CONCAT(first, second)
+
+#define QUEUE_TESTS_SLIST_CONCAT(first, second) \
+ SLIST_CONCAT(first, second, slist_id_elem, ie_entry)
+
+/*
+ * ATF test registration.
+ */
+
+#define QUEUE_TESTS_REGISTRATION(tp, type) \
+ ATF_TP_ADD_TC(tp, type ## _split_after_and_concat)
+
+/*
+ * Macros defining print functions.
+ *
+ * They are currently not used in the tests above, but are useful for debugging.
+ */
+
+#define QUEUE_TESTS_TQ_PRINT(type, hfp) \
+ static void \
+ type ## _print(const struct type ## _ids *const type) \
+ { \
+ printf(#type " %p: " __STRING(hfp ## _first) \
+ " = %p, " __STRING(hfp ## _last) " = %p\n", \
+ type, type->hfp ## _first, type->hfp ## _last); \
+ }
+
+#define QUEUE_TESTS_L_PRINT(type, hfp) \
+ static void \
+ type ## _print(const struct type ## _ids *const type) \
+ { \
+ printf(#type " %p: " __STRING(hfp ## _first) " = %p\n", \
+ type, type->hfp ## _first); \
+ }
+
+
+/*
+ * Meat.
+ */
+
+QUEUE_TESTS_COMMON(tailq, TAILQ);
+QUEUE_TESTS_COMMON(list, LIST);
+QUEUE_TESTS_COMMON(stailq, STAILQ);
+QUEUE_TESTS_COMMON(slist, SLIST);
+
+/*
+ * Main.
+ */
+ATF_TP_ADD_TCS(tp)
+{
+ QUEUE_TESTS_REGISTRATION(tp, tailq);
+ QUEUE_TESTS_REGISTRATION(tp, list);
+ QUEUE_TESTS_REGISTRATION(tp, stailq);
+ QUEUE_TESTS_REGISTRATION(tp, slist);
+
+ return (atf_no_error());
+}