All of lore.kernel.org
 help / color / mirror / Atom feed
From: Marcin Bernatowicz <marcin.bernatowicz@linux.intel.com>
To: igt-dev@lists.freedesktop.org
Cc: adam.miszczak@linux.intel.com, jakub1.kolakowski@intel.com,
	lukasz.laguna@intel.com, michal.wajdeczko@intel.com,
	Marcin Bernatowicz <marcin.bernatowicz@linux.intel.com>,
	Kamil Konieczny <kamil.konieczny@linux.intel.com>
Subject: [PATCH i-g-t v2 02/10] lib/tests/igt_sysfs_choice: Add test coverage
Date: Tue, 25 Nov 2025 11:23:01 +0100	[thread overview]
Message-ID: <20251125102312.43142-3-marcin.bernatowicz@linux.intel.com> (raw)
In-Reply-To: <20251125102312.43142-1-marcin.bernatowicz@linux.intel.com>

Add unit tests exercising parsing, selection rules, intersection,
round-trip formatting, and mask conversion for igt_sysfs_choice.

Signed-off-by: Marcin Bernatowicz <marcin.bernatowicz@linux.intel.com>
Cc: Adam Miszczak <adam.miszczak@linux.intel.com>
Cc: Jakub Kolakowski <jakub1.kolakowski@intel.com>
Cc: Kamil Konieczny <kamil.konieczny@linux.intel.com>
Cc: Lukasz Laguna <lukasz.laguna@intel.com>
Cc: Michal Wajdeczko <michal.wajdeczko@intel.com>
---
 lib/tests/igt_sysfs_choice.c | 387 +++++++++++++++++++++++++++++++++++
 lib/tests/meson.build        |   1 +
 2 files changed, 388 insertions(+)
 create mode 100644 lib/tests/igt_sysfs_choice.c

