hfsplus: introduce KUnit tests for HFS+ string operations

This patch implements the Kunit based set of
unit tests for HFS+ string operations. It checks
functionality of hfsplus_strcasecmp(), hfsplus_strcmp(),
hfsplus_uni2asc(), hfsplus_asc2uni(), hfsplus_hash_dentry(),
and hfsplus_compare_dentry().

./tools/testing/kunit/kunit.py run --kunitconfig ./fs/hfsplus/.kunitconfig
[14:38:05] Configuring KUnit Kernel ...
[14:38:05] 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
[14:38:09] Starting KUnit Kernel (1/1)...
[14:38:09] ============================================================
Running tests with:
$ .kunit/linux kunit.enable=1 mem=1G console=tty kunit_shutdown=halt
[14:38:09] ============== hfsplus_unicode (27 subtests) ===============
[14:38:09] [PASSED] hfsplus_strcasecmp_test
[14:38:09] [PASSED] hfsplus_strcmp_test
[14:38:09] [PASSED] hfsplus_unicode_edge_cases_test
[14:38:09] [PASSED] hfsplus_unicode_boundary_test
[14:38:09] [PASSED] hfsplus_uni2asc_basic_test
[14:38:09] [PASSED] hfsplus_uni2asc_special_chars_test
[14:38:09] [PASSED] hfsplus_uni2asc_buffer_test
[14:38:09] [PASSED] hfsplus_uni2asc_corrupted_test
[14:38:09] [PASSED] hfsplus_uni2asc_edge_cases_test
[14:38:09] [PASSED] hfsplus_asc2uni_basic_test
[14:38:09] [PASSED] hfsplus_asc2uni_special_chars_test
[14:38:09] [PASSED] hfsplus_asc2uni_buffer_limits_test
[14:38:09] [PASSED] hfsplus_asc2uni_edge_cases_test
[14:38:09] [PASSED] hfsplus_asc2uni_decompose_test
[14:38:09] [PASSED] hfsplus_hash_dentry_basic_test
[14:38:09] [PASSED] hfsplus_hash_dentry_casefold_test
[14:38:09] [PASSED] hfsplus_hash_dentry_special_chars_test
[14:38:09] [PASSED] hfsplus_hash_dentry_decompose_test
[14:38:09] [PASSED] hfsplus_hash_dentry_consistency_test
[14:38:09] [PASSED] hfsplus_hash_dentry_edge_cases_test
[14:38:09] [PASSED] hfsplus_compare_dentry_basic_test
[14:38:09] [PASSED] hfsplus_compare_dentry_casefold_test
[14:38:09] [PASSED] hfsplus_compare_dentry_special_chars_test
[14:38:09] [PASSED] hfsplus_compare_dentry_length_test
[14:38:09] [PASSED] hfsplus_compare_dentry_decompose_test
[14:38:09] [PASSED] hfsplus_compare_dentry_edge_cases_test
[14:38:09] [PASSED] hfsplus_compare_dentry_combined_flags_test
[14:38:09] ================= [PASSED] hfsplus_unicode =================
[14:38:09] ============================================================
[14:38:09] Testing complete. Ran 27 tests: passed: 27
[14:38:09] Elapsed time: 3.875s total, 0.001s configuring, 3.707s building, 0.115s running

v2
Rework memory management model.

Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com>
cc: John Paul Adrian Glaubitz <glaubitz@physik.fu-berlin.de>
cc: Yangtao Li <frank.li@vivo.com>
cc: linux-fsdevel@vger.kernel.org
Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com>
This commit is contained in:
Viacheslav Dubeyko
2025-11-24 16:04:29 -08:00
parent 150ec68fa7
commit 6f84ceb985
5 changed files with 1618 additions and 3 deletions

8
fs/hfsplus/.kunitconfig Normal file
View File

@@ -0,0 +1,8 @@
CONFIG_KUNIT=y
CONFIG_HFSPLUS_FS=y
CONFIG_HFSPLUS_KUNIT_TEST=y
CONFIG_BLOCK=y
CONFIG_BUFFER_HEAD=y
CONFIG_NLS=y
CONFIG_NLS_UTF8=y
CONFIG_LEGACY_DIRECT_IO=y

View File

