]> Gentwo Git Trees - linux/.git/commitdiff
hfs: introduce KUnit tests for HFS string operations
authorViacheslav Dubeyko <Slava.Dubeyko@ibm.com>
Fri, 12 Sep 2025 22:50:23 +0000 (15:50 -0700)
committerViacheslav Dubeyko <slava@dubeyko.com>
Wed, 19 Nov 2025 22:53:59 +0000 (14:53 -0800)
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.

v3
Chen Linxuan suggested to use EXPORT_SYMBOL_IF_KUNIT.

Signed-off-by: Viacheslav Dubeyko <Slava.Dubeyko@ibm.com>
cc: John Paul Adrian Glaubitz <glaubitz@physik.fu-berlin.de>
cc: Yangtao Li <frank.li@vivo.com>
cc: linux-fsdevel@vger.kernel.org
cc: Chen Linxuan <me@black-desk.cn>
Reviewed-by: Chen Linxuan <me@black-desk.cn>
Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com>
Link: https://lore.kernel.org/r/20250912225022.1083313-1-slava@dubeyko.com
Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com>
fs/hfs/.kunitconfig [new file with mode: 0644]
fs/hfs/Kconfig
fs/hfs/Makefile
fs/hfs/string.c
fs/hfs/string_test.c [new file with mode: 0644]

diff --git a/fs/hfs/.kunitconfig b/fs/hfs/.kunitconfig
new file mode 100644 (file)
index 0000000..5caa9af
--- /dev/null
@@ -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
index 5ea5cd8ecea9c0323a9582721789d47c432f6e8f..7f3cbe43b4b707b244b7ae22fec8c7a390437f9d 100644 (file)
@@ -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/.
index b65459bf3dc404b2eba839ba1f047bbddfbaf122..a7c9ce6b4609242fbe0621856de5e0ef55aeaaa2 100644 (file)
@@ -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
index 3912209153a8425fd9a49f779af666cd73ef00c5..0cfa35e82abcc313151495e90c8f21a725ccdfee 100644 (file)
@@ -16,6 +16,8 @@
 #include "hfs_fs.h"
 #include <linux/dcache.h>
 
+#include <kunit/visibility.h>
+
 /*================ File-local variables ================*/
 
 /*
@@ -65,6 +67,7 @@ int hfs_hash_dentry(const struct dentry *dentry, struct qstr *this)
        this->hash = end_name_hash(hash);
        return 0;
 }
+EXPORT_SYMBOL_IF_KUNIT(hfs_hash_dentry);
 
 /*
  * Compare two strings in the HFS filename character ordering
@@ -87,6 +90,7 @@ int hfs_strcmp(const unsigned char *s1, unsigned int len1,
        }
        return len1 - len2;
 }
+EXPORT_SYMBOL_IF_KUNIT(hfs_strcmp);
 
 /*
  * Test for equality of two strings in the HFS filename character ordering.
@@ -112,3 +116,4 @@ int hfs_compare_dentry(const struct dentry *dentry,
        }
        return 0;
 }
+EXPORT_SYMBOL_IF_KUNIT(hfs_compare_dentry);
diff --git a/fs/hfs/string_test.c b/fs/hfs/string_test.c
new file mode 100644 (file)
index 0000000..e1bf6f9
--- /dev/null
@@ -0,0 +1,133 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * KUnit tests for HFS string operations
+ *
+ * Copyright (C) 2025 Viacheslav Dubeyko <slava@dubeyko.com>
+ */
+
+#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");
+MODULE_IMPORT_NS("EXPORTED_FOR_KUNIT_TESTING");