This patch implements the initial Kunit based set of unit tests for HFS string operations. It checks functionality of hfs_strcmp(), hfs_hash_dentry(), and hfs_compare_dentry() methods. ./tools/testing/kunit/kunit.py run --kunitconfig ./fs/hfs/.kunitconfig [16:04:50] Configuring KUnit Kernel ... Regenerating .config ... Populating config with: $ make ARCH=um O=.kunit olddefconfig [16:04:51] Building KUnit Kernel ... Populating config with: $ make ARCH=um O=.kunit olddefconfig Building with: $ make all compile_commands.json scripts_gdb ARCH=um O=.kunit --jobs=22 [16:04:59] Starting KUnit Kernel (1/1)... [16:04:59] ============================================================ Running tests with: $ .kunit/linux kunit.enable=1 mem=1G console=tty kunit_shutdown=halt [16:04:59] ================= hfs_string (3 subtests) ================== [16:04:59] [PASSED] hfs_strcmp_test [16:04:59] [PASSED] hfs_hash_dentry_test [16:04:59] [PASSED] hfs_compare_dentry_test [16:04:59] =================== [PASSED] hfs_string ==================== [16:04:59] ============================================================ [16:04:59] Testing complete. Ran 3 tests: passed: 3 [16:04:59] Elapsed time: 9.087s total, 1.310s configuring, 7.611s building, 0.125s running v2 Fix linker error. Signed-off-by: Viacheslav Dubeyko <slava@xxxxxxxxxxx> cc: John Paul Adrian Glaubitz <glaubitz@xxxxxxxxxxxxxxxxxxx> cc: Yangtao Li <frank.li@xxxxxxxx> cc: linux-fsdevel@xxxxxxxxxxxxxxx --- fs/hfs/.kunitconfig | 7 +++ fs/hfs/Kconfig | 15 +++++ fs/hfs/Makefile | 2 + fs/hfs/string.c | 3 + fs/hfs/string_test.c | 132 +++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 159 insertions(+) create mode 100644 fs/hfs/.kunitconfig create mode 100644 fs/hfs/string_test.c diff --git a/fs/hfs/.kunitconfig b/fs/hfs/.kunitconfig new file mode 100644 index 000000000000..5caa9af1e3bb --- /dev/null +++ b/fs/hfs/.kunitconfig @@ -0,0 +1,7 @@ +CONFIG_KUNIT=y +CONFIG_HFS_FS=y +CONFIG_HFS_KUNIT_TEST=y +CONFIG_BLOCK=y +CONFIG_BUFFER_HEAD=y +CONFIG_NLS=y +CONFIG_LEGACY_DIRECT_IO=y diff --git a/fs/hfs/Kconfig b/fs/hfs/Kconfig index 5ea5cd8ecea9..7f3cbe43b4b7 100644 --- a/fs/hfs/Kconfig +++ b/fs/hfs/Kconfig @@ -13,3 +13,18 @@ config HFS_FS To compile this file system support as a module, choose M here: the module will be called hfs. + +config HFS_KUNIT_TEST + tristate "KUnit tests for HFS filesystem" if !KUNIT_ALL_TESTS + depends on HFS_FS && KUNIT + default KUNIT_ALL_TESTS + help + This builds KUnit tests for the HFS filesystem. + + KUnit tests run during boot and output the results to the debug + log in TAP format (https://testanything.org/). Only useful for + kernel devs running KUnit test harness and are not for inclusion + into a production build. + + For more information on KUnit and unit tests in general please + refer to the KUnit documentation in Documentation/dev-tools/kunit/. diff --git a/fs/hfs/Makefile b/fs/hfs/Makefile index b65459bf3dc4..a7c9ce6b4609 100644 --- a/fs/hfs/Makefile +++ b/fs/hfs/Makefile @@ -9,3 +9,5 @@ hfs-objs := bitmap.o bfind.o bnode.o brec.o btree.o \ catalog.o dir.o extent.o inode.o attr.o mdb.o \ part_tbl.o string.o super.o sysdep.o trans.o +# KUnit tests +obj-$(CONFIG_HFS_KUNIT_TEST) += string_test.o diff --git a/fs/hfs/string.c b/fs/hfs/string.c index 3912209153a8..b011c1cbdf94 100644 --- a/fs/hfs/string.c +++ b/fs/hfs/string.c @@ -65,6 +65,7 @@ int hfs_hash_dentry(const struct dentry *dentry, struct qstr *this) this->hash = end_name_hash(hash); return 0; } +EXPORT_SYMBOL_GPL(hfs_hash_dentry); /* * Compare two strings in the HFS filename character ordering @@ -87,6 +88,7 @@ int hfs_strcmp(const unsigned char *s1, unsigned int len1, } return len1 - len2; } +EXPORT_SYMBOL_GPL(hfs_strcmp); /* * Test for equality of two strings in the HFS filename character ordering. @@ -112,3 +114,4 @@ int hfs_compare_dentry(const struct dentry *dentry, } return 0; } +EXPORT_SYMBOL_GPL(hfs_compare_dentry); diff --git a/fs/hfs/string_test.c b/fs/hfs/string_test.c new file mode 100644 index 000000000000..de1928dc4ef4 --- /dev/null +++ b/fs/hfs/string_test.c @@ -0,0 +1,132 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * KUnit tests for HFS string operations + * + * Copyright (C) 2025 Viacheslav Dubeyko <slava@xxxxxxxxxxx> + */ + +#include <kunit/test.h> +#include <linux/dcache.h> +#include "hfs_fs.h" + +/* Test hfs_strcmp function */ +static void hfs_strcmp_test(struct kunit *test) +{ + /* Test equal strings */ + KUNIT_EXPECT_EQ(test, 0, hfs_strcmp("hello", 5, "hello", 5)); + KUNIT_EXPECT_EQ(test, 0, hfs_strcmp("test", 4, "test", 4)); + KUNIT_EXPECT_EQ(test, 0, hfs_strcmp("", 0, "", 0)); + + /* Test unequal strings */ + KUNIT_EXPECT_NE(test, 0, hfs_strcmp("hello", 5, "world", 5)); + KUNIT_EXPECT_NE(test, 0, hfs_strcmp("test", 4, "testing", 7)); + + /* Test different lengths */ + KUNIT_EXPECT_LT(test, hfs_strcmp("test", 4, "testing", 7), 0); + KUNIT_EXPECT_GT(test, hfs_strcmp("testing", 7, "test", 4), 0); + + /* Test case insensitive comparison (HFS should handle case) */ + KUNIT_EXPECT_EQ(test, 0, hfs_strcmp("Test", 4, "TEST", 4)); + KUNIT_EXPECT_EQ(test, 0, hfs_strcmp("hello", 5, "HELLO", 5)); + + /* Test with special characters */ + KUNIT_EXPECT_EQ(test, 0, hfs_strcmp("file.txt", 8, "file.txt", 8)); + KUNIT_EXPECT_NE(test, 0, hfs_strcmp("file.txt", 8, "file.dat", 8)); + + /* Test boundary cases */ + KUNIT_EXPECT_EQ(test, 0, hfs_strcmp("a", 1, "a", 1)); + KUNIT_EXPECT_NE(test, 0, hfs_strcmp("a", 1, "b", 1)); +} + +/* Test hfs_hash_dentry function */ +static void hfs_hash_dentry_test(struct kunit *test) +{ + struct qstr test_name1, test_name2, test_name3; + struct dentry dentry = {}; + char name1[] = "testfile"; + char name2[] = "TestFile"; + char name3[] = "different"; + + /* Initialize test strings */ + test_name1.name = name1; + test_name1.len = strlen(name1); + test_name1.hash = 0; + + test_name2.name = name2; + test_name2.len = strlen(name2); + test_name2.hash = 0; + + test_name3.name = name3; + test_name3.len = strlen(name3); + test_name3.hash = 0; + + /* Test hashing */ + KUNIT_EXPECT_EQ(test, 0, hfs_hash_dentry(&dentry, &test_name1)); + KUNIT_EXPECT_EQ(test, 0, hfs_hash_dentry(&dentry, &test_name2)); + KUNIT_EXPECT_EQ(test, 0, hfs_hash_dentry(&dentry, &test_name3)); + + /* Case insensitive names should hash the same */ + KUNIT_EXPECT_EQ(test, test_name1.hash, test_name2.hash); + + /* Different names should have different hashes */ + KUNIT_EXPECT_NE(test, test_name1.hash, test_name3.hash); +} + +/* Test hfs_compare_dentry function */ +static void hfs_compare_dentry_test(struct kunit *test) +{ + struct qstr test_name; + struct dentry dentry = {}; + char name[] = "TestFile"; + + test_name.name = name; + test_name.len = strlen(name); + + /* Test exact match */ + KUNIT_EXPECT_EQ(test, 0, hfs_compare_dentry(&dentry, 8, + "TestFile", &test_name)); + + /* Test case insensitive match */ + KUNIT_EXPECT_EQ(test, 0, hfs_compare_dentry(&dentry, 8, + "testfile", &test_name)); + KUNIT_EXPECT_EQ(test, 0, hfs_compare_dentry(&dentry, 8, + "TESTFILE", &test_name)); + + /* Test different names */ + KUNIT_EXPECT_EQ(test, 1, hfs_compare_dentry(&dentry, 8, + "DiffFile", &test_name)); + + /* Test different lengths */ + KUNIT_EXPECT_EQ(test, 1, hfs_compare_dentry(&dentry, 7, + "TestFil", &test_name)); + KUNIT_EXPECT_EQ(test, 1, hfs_compare_dentry(&dentry, 9, + "TestFiles", &test_name)); + + /* Test empty string */ + test_name.name = ""; + test_name.len = 0; + KUNIT_EXPECT_EQ(test, 0, hfs_compare_dentry(&dentry, 0, "", &test_name)); + + /* Test HFS_NAMELEN boundary */ + test_name.name = "This_is_a_very_long_filename_that_exceeds_normal_limits"; + test_name.len = strlen(test_name.name); + KUNIT_EXPECT_EQ(test, 0, hfs_compare_dentry(&dentry, HFS_NAMELEN, + "This_is_a_very_long_filename_th", &test_name)); +} + +static struct kunit_case hfs_string_test_cases[] = { + KUNIT_CASE(hfs_strcmp_test), + KUNIT_CASE(hfs_hash_dentry_test), + KUNIT_CASE(hfs_compare_dentry_test), + {} +}; + +static struct kunit_suite hfs_string_test_suite = { + .name = "hfs_string", + .test_cases = hfs_string_test_cases, +}; + +kunit_test_suite(hfs_string_test_suite); + +MODULE_DESCRIPTION("KUnit tests for HFS string operations"); +MODULE_LICENSE("GPL"); -- 2.43.0