| From: Gabriela Bittencourt <gbittencourt@lkcamp.dev> |
| Subject: unicode: kunit: refactor selftest to kunit tests |
| Date: Fri, 11 Oct 2024 15:25:09 +0800 |
| |
| Refactoring 'test' functions into kunit tests, to test utf-8 support in |
| unicode subsystem. |
| |
| This allows the utf8 tests to be run alongside the KUnit test suite |
| using kunit-tool, quickly compiling and running all desired tests as |
| part of the KUnit test suite, instead of compiling the selftest module |
| and loading it. |
| |
| The refactoring kept the original testing logic intact, while adopting a |
| testing pattern across different kernel modules and leveraging KUnit's |
| benefits. |
| |
| Link: https://lkml.kernel.org/r/20241011072509.3068328-7-davidgow@google.com |
| Co-developed-by: Pedro Orlando <porlando@lkcamp.dev> |
| Signed-off-by: Pedro Orlando <porlando@lkcamp.dev> |
| Co-developed-by: Danilo Pereira <dpereira@lkcamp.dev> |
| Signed-off-by: Danilo Pereira <dpereira@lkcamp.dev> |
| Signed-off-by: Gabriela Bittencourt <gbittencourt@lkcamp.dev> |
| Signed-off-by: David Gow <davidgow@google.com> |
| Reviewed-by: David Gow <davidgow@google.com> |
| Acked-by: Shuah Khan <skhan@linuxfoundation.org> |
| Cc: Andy Shevchenko <andy@kernel.org> |
| Cc: Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com> |
| Cc: Arnd Bergmann <arnd@arndb.de> |
| Cc: Brendan Higgins <brendanhiggins@google.com> |
| Cc: Bruno Sobreira Fran=C3=A7a <brunofrancadevsec@gmail.com> |
| Cc: Charlie Jenkins <charlie@rivosinc.com> |
| Cc: Christophe Leroy <christophe.leroy@csgroup.eu> |
| Cc: Daniel Latypov <dlatypov@google.com> |
| Cc: David Howells <dhowells@redhat.com> |
| Cc: David S. Miller <davem@davemloft.net> |
| Cc: Diego Vieira <diego.daniel.professional@gmail.com> |
| Cc: Fangrui Song <maskray@google.com> |
| Cc: Geert Uytterhoeven <geert@linux-m68k.org> |
| Cc: Guenter Roeck <linux@roeck-us.net> |
| Cc: Gustavo A. R. Silva <gustavoars@kernel.org> |
| Cc: Jakub Kicinski <kuba@kernel.org> |
| Cc: Jason A. Donenfeld <Jason@zx2c4.com> |
| Cc: Kees Cook <kees@kernel.org> |
| Cc: Luis Felipe Hernandez <luis.hernandez093@gmail.com> |
| Cc: Marco Elver <elver@google.com> |
| Cc: Mark Brown <broonie@kernel.org> |
| Cc: Mark Rutland <mark.rutland@arm.com> |
| Cc: "Masami Hiramatsu (Google)" <mhiramat@kernel.org> |
| Cc: Mickaël Salaün <mic@digikod.net> |
| Cc: Nathan Chancellor <nathan@kernel.org> |
| Cc: Naveen N. Rao <naveen.n.rao@linux.ibm.com> |
| Cc: Nicolas Pitre <npitre@baylibre.com> |
| Cc: Palmer Dabbelt <palmer@rivosinc.com> |
| Cc: Rae Moar <rmoar@google.com> |
| Cc: Rasmus Villemoes <linux@rasmusvillemoes.dk> |
| Cc: Simon Horman <horms@kernel.org> |
| Cc: Stephen Rothwell <sfr@canb.auug.org.au> |
| Cc: "Steven Rostedt (Google)" <rostedt@goodmis.org> |
| Cc: Vlastimil Babka <vbabka@suse.cz> |
| Cc: Yury Norov <yury.norov@gmail.com> |
| Signed-off-by: Andrew Morton <akpm@linux-foundation.org> |
| --- |
| |
| fs/unicode/.kunitconfig | 3 |
| fs/unicode/Kconfig | 5 - |
| fs/unicode/Makefile | 2 |
| fs/unicode/utf8-norm.c | 2 |
| fs/unicode/utf8-selftest.c | 151 ++++++++++++++++------------------- |
| 5 files changed, 78 insertions(+), 85 deletions(-) |
| |
| --- a/fs/unicode/Kconfig~unicode-kunit-refactor-selftest-to-kunit-tests |
| +++ a/fs/unicode/Kconfig |
| @@ -10,6 +10,7 @@ config UNICODE |
| be a separate loadable module that gets requested only when a file |
| system actually use it. |
| |
| -config UNICODE_NORMALIZATION_SELFTEST |
| +config UNICODE_NORMALIZATION_KUNIT_TEST |
| tristate "Test UTF-8 normalization support" |
| - depends on UNICODE |
| + depends on UNICODE && KUNIT |
| + default KUNIT_ALL_TESTS |
| diff --git a/fs/unicode/.kunitconfig a/fs/unicode/.kunitconfig |
| new file mode 100644 |
| --- /dev/null |
| +++ a/fs/unicode/.kunitconfig |
| @@ -0,0 +1,3 @@ |
| +CONFIG_KUNIT=y |
| +CONFIG_UNICODE=y |
| +CONFIG_UNICODE_NORMALIZATION_KUNIT_TEST=y |
| --- a/fs/unicode/Makefile~unicode-kunit-refactor-selftest-to-kunit-tests |
| +++ a/fs/unicode/Makefile |
| @@ -4,7 +4,7 @@ ifneq ($(CONFIG_UNICODE),) |
| obj-y += unicode.o |
| endif |
| obj-$(CONFIG_UNICODE) += utf8data.o |
| -obj-$(CONFIG_UNICODE_NORMALIZATION_SELFTEST) += utf8-selftest.o |
| +obj-$(CONFIG_UNICODE_NORMALIZATION_KUNIT_TEST) += utf8-selftest.o |
| |
| unicode-y := utf8-norm.o utf8-core.o |
| |
| --- a/fs/unicode/utf8-norm.c~unicode-kunit-refactor-selftest-to-kunit-tests |
| +++ a/fs/unicode/utf8-norm.c |
| @@ -586,7 +586,7 @@ ccc_mismatch: |
| } |
| } |
| |
| -#ifdef CONFIG_UNICODE_NORMALIZATION_SELFTEST_MODULE |
| +#if IS_MODULE(CONFIG_UNICODE_NORMALIZATION_KUNIT_TEST) |
| EXPORT_SYMBOL_GPL(utf8version_is_supported); |
| EXPORT_SYMBOL_GPL(utf8nlen); |
| EXPORT_SYMBOL_GPL(utf8ncursor); |
| --- a/fs/unicode/utf8-selftest.c~unicode-kunit-refactor-selftest-to-kunit-tests |
| +++ a/fs/unicode/utf8-selftest.c |
| @@ -1,38 +1,18 @@ |
| // SPDX-License-Identifier: GPL-2.0-only |
| /* |
| - * Kernel module for testing utf-8 support. |
| + * KUnit tests for utf-8 support. |
| * |
| * Copyright 2017 Collabora Ltd. |
| */ |
| |
| -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
| - |
| -#include <linux/module.h> |
| -#include <linux/printk.h> |
| #include <linux/unicode.h> |
| -#include <linux/dcache.h> |
| +#include <kunit/test.h> |
| |
| #include "utf8n.h" |
| |
| -static unsigned int failed_tests; |
| -static unsigned int total_tests; |
| - |
| /* Tests will be based on this version. */ |
| #define UTF8_LATEST UNICODE_AGE(12, 1, 0) |
| |
| -#define _test(cond, func, line, fmt, ...) do { \ |
| - total_tests++; \ |
| - if (!cond) { \ |
| - failed_tests++; \ |
| - pr_err("test %s:%d Failed: %s%s", \ |
| - func, line, #cond, (fmt?":":".")); \ |
| - if (fmt) \ |
| - pr_err(fmt, ##__VA_ARGS__); \ |
| - } \ |
| - } while (0) |
| -#define test_f(cond, fmt, ...) _test(cond, __func__, __LINE__, fmt, ##__VA_ARGS__) |
| -#define test(cond) _test(cond, __func__, __LINE__, "") |
| - |
| static const struct { |
| /* UTF-8 strings in this vector _must_ be NULL-terminated. */ |
| unsigned char str[10]; |
| @@ -170,69 +150,74 @@ static int utf8cursor(struct utf8cursor |
| return utf8ncursor(u8c, um, n, s, (unsigned int)-1); |
| } |
| |
| -static void check_utf8_nfdi(struct unicode_map *um) |
| +static void check_utf8_nfdi(struct kunit *test) |
| { |
| int i; |
| struct utf8cursor u8c; |
| + struct unicode_map *um = test->priv; |
| |
| for (i = 0; i < ARRAY_SIZE(nfdi_test_data); i++) { |
| int len = strlen(nfdi_test_data[i].str); |
| int nlen = strlen(nfdi_test_data[i].dec); |
| int j = 0; |
| unsigned char c; |
| + int ret; |
| |
| - test((utf8len(um, UTF8_NFDI, nfdi_test_data[i].str) == nlen)); |
| - test((utf8nlen(um, UTF8_NFDI, nfdi_test_data[i].str, len) == |
| - nlen)); |
| + KUNIT_EXPECT_EQ(test, utf8len(um, UTF8_NFDI, nfdi_test_data[i].str), nlen); |
| + KUNIT_EXPECT_EQ(test, utf8nlen(um, UTF8_NFDI, nfdi_test_data[i].str, len), |
| + nlen); |
| |
| - if (utf8cursor(&u8c, um, UTF8_NFDI, nfdi_test_data[i].str) < 0) |
| - pr_err("can't create cursor\n"); |
| + |
| + ret = utf8cursor(&u8c, um, UTF8_NFDI, nfdi_test_data[i].str); |
| + KUNIT_EXPECT_TRUE_MSG(test, ret >= 0, "Can't create cursor\n"); |
| |
| while ((c = utf8byte(&u8c)) > 0) { |
| - test_f((c == nfdi_test_data[i].dec[j]), |
| - "Unexpected byte 0x%x should be 0x%x\n", |
| - c, nfdi_test_data[i].dec[j]); |
| + KUNIT_EXPECT_EQ_MSG(test, c, nfdi_test_data[i].dec[j], |
| + "Unexpected byte 0x%x should be 0x%x\n", |
| + c, nfdi_test_data[i].dec[j]); |
| j++; |
| } |
| |
| - test((j == nlen)); |
| + KUNIT_EXPECT_EQ(test, j, nlen); |
| } |
| } |
| |
| -static void check_utf8_nfdicf(struct unicode_map *um) |
| +static void check_utf8_nfdicf(struct kunit *test) |
| { |
| int i; |
| struct utf8cursor u8c; |
| + struct unicode_map *um = test->priv; |
| |
| for (i = 0; i < ARRAY_SIZE(nfdicf_test_data); i++) { |
| int len = strlen(nfdicf_test_data[i].str); |
| int nlen = strlen(nfdicf_test_data[i].ncf); |
| int j = 0; |
| + int ret; |
| unsigned char c; |
| |
| - test((utf8len(um, UTF8_NFDICF, nfdicf_test_data[i].str) == |
| - nlen)); |
| - test((utf8nlen(um, UTF8_NFDICF, nfdicf_test_data[i].str, len) == |
| - nlen)); |
| - |
| - if (utf8cursor(&u8c, um, UTF8_NFDICF, |
| - nfdicf_test_data[i].str) < 0) |
| - pr_err("can't create cursor\n"); |
| + KUNIT_EXPECT_EQ(test, utf8len(um, UTF8_NFDICF, nfdicf_test_data[i].str), |
| + nlen); |
| + KUNIT_EXPECT_EQ(test, utf8nlen(um, UTF8_NFDICF, nfdicf_test_data[i].str, len), |
| + nlen); |
| + |
| + ret = utf8cursor(&u8c, um, UTF8_NFDICF, nfdicf_test_data[i].str); |
| + KUNIT_EXPECT_TRUE_MSG(test, ret >= 0, "Can't create cursor\n"); |
| |
| while ((c = utf8byte(&u8c)) > 0) { |
| - test_f((c == nfdicf_test_data[i].ncf[j]), |
| - "Unexpected byte 0x%x should be 0x%x\n", |
| - c, nfdicf_test_data[i].ncf[j]); |
| + KUNIT_EXPECT_EQ_MSG(test, c, nfdicf_test_data[i].ncf[j], |
| + "Unexpected byte 0x%x should be 0x%x\n", |
| + c, nfdicf_test_data[i].ncf[j]); |
| j++; |
| } |
| |
| - test((j == nlen)); |
| + KUNIT_EXPECT_EQ(test, j, nlen); |
| } |
| } |
| |
| -static void check_utf8_comparisons(struct unicode_map *table) |
| +static void check_utf8_comparisons(struct kunit *test) |
| { |
| int i; |
| + struct unicode_map *um = test->priv; |
| |
| for (i = 0; i < ARRAY_SIZE(nfdi_test_data); i++) { |
| const struct qstr s1 = {.name = nfdi_test_data[i].str, |
| @@ -240,8 +225,9 @@ static void check_utf8_comparisons(struc |
| const struct qstr s2 = {.name = nfdi_test_data[i].dec, |
| .len = sizeof(nfdi_test_data[i].dec)}; |
| |
| - test_f(!utf8_strncmp(table, &s1, &s2), |
| - "%s %s comparison mismatch\n", s1.name, s2.name); |
| + /* strncmp returns 0 when strings are equal */ |
| + KUNIT_EXPECT_TRUE_MSG(test, utf8_strncmp(um, &s1, &s2) == 0, |
| + "%s %s comparison mismatch\n", s1.name, s2.name); |
| } |
| |
| for (i = 0; i < ARRAY_SIZE(nfdicf_test_data); i++) { |
| @@ -250,62 +236,65 @@ static void check_utf8_comparisons(struc |
| const struct qstr s2 = {.name = nfdicf_test_data[i].ncf, |
| .len = sizeof(nfdicf_test_data[i].ncf)}; |
| |
| - test_f(!utf8_strncasecmp(table, &s1, &s2), |
| - "%s %s comparison mismatch\n", s1.name, s2.name); |
| + /* strncasecmp returns 0 when strings are equal */ |
| + KUNIT_EXPECT_TRUE_MSG(test, utf8_strncasecmp(um, &s1, &s2) == 0, |
| + "%s %s comparison mismatch\n", s1.name, s2.name); |
| } |
| } |
| |
| -static void check_supported_versions(struct unicode_map *um) |
| +static void check_supported_versions(struct kunit *test) |
| { |
| + struct unicode_map *um = test->priv; |
| /* Unicode 7.0.0 should be supported. */ |
| - test(utf8version_is_supported(um, UNICODE_AGE(7, 0, 0))); |
| + KUNIT_EXPECT_TRUE(test, utf8version_is_supported(um, UNICODE_AGE(7, 0, 0))); |
| |
| /* Unicode 9.0.0 should be supported. */ |
| - test(utf8version_is_supported(um, UNICODE_AGE(9, 0, 0))); |
| + KUNIT_EXPECT_TRUE(test, utf8version_is_supported(um, UNICODE_AGE(9, 0, 0))); |
| |
| /* Unicode 1x.0.0 (the latest version) should be supported. */ |
| - test(utf8version_is_supported(um, UTF8_LATEST)); |
| + KUNIT_EXPECT_TRUE(test, utf8version_is_supported(um, UTF8_LATEST)); |
| |
| /* Next versions don't exist. */ |
| - test(!utf8version_is_supported(um, UNICODE_AGE(13, 0, 0))); |
| - test(!utf8version_is_supported(um, UNICODE_AGE(0, 0, 0))); |
| - test(!utf8version_is_supported(um, UNICODE_AGE(-1, -1, -1))); |
| + KUNIT_EXPECT_FALSE(test, utf8version_is_supported(um, UNICODE_AGE(13, 0, 0))); |
| + KUNIT_EXPECT_FALSE(test, utf8version_is_supported(um, UNICODE_AGE(0, 0, 0))); |
| + KUNIT_EXPECT_FALSE(test, utf8version_is_supported(um, UNICODE_AGE(-1, -1, -1))); |
| } |
| |
| -static int __init init_test_ucd(void) |
| +static struct kunit_case unicode_normalization_test_cases[] = { |
| + KUNIT_CASE(check_supported_versions), |
| + KUNIT_CASE(check_utf8_comparisons), |
| + KUNIT_CASE(check_utf8_nfdicf), |
| + KUNIT_CASE(check_utf8_nfdi), |
| + {} |
| +}; |
| + |
| +static int init_test_ucd(struct kunit *test) |
| { |
| - struct unicode_map *um; |
| + struct unicode_map *um = utf8_load(UTF8_LATEST); |
| |
| - failed_tests = 0; |
| - total_tests = 0; |
| + test->priv = um; |
| |
| - um = utf8_load(UTF8_LATEST); |
| - if (IS_ERR(um)) { |
| - pr_err("%s: Unable to load utf8 table.\n", __func__); |
| - return PTR_ERR(um); |
| - } |
| + KUNIT_EXPECT_EQ_MSG(test, IS_ERR(um), 0, |
| + "%s: Unable to load utf8 table.\n", __func__); |
| |
| - check_supported_versions(um); |
| - check_utf8_nfdi(um); |
| - check_utf8_nfdicf(um); |
| - check_utf8_comparisons(um); |
| - |
| - if (!failed_tests) |
| - pr_info("All %u tests passed\n", total_tests); |
| - else |
| - pr_err("%u out of %u tests failed\n", failed_tests, |
| - total_tests); |
| - utf8_unload(um); |
| return 0; |
| } |
| |
| -static void __exit exit_test_ucd(void) |
| +static void exit_test_ucd(struct kunit *test) |
| { |
| + utf8_unload(test->priv); |
| } |
| |
| -module_init(init_test_ucd); |
| -module_exit(exit_test_ucd); |
| +static struct kunit_suite unicode_normalization_test_suite = { |
| + .name = "unicode_normalization", |
| + .test_cases = unicode_normalization_test_cases, |
| + .init = init_test_ucd, |
| + .exit = exit_test_ucd, |
| +}; |
| + |
| +kunit_test_suite(unicode_normalization_test_suite); |
| + |
| |
| MODULE_AUTHOR("Gabriel Krisman Bertazi <krisman@collabora.co.uk>"); |
| -MODULE_DESCRIPTION("Kernel module for testing utf-8 support"); |
| +MODULE_DESCRIPTION("KUnit tests for utf-8 support."); |
| MODULE_LICENSE("GPL"); |
| _ |