diff --git a/lib/tests/igt_sysfs_choice.c b/lib/tests/igt_sysfs_choice.c
new file mode 100644
index 000000000..05b10c0d0
--- /dev/null
+++ b/lib/tests/igt_sysfs_choice.c
@@ -0,0 +1,387 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright © 2025 Intel Corporation
+ */
+#include <errno.h>
+#include "drmtest.h"
+#include "igt_core.h"
+#include "igt_sysfs_choice.h"
+
+static void assert_token(const struct igt_sysfs_choice *c,
+			 size_t idx, const char *expected)
+{
+	igt_assert_f(idx < c->num_tokens,
+		     "token index %zu out of range (num_tokens=%zu)\n",
+		     idx, c->num_tokens);
+	igt_assert(c->tokens[idx]);
+	igt_assert_f(!strcmp(c->tokens[idx], expected),
+		     "token[%zu] mismatch: got='%s' expected='%s'\n",
+		     idx, c->tokens[idx], expected);
+}
+
+static void parse_ok(const char *str, struct igt_sysfs_choice *choice)
+{
+	int ret;
+
+	ret = igt_sysfs_choice_parse(str, choice);
+	igt_assert_f(ret == 0, "parse(\"%s\") failed: %d\n", str, ret);
+}
+
+static void test_parse_basic_first_selected(void)
+{
+	struct igt_sysfs_choice c;
+
+	parse_ok("[low] normal high\n", &c);
+
+	igt_assert_eq(c.num_tokens, 3);
+	assert_token(&c, 0, "low");
+	assert_token(&c, 1, "normal");
+	assert_token(&c, 2, "high");
+
+	igt_assert_eq(c.selected, 0);
+}
+
+static void test_parse_middle_selected_whitespace(void)
+{
+	struct igt_sysfs_choice c;
+
+	parse_ok("  low   [normal]   high  \n", &c);
+
+	igt_assert_eq(c.num_tokens, 3);
+	assert_token(&c, 0, "low");
+	assert_token(&c, 1, "normal");
+	assert_token(&c, 2, "high");
+
+	igt_assert_eq(c.selected, 1);
+}
+
+static void test_parse_single_token(void)
+{
+	struct igt_sysfs_choice c;
+
+	parse_ok("[only]\n", &c);
+
+	igt_assert_eq(c.num_tokens, 1);
+	assert_token(&c, 0, "only");
+	igt_assert_eq(c.selected, 0);
+}
+
+static void test_parse_error_missing_selected(void)
+{
+	struct igt_sysfs_choice c;
+	int ret;
+
+	ret = igt_sysfs_choice_parse("low normal high\n", &c);
+	igt_assert_eq(ret, -EINVAL);
+}
+
+static void test_parse_error_multiple_selected(void)
+{
+	struct igt_sysfs_choice c;
+	int ret;
+
+	ret = igt_sysfs_choice_parse("[low] [normal] high\n", &c);
+	igt_assert_eq(ret, -EINVAL);
+
+	ret = igt_sysfs_choice_parse("low [normal] [high]\n", &c);
+	igt_assert_eq(ret, -EINVAL);
+}
+
+static void test_parse_error_unterminated_bracket(void)
+{
+	struct igt_sysfs_choice c;
+	int ret;
+
+	ret = igt_sysfs_choice_parse("[low normal high\n", &c);
+	igt_assert_eq(ret, -EINVAL);
+
+	ret = igt_sysfs_choice_parse("low [normal high]\n", &c);
+	igt_assert_eq(ret, -EINVAL);
+}
+
+static void test_parse_error_too_many_tokens(void)
+{
+	struct igt_sysfs_choice c;
+	char buf[512];
+	size_t i;
+	int len = 0;
+	int ret;
+
+	/*
+	 * Build a line with (IGT_SYSFS_CHOICE_MAX_TOKENS + 1) tokens:
+	 * "[t0] t1 t2 ... tN"
+	 */
+	len += snprintf(buf + len, sizeof(buf) - len, "[t0]");
+	for (i = 1; i < IGT_SYSFS_CHOICE_MAX_TOKENS + 1 && len < (int)sizeof(buf); i++)
+		len += snprintf(buf + len, sizeof(buf) - len, " t%zu", i);
+	len += snprintf(buf + len, sizeof(buf) - len, "\n");
+
+	ret = igt_sysfs_choice_parse(buf, &c);
+	igt_assert_eq(ret, -E2BIG);
+}
+
+static void test_selected_basic(void)
+{
+	struct igt_sysfs_choice c;
+	const char *sel;
+
+	/* selected at position 0 */
+	parse_ok("[low] normal high\n", &c);
+	sel = igt_sysfs_choice_selected(&c);
+	igt_assert(sel);
+	igt_assert(!strcmp(sel, "low"));
+
+	/* selected at position 1 */
+	parse_ok("low [normal] high\n", &c);
+	sel = igt_sysfs_choice_selected(&c);
+	igt_assert(sel);
+	igt_assert(!strcmp(sel, "normal"));
+
+	/* selected at position 2 */
+	parse_ok("low normal [high]\n", &c);
+	sel = igt_sysfs_choice_selected(&c);
+	igt_assert(sel);
+	igt_assert(!strcmp(sel, "high"));
+}
+
+static void test_selected_invalid_index(void)
+{
+	struct igt_sysfs_choice c;
+	const char *sel;
+
+	/* selected = -1 */
+	parse_ok("[only]\n", &c);
+	c.selected = -1;
+	sel = igt_sysfs_choice_selected(&c);
+	igt_assert(!sel);
+
+	/* selected >= num_tokens */
+	parse_ok("[only]\n", &c);
+	c.selected = 999;
+	sel = igt_sysfs_choice_selected(&c);
+	igt_assert(!sel);
+
+	/* empty choice */
+	memset(&c, 0, sizeof(c));
+	sel = igt_sysfs_choice_selected(&c);
+	igt_assert(!sel);
+}
+
+static void test_to_string_roundtrip(void)
+{
+	struct igt_sysfs_choice c1, c2;
+	char out[IGT_SYSFS_CHOICE_MAX_LEN];
+	const char *s;
+
+	parse_ok(" low [normal]  high \n", &c1);
+
+	s = igt_sysfs_choice_to_string(&c1, out, sizeof(out));
+	igt_assert(s == out);
+
+	/*
+	 * Expect canonical format: tokens separated by single spaces,
+	 * one [selected], no trailing newline.
+	 */
+	igt_assert_f(!strcmp(out, "low [normal] high"),
+		     "to_string produced '%s'\n", out);
+
+	/* Parse again and ensure we get the same structure. */
+	parse_ok(out, &c2);
+
+	igt_assert_eq(c2.num_tokens, 3);
+	assert_token(&c2, 0, "low");
+	assert_token(&c2, 1, "normal");
+	assert_token(&c2, 2, "high");
+	igt_assert_eq(c2.selected, 1);
+}
+
+static void test_find_basic(void)
+{
+	struct igt_sysfs_choice c;
+	int idx;
+
+	parse_ok("[low] normal high\n", &c);
+
+	idx = igt_sysfs_choice_find(&c, "low");
+	igt_assert_eq(idx, 0);
+
+	idx = igt_sysfs_choice_find(&c, "normal");
+	igt_assert_eq(idx, 1);
+
+	idx = igt_sysfs_choice_find(&c, "high");
+	igt_assert_eq(idx, 2);
+
+	idx = igt_sysfs_choice_find(&c, "ultra");
+	igt_assert_lt(idx, 0);
+}
+
+static const char *const prio_names[] = {
+	"low",
+	"normal",
+	"high",
+};
+
+static void test_to_mask_basic(void)
+{
+	struct igt_sysfs_choice c;
+	unsigned int mask = 0;
+	int selected_idx = -1;
+	int ret;
+
+	parse_ok("[low] normal high\n", &c);
+
+	ret = igt_sysfs_choice_to_mask(&c, prio_names, ARRAY_SIZE(prio_names),
+				       &mask, &selected_idx);
+	igt_assert_eq(ret, 0);
+
+	/* low | normal | high -> bits 0,1,2 set */
+	igt_assert_eq(mask, (1u << 0) | (1u << 1) | (1u << 2));
+	igt_assert_eq(selected_idx, 0);
+}
+
+static void test_to_mask_ignores_unknown(void)
+{
+	struct igt_sysfs_choice c;
+	unsigned int mask = 0;
+	int selected_idx = -1;
+	int ret;
+
+	parse_ok("[low] normal extra\n", &c);
+
+	ret = igt_sysfs_choice_to_mask(&c, prio_names, ARRAY_SIZE(prio_names),
+				       &mask, &selected_idx);
+	igt_assert_eq(ret, 0);
+
+	/* "extra" is ignored, only low + normal mapped */
+	igt_assert_eq(mask, (1u << 0) | (1u << 1));
+	igt_assert_eq(selected_idx, 0);
+}
+
+static void test_to_mask_selected_unknown(void)
+{
+	struct igt_sysfs_choice c;
+	unsigned int mask = 0;
+	int selected_idx = 123;
+	int ret;
+
+	parse_ok("low normal [extra]\n", &c);
+
+	ret = igt_sysfs_choice_to_mask(&c, prio_names, ARRAY_SIZE(prio_names),
+				       &mask, &selected_idx);
+	igt_assert_eq(ret, 0);
+
+	igt_assert_eq(mask, (1u << 0) | (1u << 1)); /* low + normal */
+	igt_assert_eq(selected_idx, -1);
+}
+
+static void test_format_mask_basic(void)
+{
+	char buf[128];
+	const char *s;
+
+	/* mask for low + normal + high, selected = normal (1) */
+	s = igt_sysfs_choice_format_mask(buf, sizeof(buf),
+					 prio_names, ARRAY_SIZE(prio_names),
+					 (1u << 0) | (1u << 1) | (1u << 2),
+					 1);
+	igt_assert(s == buf);
+	igt_assert_f(!strcmp(buf, "low [normal] high"),
+		     "format_mask produced '%s'\n", buf);
+}
+
+static void test_format_mask_empty(void)
+{
+	char buf[128];
+	const char *s;
+
+	s = igt_sysfs_choice_format_mask(buf, sizeof(buf),
+					 prio_names, ARRAY_SIZE(prio_names),
+					 0, -1);
+	igt_assert(s == buf);
+	igt_assert_eq(buf[0], '\0');
+}
+
+static void test_format_mask_unknown_bit(void)
+{
+	char buf[128];
+	const char *s;
+
+	s = igt_sysfs_choice_format_mask(buf, sizeof(buf),
+					 prio_names, ARRAY_SIZE(prio_names),
+					 (1u << 0) | (1u << 3),
+					 0);
+	igt_assert(s == buf);
+	igt_assert_f(!strcmp(buf, "[low]"),
+		     "format_mask produced '%s'\n", buf);
+}
+
+static void test_intersect_basic(void)
+{
+	struct igt_sysfs_choice a, b;
+	int ret;
+
+	parse_ok("[low] normal high\n", &a);
+	parse_ok("low [normal] ultra\n", &b);
+
+	ret = igt_sysfs_choice_intersect(&a, &b);
+	igt_assert_eq(ret, 0);
+
+	igt_assert_eq(a.num_tokens, 2);
+	assert_token(&a, 0, "low");
+	assert_token(&a, 1, "normal");
+
+	/* semantics: selected remains the original selected token if still common */
+	igt_assert_eq(a.selected, 0);
+}
+
+static void test_intersect_single_common(void)
+{
+	struct igt_sysfs_choice a, b;
+	int ret;
+
+	parse_ok("low [normal] high\n", &a);
+	parse_ok("[normal] ultra\n", &b);
+
+	ret = igt_sysfs_choice_intersect(&a, &b);
+	igt_assert_eq(ret, 0);
+
+	igt_assert_eq(a.num_tokens, 1);
+	assert_token(&a, 0, "normal");
+	igt_assert_eq(a.selected, 0);
+}
+
+static void test_intersect_no_common(void)
+{
+	struct igt_sysfs_choice a, b;
+	int ret;
+
+	parse_ok("[low] normal\n", &a);
+	parse_ok("[high] ultra\n", &b);
+
+	ret = igt_sysfs_choice_intersect(&a, &b);
+	igt_assert_eq(ret, -ENOENT);
+}
+
+igt_simple_main
+{
+	test_parse_basic_first_selected();
+	test_parse_middle_selected_whitespace();
+	test_parse_single_token();
+	test_parse_error_missing_selected();
+	test_parse_error_multiple_selected();
+	test_parse_error_unterminated_bracket();
+	test_parse_error_too_many_tokens();
+	test_selected_basic();
+	test_selected_invalid_index();
+	test_to_string_roundtrip();
+	test_find_basic();
+	test_to_mask_basic();
+	test_to_mask_ignores_unknown();
+	test_to_mask_selected_unknown();
+	test_format_mask_basic();
+	test_format_mask_empty();
+	test_format_mask_unknown_bit();
+	test_intersect_basic();
+	test_intersect_single_common();
+	test_intersect_no_common();
+}
diff --git a/lib/tests/meson.build b/lib/tests/meson.build
index 1ce19f63c..124a9ecae 100644
--- a/lib/tests/meson.build
+++ b/lib/tests/meson.build
@@ -23,6 +23,7 @@ lib_tests = [
 	'igt_simulation',
 	'igt_stats',
 	'igt_subtest_group',
+	'igt_sysfs_choice',
 	'igt_thread',
 	'igt_types',
 	'i915_perf_data_alignment',
-- 
2.43.0


  parent reply	other threads:[~2025-11-25 10:23 UTC|newest]

Thread overview: 26+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-11-25 10:22 [PATCH i-g-t v2 00/10] Xe SR-IOV admin scheduling helpers and test updates Marcin Bernatowicz
2025-11-25 10:23 ` [PATCH i-g-t v2 01/10] lib/igt_sysfs_choice: Add helpers for sysfs enumerated choice attributes Marcin Bernatowicz
2026-01-15  7:24   ` Laguna, Lukasz
2025-11-25 10:23 ` Marcin Bernatowicz [this message]
2026-01-15 10:31   ` [PATCH i-g-t v2 02/10] lib/tests/igt_sysfs_choice: Add test coverage Laguna, Lukasz
2025-11-25 10:23 ` [PATCH i-g-t v2 03/10] lib/xe/xe_sriov_provisioning: Add string conversion helpers for scheduling priority Marcin Bernatowicz
2026-01-15  7:48   ` Laguna, Lukasz
2025-11-25 10:23 ` [PATCH i-g-t v2 04/10] lib/xe/xe_sriov_provisioning: Add sched priority mask to string helper Marcin Bernatowicz
2026-01-15  8:04   ` Laguna, Lukasz
2025-11-25 10:23 ` [PATCH i-g-t v2 05/10] lib/igt_sriov_device: Add helper for PF/VF sysfs path formatting Marcin Bernatowicz
2026-01-15  8:10   ` Laguna, Lukasz
2025-11-25 10:23 ` [PATCH i-g-t v2 06/10] lib/xe/xe_sriov_admin: Add SR-IOV admin sysfs accessors Marcin Bernatowicz
2026-01-15  8:24   ` Laguna, Lukasz
2025-11-25 10:23 ` [PATCH i-g-t v2 07/10] tests/intel/xe_sriov_scheduling: Avoid assert on scheduling params restore in cleanup Marcin Bernatowicz
2026-01-15  8:25   ` Laguna, Lukasz
2025-11-25 10:23 ` [PATCH i-g-t v2 08/10] tests/intel/xe_sriov_scheduling: Prefer SR-IOV admin sysfs accessors Marcin Bernatowicz
2026-01-15  8:25   ` Laguna, Lukasz
2025-11-25 10:23 ` [PATCH i-g-t v2 09/10] tests/intel/xe_pmu: " Marcin Bernatowicz
2026-01-15  8:27   ` Laguna, Lukasz
2025-11-25 10:23 ` [PATCH i-g-t v2 10/10] tests/intel/xe_sriov_admin_profile: Add SR-IOV admin sysfs scheduling attributes tests Marcin Bernatowicz
2026-01-15 10:05   ` Laguna, Lukasz
2026-01-15 10:10   ` Laguna, Lukasz
2025-11-25 17:27 ` ✓ i915.CI.BAT: success for Xe SR-IOV admin scheduling helpers and test updates (rev2) Patchwork
2025-11-25 17:50 ` ✓ Xe.CI.BAT: " Patchwork
2025-11-25 20:25 ` ✗ Xe.CI.Full: failure " Patchwork
2025-11-26  6:39 ` ✗ i915.CI.Full: " Patchwork

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=20251125102312.43142-3-marcin.bernatowicz@linux.intel.com \
    --to=marcin.bernatowicz@linux.intel.com \
    --cc=adam.miszczak@linux.intel.com \
    --cc=igt-dev@lists.freedesktop.org \
    --cc=jakub1.kolakowski@intel.com \
    --cc=kamil.konieczny@linux.intel.com \
    --cc=lukasz.laguna@intel.com \
    --cc=michal.wajdeczko@intel.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.