@@ -14,3 +14,18 @@ config HFSPLUS_FS
MacOS 8. It includes all Mac specific filesystem data such as
data forks and creator codes, but it also has several UNIX
style features such as file ownership and permissions.
config HFSPLUS_KUNIT_TEST
tristate "KUnit tests for HFS+ filesystem" if !KUNIT_ALL_TESTS
depends on HFSPLUS_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/.

View File

@@ -8,3 +8,6 @@ obj-$(CONFIG_HFSPLUS_FS) += hfsplus.o
hfsplus-objs := super.o options.o inode.o ioctl.o extents.o catalog.o dir.o btree.o \
bnode.o brec.o bfind.o tables.o unicode.o wrapper.o bitmap.o part_tbl.o \
attributes.o xattr.o xattr_user.o xattr_security.o xattr_trusted.o
# KUnit tests
obj-$(CONFIG_HFSPLUS_KUNIT_TEST) += unicode_test.o

View File

@@ -11,6 +11,9 @@
#include <linux/types.h>
#include <linux/nls.h>
#include <kunit/visibility.h>
#include "hfsplus_fs.h"
#include "hfsplus_raw.h"
@@ -72,6 +75,7 @@ int hfsplus_strcasecmp(const struct hfsplus_unistr *s1,
return 0;
}
}
EXPORT_SYMBOL_IF_KUNIT(hfsplus_strcasecmp);
/* Compare names as a sequence of 16-bit unsigned integers */
int hfsplus_strcmp(const struct hfsplus_unistr *s1,
@@ -110,7 +114,7 @@ int hfsplus_strcmp(const struct hfsplus_unistr *s1,
return len1 < len2 ? -1 :
len1 > len2 ? 1 : 0;
}
EXPORT_SYMBOL_IF_KUNIT(hfsplus_strcmp);
#define Hangul_SBase 0xac00
#define Hangul_LBase 0x1100
@@ -143,8 +147,9 @@ static u16 *hfsplus_compose_lookup(u16 *p, u16 cc)
return NULL;
}
static int hfsplus_uni2asc(struct super_block *sb, const struct hfsplus_unistr *ustr,
int max_len, char *astr, int *len_p)
static int hfsplus_uni2asc(struct super_block *sb,
const struct hfsplus_unistr *ustr,
int max_len, char *astr, int *len_p)
{
const hfsplus_unichr *ip;
struct nls_table *nls = HFSPLUS_SB(sb)->nls;
@@ -285,6 +290,7 @@ inline int hfsplus_uni2asc_str(struct super_block *sb,
{
return hfsplus_uni2asc(sb, ustr, HFSPLUS_MAX_STRLEN, astr, len_p);
}
EXPORT_SYMBOL_IF_KUNIT(hfsplus_uni2asc_str);
inline int hfsplus_uni2asc_xattr_str(struct super_block *sb,
const struct hfsplus_attr_unistr *ustr,
@@ -293,6 +299,7 @@ inline int hfsplus_uni2asc_xattr_str(struct super_block *sb,
return hfsplus_uni2asc(sb, (const struct hfsplus_unistr *)ustr,
HFSPLUS_ATTR_MAX_STRLEN, astr, len_p);
}
EXPORT_SYMBOL_IF_KUNIT(hfsplus_uni2asc_xattr_str);
/*
* Convert one or more ASCII characters into a single unicode character.
@@ -420,6 +427,7 @@ int hfsplus_asc2uni(struct super_block *sb,
return -ENAMETOOLONG;
return 0;
}
EXPORT_SYMBOL_IF_KUNIT(hfsplus_asc2uni);
/*
* Hash a string to an integer as appropriate for the HFS+ filesystem.
@@ -472,6 +480,7 @@ int hfsplus_hash_dentry(const struct dentry *dentry, struct qstr *str)
return 0;
}
EXPORT_SYMBOL_IF_KUNIT(hfsplus_hash_dentry);
/*
* Compare strings with HFS+ filename ordering.
@@ -563,3 +572,4 @@ int hfsplus_compare_dentry(const struct dentry *dentry,
return 1;
return 0;
}
EXPORT_SYMBOL_IF_KUNIT(hfsplus_compare_dentry);

1579
fs/hfsplus/unicode_test.c Normal file

File diff suppressed because it is too large Load Diff