Hi Kir,
On Wed, Jan 07, 2026 at 02:19:03PM +0900, Kir Chou wrote:
> This patch converts the existing glob selftest (lib/globtest.c) to use
> the KUnit framework (lib/tests/glob_kunit.c).
>
> The new test:
>
> - Migrates all 64 test cases from the original test to the KUnit suite.
> - Removes the custom 'verbose' module parameter as KUnit handles logging.
> - Updates Kconfig.debug and Makefile to support the new KUnit test.
> - Updates Kconfig and Makefile to remove the original selftest.
> - Updates GLOB_SELFTEST to GLOB_KUNIT_TEST for arch/m68k/configs.
>
> This commit is verified by `./tools/testing/kunit/kunit.py run`
> with the .kunit/.kunitconfig:
>
> ```
> CONFIG_KUNIT=y
> CONFIG_GLOB_KUNIT_TEST=y
> ```
>
> Signed-off-by: Kir Chou <[email protected]>
Thanks for the patch.
However, it seems you missed carrying forward David's Reviewed-by and
Geert's Acked-by tags. Please include them in the next version. If you
dropped them intentionally (e.g., due to changes in v3), please explain
why under --- line.
> ---
> v2:
> - Remove CONFIG_GLOB_KUNIT_TEST from defconfigs as it's implicitly enabled
> by CONFIG_KUNIT_ALL_TESTS. (Suggested by Geert)
> v3:
> - Move lib/glob_kunit.c to lib/tests/glob_kunit.c.
> - Update Makefile accordingly.
> ---
> arch/m68k/configs/amiga_defconfig | 1 -
> arch/m68k/configs/apollo_defconfig | 1 -
> arch/m68k/configs/atari_defconfig | 1 -
> arch/m68k/configs/bvme6000_defconfig | 1 -
> arch/m68k/configs/hp300_defconfig | 1 -
> arch/m68k/configs/mac_defconfig | 1 -
> arch/m68k/configs/multi_defconfig | 1 -
> arch/m68k/configs/mvme147_defconfig | 1 -
> arch/m68k/configs/mvme16x_defconfig | 1 -
> arch/m68k/configs/q40_defconfig | 1 -
> arch/m68k/configs/sun3_defconfig | 1 -
> arch/m68k/configs/sun3x_defconfig | 1 -
> lib/Kconfig | 13 ---
> lib/Kconfig.debug | 13 +++
> lib/Makefile | 1 -
> lib/globtest.c | 167 ---------------------------
> lib/tests/Makefile | 1 +
> lib/tests/glob_kunit.c | 122 +++++++++++++++++++
> 18 files changed, 136 insertions(+), 193 deletions(-)
> delete mode 100644 lib/globtest.c
> create mode 100644 lib/tests/glob_kunit.c
>
...
> @@ -430,19 +430,6 @@ config GLOB
> are compiling an out-of tree driver which tells you that it
> depends on this.
>
> -config GLOB_SELFTEST
> - tristate "glob self-test on init"
> - depends on GLOB
> - help
> - This option enables a simple self-test of the glob_match
> - function on startup. It is primarily useful for people
> - working on the code to ensure they haven't introduced any
> - regressions.
> -
> - It only adds a little bit of code and slows kernel boot (or
> - module load) by a small amount, so you're welcome to play with
> - it, but you probably don't need it.
> -
> #
> # Netlink attribute parsing support is select'ed if needed
> #
> diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
> index ba36939fd..e4347e145 100644
> --- a/lib/Kconfig.debug
> +++ b/lib/Kconfig.debug
> @@ -3354,6 +3354,19 @@ config PRIME_NUMBERS_KUNIT_TEST
>
> If unsure, say N
>
> +config GLOB_KUNIT_TEST
> + tristate "Glob matching test" if !KUNIT_ALL_TESTS
> + depends on KUNIT
> + default KUNIT_ALL_TESTS
> + select GLOB
The original test used depends on GLOB.
Any specific reason for switching to select GLOB?
Ideally, tests should not select functionality, to prevent increasing
the attack vector.
> + help
> + Enable this option to test the glob functions at runtime.
> +
> + This test suite verifies the correctness of glob_match() across
> various
> + scenarios, including edge cases.
> +
> + If unsure, say N
> +
> endif # RUNTIME_TESTING_MENU
>
> config ARCH_USE_MEMTEST
...
> diff --git a/lib/tests/glob_kunit.c b/lib/tests/glob_kunit.c
> new file mode 100644
> index 000000000..797e32a8c
> --- /dev/null
> +++ b/lib/tests/glob_kunit.c
> @@ -0,0 +1,122 @@
> +// SPDX-License-Identifier: GPL-2.0
The original file lib/globtest.c (and lib/glob.c) is dual-licensed
(MIT/GPL), and your MODULE_LICENSE at the end of this file also states
"Dual MIT/GPL".
However, this SPDX identifier marks the file as GPL-2.0 only.
> +/*
> + * Test cases for glob functions.
> + */
> +
> +#include <kunit/test.h>
> +#include <linux/glob.h>
> +#include <linux/module.h>
> +
> +struct glob_test_case {
> + // Pattern to match.
> + const char *pat;
> + // String to match against.
> + const char *str;
> + // Expected glob_match result, true is matched.
If you want to document the struct members, the standard kernel-doc
format [1] would be preferred over C++-style comments.
[1]:
https://origin.kernel.org/doc/html/v6.18/doc-guide/kernel-doc.html#structure-union-and-enumeration-documentation
> + bool expected;
> +};
> +
> +static const struct glob_test_case glob_test_cases[] = {
> + /* Some basic tests */
> + { .pat = "a", .str = "a", .expected = true },
> + { .pat = "a", .str = "b", .expected = false },
> + { .pat = "a", .str = "aa", .expected = false },
> + { .pat = "a", .str = "", .expected = false },
> + { .pat = "", .str = "", .expected = true },
> + { .pat = "", .str = "a", .expected = false },
> + /* Simple character class tests */
> + { .pat = "[a]", .str = "a", .expected = true },
> + { .pat = "[a]", .str = "b", .expected = false },
> + { .pat = "[!a]", .str = "a", .expected = false },
> + { .pat = "[!a]", .str = "b", .expected = true },
> + { .pat = "[ab]", .str = "a", .expected = true },
> + { .pat = "[ab]", .str = "b", .expected = true },
> + { .pat = "[ab]", .str = "c", .expected = false },
> + { .pat = "[!ab]", .str = "c", .expected = true },
> + { .pat = "[a-c]", .str = "b", .expected = true },
> + { .pat = "[a-c]", .str = "d", .expected = false },
> + /* Corner cases in character class parsing */
> + { .pat = "[a-c-e-g]", .str = "-", .expected = true },
> + { .pat = "[a-c-e-g]", .str = "d", .expected = false },
> + { .pat = "[a-c-e-g]", .str = "f", .expected = true },
> + { .pat = "[]a-ceg-ik[]", .str = "a", .expected = true },
> + { .pat = "[]a-ceg-ik[]", .str = "]", .expected = true },
> + { .pat = "[]a-ceg-ik[]", .str = "[", .expected = true },
> + { .pat = "[]a-ceg-ik[]", .str = "h", .expected = true },
> + { .pat = "[]a-ceg-ik[]", .str = "f", .expected = false },
> + { .pat = "[!]a-ceg-ik[]", .str = "h", .expected = false },
> + { .pat = "[!]a-ceg-ik[]", .str = "]", .expected = false },
> + { .pat = "[!]a-ceg-ik[]", .str = "f", .expected = true },
> + /* Simple wild cards */
> + { .pat = "?", .str = "a", .expected = true },
> + { .pat = "?", .str = "aa", .expected = false },
> + { .pat = "??", .str = "a", .expected = false },
> + { .pat = "?x?", .str = "axb", .expected = true },
> + { .pat = "?x?", .str = "abx", .expected = false },
> + { .pat = "?x?", .str = "xab", .expected = false },
> + /* Asterisk wild cards (backtracking) */
> + { .pat = "*??", .str = "a", .expected = false },
> + { .pat = "*??", .str = "ab", .expected = true },
> + { .pat = "*??", .str = "abc", .expected = true },
> + { .pat = "*??", .str = "abcd", .expected = true },
> + { .pat = "??*", .str = "a", .expected = false },
> + { .pat = "??*", .str = "ab", .expected = true },
> + { .pat = "??*", .str = "abc", .expected = true },
> + { .pat = "??*", .str = "abcd", .expected = true },
> + { .pat = "?*?", .str = "a", .expected = false },
> + { .pat = "?*?", .str = "ab", .expected = true },
> + { .pat = "?*?", .str = "abc", .expected = true },
> + { .pat = "?*?", .str = "abcd", .expected = true },
> + { .pat = "*b", .str = "b", .expected = true },
> + { .pat = "*b", .str = "ab", .expected = true },
> + { .pat = "*b", .str = "ba", .expected = false },
> + { .pat = "*b", .str = "bb", .expected = true },
> + { .pat = "*b", .str = "abb", .expected = true },
> + { .pat = "*b", .str = "bab", .expected = true },
> + { .pat = "*bc", .str = "abbc", .expected = true },
> + { .pat = "*bc", .str = "bc", .expected = true },
> + { .pat = "*bc", .str = "bbc", .expected = true },
> + { .pat = "*bc", .str = "bcbc", .expected = true },
> + /* Multiple asterisks (complex backtracking) */
> + { .pat = "*ac*", .str = "abacadaeafag", .expected = true },
> + { .pat = "*ac*ae*ag*", .str = "abacadaeafag", .expected = true },
> + { .pat = "*a*b*[bc]*[ef]*g*", .str = "abacadaeafag", .expected = true },
> + { .pat = "*a*b*[ef]*[cd]*g*", .str = "abacadaeafag", .expected = false
> },
> + { .pat = "*abcd*", .str = "abcabcabcabcdefg", .expected = true },
> + { .pat = "*ab*cd*", .str = "abcabcabcabcdefg", .expected = true },
> + { .pat = "*abcd*abcdef*", .str = "abcabcdabcdeabcdefg", .expected =
> true },
> + { .pat = "*abcd*", .str = "abcabcabcabcefg", .expected = false },
> + { .pat = "*ab*cd*", .str = "abcabcabcabcefg", .expected = false },
> +};
> +
> +static void glob_case_to_desc(const struct glob_test_case *t, char *desc)
> +{
> + snprintf(desc, KUNIT_PARAM_DESC_SIZE, "pat:\"%s\" str:\"%s\"", t->pat,
> t->str);
> +}
> +
> +KUNIT_ARRAY_PARAM(glob, glob_test_cases, glob_case_to_desc);
> +
> +static void glob_test_match(struct kunit *test)
> +{
> + const struct glob_test_case *params = test->param_value;
> +
> + KUNIT_EXPECT_EQ_MSG(test,
checkpatch.pl reports an alignment issue here:
CHECK: Alignment should match open parenthesis
#632: FILE: lib/tests/glob_kunit.c:104:
+ KUNIT_EXPECT_EQ_MSG(test,
+ glob_match(params->pat, params->str),
Regards,
Kuan-Wei
> + glob_match(params->pat, params->str),
> + params->expected,
> + "Pattern: \"%s\", String: \"%s\", Expected: %d",
> + params->pat, params->str, params->expected);
> +}
> +
> +static struct kunit_case glob_kunit_test_cases[] = {
> + KUNIT_CASE_PARAM(glob_test_match, glob_gen_params),
> + {}
> +};
> +
> +static struct kunit_suite glob_test_suite = {
> + .name = "glob",
> + .test_cases = glob_kunit_test_cases,
> +};
> +
> +kunit_test_suite(glob_test_suite);
> +MODULE_DESCRIPTION("Test cases for glob functions");
> +MODULE_LICENSE("Dual MIT/GPL");
> --
> 2.52.0.351.gbe84eed79e-goog
>
>