[Concept,08/35] test: Add ut_asserteq_regex() for regex pattern matching

Message ID 20251210000737.180797-9-sjg@u-boot.org
State New
Headers
Series malloc: Add heap debugging commands and mcheck caller tracking |

Commit Message

Simon Glass Dec. 10, 2025, 12:06 a.m. UTC
  From: Simon Glass <simon.glass@canonical.com>

Add a new assertion macro ut_asserteq_regex() that checks if a string
matches a regular expression pattern using the SLRE library.

This is useful for tests where exact string-matching is difficult, such
as when output contains line numbers or other variable content.

Use a helper function ut_check_regex() to avoid including slre.h in the
header.

Co-developed-by: Claude <noreply@anthropic.com>
Signed-off-by: Simon Glass <simon.glass@canonical.com>
---

 doc/develop/tests_writing.rst |  5 +++++
 include/test/ut.h             | 29 +++++++++++++++++++++++++++++
 test/ut.c                     | 30 ++++++++++++++++++++++++++++++
 3 files changed, 64 insertions(+)
  

Patch

diff --git a/doc/develop/tests_writing.rst b/doc/develop/tests_writing.rst
index 31454aa4819..43756989d43 100644
--- a/doc/develop/tests_writing.rst
+++ b/doc/develop/tests_writing.rst
@@ -422,6 +422,11 @@  ut_asserteq_addr(expr1, expr2)
     Assert that two addresses (converted from pointers via map_to_sysmem())
     are equal
 
+ut_asserteq_regex(pattern, str)
+    Assert that a string matches a regular expression pattern. Uses the SLRE
+    library for regex matching. Useful when exact matching is fragile, e.g.
+    when output contains line numbers or variable content.
+
 Pointer assertions
 ~~~~~~~~~~~~~~~~~~
 
diff --git a/include/test/ut.h b/include/test/ut.h
index 70eaaea5e0e..a2b42cdf414 100644
--- a/include/test/ut.h
+++ b/include/test/ut.h
@@ -13,6 +13,9 @@ 
 #include <linux/err.h>
 #include <test/test.h>
 
+/* Size of error buffer for ut_check_regex() */
+#define UT_REGEX_ERR_SIZE	256
+
 struct unit_test_state;
 
 /**
@@ -41,6 +44,16 @@  void ut_failf(struct unit_test_state *uts, const char *fname, int line,
 	      const char *func, const char *cond, const char *fmt, ...)
 			__attribute__ ((format (__printf__, 6, 7)));
 
+/**
+ * ut_check_regex() - Check if a string matches a regex pattern
+ *
+ * @pattern: Regular expression pattern
+ * @str: String to match against
+ * @err: Buffer to hold error message on failure (UT_REGEX_ERR_SIZE bytes)
+ * Return: 0 if match, -EINVAL if pattern is invalid, -ENOENT if no match
+ */
+int ut_check_regex(const char *pattern, const char *str, char *err);
+
 /**
  * ut_check_console_line() - Check the next console line against expectations
  *
@@ -254,6 +267,22 @@  int ut_check_console_dump(struct unit_test_state *uts, int total_bytes);
 	__ret;								\
 })
 
+/* Assert that a string matches a regex pattern */
+#define ut_asserteq_regex(pattern, str) ({				\
+	const char *_pattern = (pattern), *_str = (str);		\
+	char _err[UT_REGEX_ERR_SIZE];					\
+	int __ret = 0;							\
+									\
+	__ret = ut_check_regex(_pattern, _str, _err);			\
+	if (__ret) {							\
+		ut_failf(uts, __FILE__, __LINE__, __func__,		\
+			 #pattern " matches " #str, "%s", _err);	\
+		if (!uts->soft_fail)					\
+			return CMD_RET_FAILURE;				\
+	}								\
+	__ret;								\
+})
+
 /* Assert that two memory areas are equal */
 #define ut_asserteq_mem(expr1, expr2, len) ({				\
 	const u8 *_val1 = (u8 *)(expr1), *_val2 = (u8 *)(expr2);	\
diff --git a/test/ut.c b/test/ut.c
index a16fdfb3a93..b4f2a8bf40f 100644
--- a/test/ut.c
+++ b/test/ut.c
@@ -6,7 +6,10 @@ 
  */
 
 #include <console.h>
+#include <errno.h>
 #include <malloc.h>
+#include <slre.h>
+#include <vsprintf.h>
 #ifdef CONFIG_SANDBOX
 #include <asm/state.h>
 #endif
@@ -38,6 +41,33 @@  void ut_failf(struct unit_test_state *uts, const char *fname, int line,
 	uts->cur.fail_count++;
 }
 
+int ut_check_regex(const char *pattern, const char *str, char *err)
+{
+	struct slre slre;
+
+	if (!pattern || !str) {
+		snprintf(err, UT_REGEX_ERR_SIZE,
+			 "NULL value: pattern=%s, str=%s",
+			 pattern ? pattern : "(null)",
+			 str ? str : "(null)");
+		return -EINVAL;
+	}
+
+	if (!slre_compile(&slre, pattern)) {
+		snprintf(err, UT_REGEX_ERR_SIZE,
+			 "Invalid regex '%s': %s", pattern, slre.err_str);
+		return -EINVAL;
+	}
+
+	if (!slre_match(&slre, str, strlen(str), NULL)) {
+		snprintf(err, UT_REGEX_ERR_SIZE,
+			 "No match: pattern '%s', str '%s'", pattern, str);
+		return -ENOENT;
+	}
+
+	return 0;
+}
+
 ulong ut_check_free(void)
 {
 	struct mallinfo info = mallinfo();