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(+) 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(); -- 2.43.0