xref: /linux/fs/hfsplus/unicode_test.c (revision 59e6295fac26b8e85c1ea859cdd89fa1e47519d7)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * KUnit tests for HFS+ Unicode string operations
4  *
5  * Copyright (C) 2025 Viacheslav Dubeyko <slava@dubeyko.com>
6  */
7 
8 #include <kunit/test.h>
9 #include <linux/nls.h>
10 #include <linux/dcache.h>
11 #include <linux/stringhash.h>
12 #include "hfsplus_fs.h"
13 
14 struct test_mock_string_env {
15 	struct hfsplus_unistr str1;
16 	struct hfsplus_unistr str2;
17 	char *buf;
18 	u32 buf_size;
19 };
20 
21 static struct test_mock_string_env *setup_mock_str_env(u32 buf_size)
22 {
23 	struct test_mock_string_env *env;
24 
25 	env = kzalloc_obj(struct test_mock_string_env);
26 	if (!env)
27 		return NULL;
28 
29 	env->buf = kzalloc(buf_size, GFP_KERNEL);
30 	if (!env->buf) {
31 		kfree(env);
32 		return NULL;
33 	}
34 
35 	env->buf_size = buf_size;
36 
37 	return env;
38 }
39 
40 static void free_mock_str_env(struct test_mock_string_env *env)
41 {
42 	kfree(env->buf);
43 	kfree(env);
44 }
45 
46 /* Helper function to create hfsplus_unistr */
47 static void create_unistr(struct hfsplus_unistr *ustr, const char *ascii_str)
48 {
49 	int len = strlen(ascii_str);
50 	int i;
51 
52 	memset(ustr->unicode, 0, sizeof(ustr->unicode));
53 
54 	ustr->length = cpu_to_be16(len);
55 	for (i = 0; i < len && i < HFSPLUS_MAX_STRLEN; i++)
56 		ustr->unicode[i] = cpu_to_be16((u16)ascii_str[i]);
57 }
58 
59 static void corrupt_unistr(struct hfsplus_unistr *ustr)
60 {
61 	ustr->length = cpu_to_be16(U16_MAX);
62 }
63 
64 /* Test hfsplus_strcasecmp function */
65 static void hfsplus_strcasecmp_test(struct kunit *test)
66 {
67 	struct test_mock_string_env *mock_env;
68 
69 	mock_env = setup_mock_str_env(HFSPLUS_MAX_STRLEN + 1);
70 	KUNIT_ASSERT_NOT_NULL(test, mock_env);
71 
72 	/* Test identical strings */
73 	create_unistr(&mock_env->str1, "hello");
74 	create_unistr(&mock_env->str2, "hello");
75 	KUNIT_EXPECT_EQ(test, 0, hfsplus_strcasecmp(&mock_env->str1,
76 						    &mock_env->str2));
77 
78 	/* Test case insensitive comparison */
79 	create_unistr(&mock_env->str1, "Hello");
80 	create_unistr(&mock_env->str2, "hello");
81 	KUNIT_EXPECT_EQ(test, 0, hfsplus_strcasecmp(&mock_env->str1,
82 						    &mock_env->str2));
83 
84 	create_unistr(&mock_env->str1, "HELLO");
85 	create_unistr(&mock_env->str2, "hello");
86 	KUNIT_EXPECT_EQ(test, 0, hfsplus_strcasecmp(&mock_env->str1,
87 						    &mock_env->str2));
88 
89 	/* Test different strings */
90 	create_unistr(&mock_env->str1, "apple");
91 	create_unistr(&mock_env->str2, "banana");
92 	KUNIT_EXPECT_LT(test, hfsplus_strcasecmp(&mock_env->str1,
93 						 &mock_env->str2), 0);
94 
95 	create_unistr(&mock_env->str1, "zebra");
96 	create_unistr(&mock_env->str2, "apple");
97 	KUNIT_EXPECT_GT(test, hfsplus_strcasecmp(&mock_env->str1,
98 						 &mock_env->str2), 0);
99 
100 	/* Test different lengths */
101 	create_unistr(&mock_env->str1, "test");
102 	create_unistr(&mock_env->str2, "testing");
103 	KUNIT_EXPECT_LT(test, hfsplus_strcasecmp(&mock_env->str1,
104 						 &mock_env->str2), 0);
105 
106 	create_unistr(&mock_env->str1, "testing");
107 	create_unistr(&mock_env->str2, "test");
108 	KUNIT_EXPECT_GT(test, hfsplus_strcasecmp(&mock_env->str1,
109 						 &mock_env->str2), 0);
110 
111 	/* Test empty strings */
112 	create_unistr(&mock_env->str1, "");
113 	create_unistr(&mock_env->str2, "");
114 	KUNIT_EXPECT_EQ(test, 0, hfsplus_strcasecmp(&mock_env->str1,
115 						    &mock_env->str2));
116 
117 	create_unistr(&mock_env->str1, "");
118 	create_unistr(&mock_env->str2, "test");
119 	KUNIT_EXPECT_LT(test, hfsplus_strcasecmp(&mock_env->str1,
120 						 &mock_env->str2), 0);
121 
122 	/* Test single characters */
123 	create_unistr(&mock_env->str1, "A");
124 	create_unistr(&mock_env->str2, "a");
125 	KUNIT_EXPECT_EQ(test, 0, hfsplus_strcasecmp(&mock_env->str1,
126 						    &mock_env->str2));
127 
128 	create_unistr(&mock_env->str1, "A");
129 	create_unistr(&mock_env->str2, "B");
130 	KUNIT_EXPECT_LT(test, hfsplus_strcasecmp(&mock_env->str1,
131 						 &mock_env->str2), 0);
132 
133 	/* Test maximum length strings */
134 	memset(mock_env->buf, 'a', HFSPLUS_MAX_STRLEN);
135 	mock_env->buf[HFSPLUS_MAX_STRLEN] = '\0';
136 	create_unistr(&mock_env->str1, mock_env->buf);
137 	create_unistr(&mock_env->str2, mock_env->buf);
138 	KUNIT_EXPECT_EQ(test, 0, hfsplus_strcasecmp(&mock_env->str1,
139 						    &mock_env->str2));
140 
141 	/* Change one character in the middle */
142 	mock_env->buf[HFSPLUS_MAX_STRLEN / 2] = 'b';
143 	create_unistr(&mock_env->str2, mock_env->buf);
144 	KUNIT_EXPECT_LT(test, hfsplus_strcasecmp(&mock_env->str1,
145 						 &mock_env->str2), 0);
146 
147 	/* Test corrupted strings */
148 	create_unistr(&mock_env->str1, "");
149 	corrupt_unistr(&mock_env->str1);
150 	create_unistr(&mock_env->str2, "");
151 	KUNIT_EXPECT_NE(test, 0, hfsplus_strcasecmp(&mock_env->str1,
152 						    &mock_env->str2));
153 
154 	create_unistr(&mock_env->str1, "");
155 	create_unistr(&mock_env->str2, "");
156 	corrupt_unistr(&mock_env->str2);
157 	KUNIT_EXPECT_NE(test, 0, hfsplus_strcasecmp(&mock_env->str1,
158 						    &mock_env->str2));
159 
160 	create_unistr(&mock_env->str1, "test");
161 	corrupt_unistr(&mock_env->str1);
162 	create_unistr(&mock_env->str2, "testing");
163 	KUNIT_EXPECT_GT(test, hfsplus_strcasecmp(&mock_env->str1,
164 						 &mock_env->str2), 0);
165 
166 	create_unistr(&mock_env->str1, "test");
167 	create_unistr(&mock_env->str2, "testing");
168 	corrupt_unistr(&mock_env->str2);
169 	KUNIT_EXPECT_LT(test, hfsplus_strcasecmp(&mock_env->str1,
170 						 &mock_env->str2), 0);
171 
172 	create_unistr(&mock_env->str1, "testing");
173 	corrupt_unistr(&mock_env->str1);
174 	create_unistr(&mock_env->str2, "test");
175 	KUNIT_EXPECT_GT(test, hfsplus_strcasecmp(&mock_env->str1,
176 						 &mock_env->str2), 0);
177 
178 	create_unistr(&mock_env->str1, "testing");
179 	create_unistr(&mock_env->str2, "test");
180 	corrupt_unistr(&mock_env->str2);
181 	KUNIT_EXPECT_LT(test, hfsplus_strcasecmp(&mock_env->str1,
182 						 &mock_env->str2), 0);
183 
184 	free_mock_str_env(mock_env);
185 }
186 
187 /* Test hfsplus_strcmp function (case-sensitive) */
188 static void hfsplus_strcmp_test(struct kunit *test)
189 {
190 	struct test_mock_string_env *mock_env;
191 
192 	mock_env = setup_mock_str_env(HFSPLUS_MAX_STRLEN + 1);
193 	KUNIT_ASSERT_NOT_NULL(test, mock_env);
194 
195 	/* Test identical strings */
196 	create_unistr(&mock_env->str1, "hello");
197 	create_unistr(&mock_env->str2, "hello");
198 	KUNIT_EXPECT_EQ(test, 0, hfsplus_strcmp(&mock_env->str1,
199 						&mock_env->str2));
200 
201 	/* Test case sensitive comparison - should NOT be equal */
202 	create_unistr(&mock_env->str1, "Hello");
203 	create_unistr(&mock_env->str2, "hello");
204 	KUNIT_EXPECT_NE(test, 0, hfsplus_strcmp(&mock_env->str1,
205 						&mock_env->str2));
206 	 /* 'H' < 'h' in Unicode */
207 	KUNIT_EXPECT_LT(test, hfsplus_strcmp(&mock_env->str1,
208 					     &mock_env->str2), 0);
209 
210 	/* Test lexicographic ordering */
211 	create_unistr(&mock_env->str1, "apple");
212 	create_unistr(&mock_env->str2, "banana");
213 	KUNIT_EXPECT_LT(test, hfsplus_strcmp(&mock_env->str1,
214 					     &mock_env->str2), 0);
215 
216 	create_unistr(&mock_env->str1, "zebra");
217 	create_unistr(&mock_env->str2, "apple");
218 	KUNIT_EXPECT_GT(test, hfsplus_strcmp(&mock_env->str1,
219 					     &mock_env->str2), 0);
220 
221 	/* Test different lengths with common prefix */
222 	create_unistr(&mock_env->str1, "test");
223 	create_unistr(&mock_env->str2, "testing");
224 	KUNIT_EXPECT_LT(test, hfsplus_strcmp(&mock_env->str1,
225 					     &mock_env->str2), 0);
226 
227 	create_unistr(&mock_env->str1, "testing");
228 	create_unistr(&mock_env->str2, "test");
229 	KUNIT_EXPECT_GT(test, hfsplus_strcmp(&mock_env->str1,
230 					     &mock_env->str2), 0);
231 
232 	/* Test empty strings */
233 	create_unistr(&mock_env->str1, "");
234 	create_unistr(&mock_env->str2, "");
235 	KUNIT_EXPECT_EQ(test, 0, hfsplus_strcmp(&mock_env->str1,
236 						&mock_env->str2));
237 
238 	/* Test maximum length strings */
239 	memset(mock_env->buf, 'a', HFSPLUS_MAX_STRLEN);
240 	mock_env->buf[HFSPLUS_MAX_STRLEN] = '\0';
241 	create_unistr(&mock_env->str1, mock_env->buf);
242 	create_unistr(&mock_env->str2, mock_env->buf);
243 	KUNIT_EXPECT_EQ(test, 0, hfsplus_strcmp(&mock_env->str1,
244 						&mock_env->str2));
245 
246 	/* Change one character in the middle */
247 	mock_env->buf[HFSPLUS_MAX_STRLEN / 2] = 'b';
248 	create_unistr(&mock_env->str2, mock_env->buf);
249 	KUNIT_EXPECT_LT(test, hfsplus_strcmp(&mock_env->str1,
250 					     &mock_env->str2), 0);
251 
252 	/* Test corrupted strings */
253 	create_unistr(&mock_env->str1, "");
254 	corrupt_unistr(&mock_env->str1);
255 	create_unistr(&mock_env->str2, "");
256 	KUNIT_EXPECT_NE(test, 0, hfsplus_strcmp(&mock_env->str1,
257 						&mock_env->str2));
258 
259 	create_unistr(&mock_env->str1, "");
260 	create_unistr(&mock_env->str2, "");
261 	corrupt_unistr(&mock_env->str2);
262 	KUNIT_EXPECT_NE(test, 0, hfsplus_strcmp(&mock_env->str1,
263 						&mock_env->str2));
264 
265 	create_unistr(&mock_env->str1, "test");
266 	corrupt_unistr(&mock_env->str1);
267 	create_unistr(&mock_env->str2, "testing");
268 	KUNIT_EXPECT_LT(test, hfsplus_strcmp(&mock_env->str1,
269 					     &mock_env->str2), 0);
270 
271 	create_unistr(&mock_env->str1, "test");
272 	create_unistr(&mock_env->str2, "testing");
273 	corrupt_unistr(&mock_env->str2);
274 	KUNIT_EXPECT_LT(test, hfsplus_strcmp(&mock_env->str1,
275 					     &mock_env->str2), 0);
276 
277 	create_unistr(&mock_env->str1, "testing");
278 	corrupt_unistr(&mock_env->str1);
279 	create_unistr(&mock_env->str2, "test");
280 	KUNIT_EXPECT_GT(test, hfsplus_strcmp(&mock_env->str1,
281 					     &mock_env->str2), 0);
282 
283 	create_unistr(&mock_env->str1, "testing");
284 	create_unistr(&mock_env->str2, "test");
285 	corrupt_unistr(&mock_env->str2);
286 	KUNIT_EXPECT_GT(test, hfsplus_strcmp(&mock_env->str1,
287 					     &mock_env->str2), 0);
288 
289 	free_mock_str_env(mock_env);
290 }
291 
292 /* Test Unicode edge cases */
293 static void hfsplus_unicode_edge_cases_test(struct kunit *test)
294 {
295 	struct test_mock_string_env *mock_env;
296 
297 	mock_env = setup_mock_str_env(HFSPLUS_MAX_STRLEN + 1);
298 	KUNIT_ASSERT_NOT_NULL(test, mock_env);
299 
300 	/* Test with special characters */
301 	mock_env->str1.length = cpu_to_be16(3);
302 	mock_env->str1.unicode[0] = cpu_to_be16(0x00E9); /* é */
303 	mock_env->str1.unicode[1] = cpu_to_be16(0x00F1); /* ñ */
304 	mock_env->str1.unicode[2] = cpu_to_be16(0x00FC); /* ü */
305 
306 	mock_env->str2.length = cpu_to_be16(3);
307 	mock_env->str2.unicode[0] = cpu_to_be16(0x00E9); /* é */
308 	mock_env->str2.unicode[1] = cpu_to_be16(0x00F1); /* ñ */
309 	mock_env->str2.unicode[2] = cpu_to_be16(0x00FC); /* ü */
310 
311 	KUNIT_EXPECT_EQ(test, 0, hfsplus_strcmp(&mock_env->str1,
312 						&mock_env->str2));
313 	KUNIT_EXPECT_EQ(test, 0, hfsplus_strcasecmp(&mock_env->str1,
314 						    &mock_env->str2));
315 
316 	/* Test with different special characters */
317 	mock_env->str2.unicode[1] = cpu_to_be16(0x00F2); /* ò */
318 	KUNIT_EXPECT_NE(test, 0, hfsplus_strcmp(&mock_env->str1,
319 						&mock_env->str2));
320 
321 	/* Test null characters within string (should be handled correctly) */
322 	mock_env->str1.length = cpu_to_be16(3);
323 	mock_env->str1.unicode[0] = cpu_to_be16('a');
324 	mock_env->str1.unicode[1] = cpu_to_be16(0x0000); /* null */
325 	mock_env->str1.unicode[2] = cpu_to_be16('b');
326 
327 	mock_env->str2.length = cpu_to_be16(3);
328 	mock_env->str2.unicode[0] = cpu_to_be16('a');
329 	mock_env->str2.unicode[1] = cpu_to_be16(0x0000); /* null */
330 	mock_env->str2.unicode[2] = cpu_to_be16('b');
331 
332 	KUNIT_EXPECT_EQ(test, 0, hfsplus_strcmp(&mock_env->str1,
333 						&mock_env->str2));
334 
335 	free_mock_str_env(mock_env);
336 }
337 
338 /* Test boundary conditions */
339 static void hfsplus_unicode_boundary_test(struct kunit *test)
340 {
341 	struct test_mock_string_env *mock_env;
342 	int i;
343 
344 	mock_env = setup_mock_str_env(HFSPLUS_MAX_STRLEN + 1);
345 	KUNIT_ASSERT_NOT_NULL(test, mock_env);
346 
347 	/* Test maximum length boundary */
348 	mock_env->str1.length = cpu_to_be16(HFSPLUS_MAX_STRLEN);
349 	mock_env->str2.length = cpu_to_be16(HFSPLUS_MAX_STRLEN);
350 
351 	for (i = 0; i < HFSPLUS_MAX_STRLEN; i++) {
352 		mock_env->str1.unicode[i] = cpu_to_be16('A');
353 		mock_env->str2.unicode[i] = cpu_to_be16('A');
354 	}
355 
356 	KUNIT_EXPECT_EQ(test, 0, hfsplus_strcmp(&mock_env->str1,
357 						&mock_env->str2));
358 
359 	/* Change last character */
360 	mock_env->str2.unicode[HFSPLUS_MAX_STRLEN - 1] = cpu_to_be16('B');
361 	KUNIT_EXPECT_LT(test, hfsplus_strcmp(&mock_env->str1,
362 					     &mock_env->str2), 0);
363 
364 	/* Test zero length strings */
365 	mock_env->str1.length = cpu_to_be16(0);
366 	mock_env->str2.length = cpu_to_be16(0);
367 	KUNIT_EXPECT_EQ(test, 0, hfsplus_strcmp(&mock_env->str1,
368 						&mock_env->str2));
369 	KUNIT_EXPECT_EQ(test, 0, hfsplus_strcasecmp(&mock_env->str1,
370 						    &mock_env->str2));
371 
372 	/* Test one character vs empty */
373 	mock_env->str1.length = cpu_to_be16(1);
374 	mock_env->str1.unicode[0] = cpu_to_be16('A');
375 	mock_env->str2.length = cpu_to_be16(0);
376 	KUNIT_EXPECT_GT(test, hfsplus_strcmp(&mock_env->str1,
377 					     &mock_env->str2), 0);
378 	KUNIT_EXPECT_GT(test, hfsplus_strcasecmp(&mock_env->str1,
379 						 &mock_env->str2), 0);
380 
381 	free_mock_str_env(mock_env);
382 }
383 
384 /* Mock superblock and NLS table for testing hfsplus_uni2asc */
385 struct test_mock_sb {
386 	struct nls_table nls;
387 	struct hfsplus_sb_info sb_info;
388 	struct super_block sb;
389 };
390 
391 static struct test_mock_sb *setup_mock_sb(void)
392 {
393 	struct test_mock_sb *ptr;
394 
395 	ptr = kzalloc_obj(struct test_mock_sb);
396 	if (!ptr)
397 		return NULL;
398 
399 	ptr->nls.charset = "utf8";
400 	ptr->nls.uni2char = NULL; /* Will use default behavior */
401 	ptr->sb_info.nls = &ptr->nls;
402 	ptr->sb.s_fs_info = &ptr->sb_info;
403 
404 	/* Set default flags - no decomposition, no case folding */
405 	clear_bit(HFSPLUS_SB_NODECOMPOSE, &ptr->sb_info.flags);
406 	clear_bit(HFSPLUS_SB_CASEFOLD, &ptr->sb_info.flags);
407 
408 	return ptr;
409 }
410 
411 static void free_mock_sb(struct test_mock_sb *ptr)
412 {
413 	kfree(ptr);
414 }
415 
416 /* Simple uni2char implementation for testing */
417 static int test_uni2char(wchar_t uni, unsigned char *out, int boundlen)
418 {
419 	if (boundlen <= 0)
420 		return -ENAMETOOLONG;
421 
422 	if (uni < 0x80) {
423 		*out = (unsigned char)uni;
424 		return 1;
425 	}
426 
427 	/* For non-ASCII, just use '?' as fallback */
428 	*out = '?';
429 	return 1;
430 }
431 
432 /* Test hfsplus_uni2asc basic functionality */
433 static void hfsplus_uni2asc_basic_test(struct kunit *test)
434 {
435 	struct test_mock_sb *mock_sb;
436 	struct test_mock_string_env *mock_env;
437 	int len, result;
438 
439 	mock_env = setup_mock_str_env(HFSPLUS_MAX_STRLEN + 1);
440 	KUNIT_ASSERT_NOT_NULL(test, mock_env);
441 
442 	mock_sb = setup_mock_sb();
443 	KUNIT_ASSERT_NOT_NULL(test, mock_sb);
444 
445 	mock_sb->nls.uni2char = test_uni2char;
446 
447 	/* Test simple ASCII string conversion */
448 	create_unistr(&mock_env->str1, "hello");
449 	len = mock_env->buf_size;
450 	result = hfsplus_uni2asc_str(&mock_sb->sb, &mock_env->str1,
451 				     mock_env->buf, &len);
452 
453 	KUNIT_EXPECT_EQ(test, 0, result);
454 	KUNIT_EXPECT_EQ(test, 5, len);
455 	KUNIT_EXPECT_STREQ(test, "hello", mock_env->buf);
456 
457 	/* Test empty string */
458 	create_unistr(&mock_env->str1, "");
459 	len = mock_env->buf_size;
460 	result = hfsplus_uni2asc_str(&mock_sb->sb, &mock_env->str1,
461 				     mock_env->buf, &len);
462 
463 	KUNIT_EXPECT_EQ(test, 0, result);
464 	KUNIT_EXPECT_EQ(test, 0, len);
465 
466 	/* Test single character */
467 	create_unistr(&mock_env->str1, "A");
468 	len = mock_env->buf_size;
469 	result = hfsplus_uni2asc_str(&mock_sb->sb, &mock_env->str1,
470 				     mock_env->buf, &len);
471 
472 	KUNIT_EXPECT_EQ(test, 0, result);
473 	KUNIT_EXPECT_EQ(test, 1, len);
474 	KUNIT_EXPECT_EQ(test, 'A', mock_env->buf[0]);
475 
476 	free_mock_str_env(mock_env);
477 	free_mock_sb(mock_sb);
478 }
479 
480 /* Test special character handling */
481 static void hfsplus_uni2asc_special_chars_test(struct kunit *test)
482 {
483 	struct test_mock_sb *mock_sb;
484 	struct test_mock_string_env *mock_env;
485 	int len, result;
486 
487 	mock_env = setup_mock_str_env(HFSPLUS_MAX_STRLEN + 1);
488 	KUNIT_ASSERT_NOT_NULL(test, mock_env);
489 
490 	mock_sb = setup_mock_sb();
491 	KUNIT_ASSERT_NOT_NULL(test, mock_sb);
492 
493 	mock_sb->nls.uni2char = test_uni2char;
494 
495 	/* Test null character conversion (should become 0x2400) */
496 	mock_env->str1.length = cpu_to_be16(1);
497 	mock_env->str1.unicode[0] = cpu_to_be16(0x0000);
498 	len = mock_env->buf_size;
499 	result = hfsplus_uni2asc_str(&mock_sb->sb, &mock_env->str1,
500 				     mock_env->buf, &len);
501 
502 	KUNIT_EXPECT_EQ(test, 0, result);
503 	KUNIT_EXPECT_EQ(test, 1, len);
504 	/* Our test implementation returns '?' for non-ASCII */
505 	KUNIT_EXPECT_EQ(test, '?', mock_env->buf[0]);
506 
507 	/* Test forward slash conversion (should become colon) */
508 	mock_env->str1.length = cpu_to_be16(1);
509 	mock_env->str1.unicode[0] = cpu_to_be16('/');
510 	len = mock_env->buf_size;
511 	result = hfsplus_uni2asc_str(&mock_sb->sb, &mock_env->str1,
512 				     mock_env->buf, &len);
513 
514 	KUNIT_EXPECT_EQ(test, 0, result);
515 	KUNIT_EXPECT_EQ(test, 1, len);
516 	KUNIT_EXPECT_EQ(test, ':', mock_env->buf[0]);
517 
518 	/* Test string with mixed special characters */
519 	mock_env->str1.length = cpu_to_be16(3);
520 	mock_env->str1.unicode[0] = cpu_to_be16('a');
521 	mock_env->str1.unicode[1] = cpu_to_be16('/');
522 	mock_env->str1.unicode[2] = cpu_to_be16('b');
523 	len = mock_env->buf_size;
524 	result = hfsplus_uni2asc_str(&mock_sb->sb, &mock_env->str1,
525 				     mock_env->buf, &len);
526 
527 	KUNIT_EXPECT_EQ(test, 0, result);
528 	KUNIT_EXPECT_EQ(test, 3, len);
529 	KUNIT_EXPECT_EQ(test, 'a', mock_env->buf[0]);
530 	KUNIT_EXPECT_EQ(test, ':', mock_env->buf[1]);
531 	KUNIT_EXPECT_EQ(test, 'b', mock_env->buf[2]);
532 
533 	free_mock_str_env(mock_env);
534 	free_mock_sb(mock_sb);
535 }
536 
537 /* Test buffer length handling */
538 static void hfsplus_uni2asc_buffer_test(struct kunit *test)
539 {
540 	struct test_mock_sb *mock_sb;
541 	struct test_mock_string_env *mock_env;
542 	int len, result;
543 
544 	mock_env = setup_mock_str_env(10);
545 	KUNIT_ASSERT_NOT_NULL(test, mock_env);
546 
547 	mock_sb = setup_mock_sb();
548 	KUNIT_ASSERT_NOT_NULL(test, mock_sb);
549 
550 	mock_sb->nls.uni2char = test_uni2char;
551 
552 	/* Test insufficient buffer space */
553 	create_unistr(&mock_env->str1, "toolongstring");
554 	len = 5; /* Buffer too small */
555 	result = hfsplus_uni2asc_str(&mock_sb->sb, &mock_env->str1,
556 				     mock_env->buf, &len);
557 
558 	KUNIT_EXPECT_EQ(test, -ENAMETOOLONG, result);
559 	KUNIT_EXPECT_EQ(test, 5, len); /* Should be set to consumed length */
560 
561 	/* Test exact buffer size */
562 	create_unistr(&mock_env->str1, "exact");
563 	len = 5;
564 	result = hfsplus_uni2asc_str(&mock_sb->sb, &mock_env->str1,
565 				     mock_env->buf, &len);
566 
567 	KUNIT_EXPECT_EQ(test, 0, result);
568 	KUNIT_EXPECT_EQ(test, 5, len);
569 
570 	/* Test zero length buffer */
571 	create_unistr(&mock_env->str1, "test");
572 	len = 0;
573 	result = hfsplus_uni2asc_str(&mock_sb->sb, &mock_env->str1,
574 				     mock_env->buf, &len);
575 
576 	KUNIT_EXPECT_EQ(test, -ENAMETOOLONG, result);
577 	KUNIT_EXPECT_EQ(test, 0, len);
578 
579 	free_mock_str_env(mock_env);
580 	free_mock_sb(mock_sb);
581 }
582 
583 /* Test corrupted unicode string handling */
584 static void hfsplus_uni2asc_corrupted_test(struct kunit *test)
585 {
586 	struct test_mock_sb *mock_sb;
587 	struct test_mock_string_env *mock_env;
588 	int len, result;
589 
590 	mock_env = setup_mock_str_env(HFSPLUS_MAX_STRLEN + 1);
591 	KUNIT_ASSERT_NOT_NULL(test, mock_env);
592 
593 	mock_sb = setup_mock_sb();
594 	KUNIT_ASSERT_NOT_NULL(test, mock_sb);
595 
596 	mock_sb->nls.uni2char = test_uni2char;
597 
598 	/* Test corrupted length (too large) */
599 	create_unistr(&mock_env->str1, "test");
600 	corrupt_unistr(&mock_env->str1); /* Sets length to U16_MAX */
601 	len = mock_env->buf_size;
602 
603 	result = hfsplus_uni2asc_str(&mock_sb->sb, &mock_env->str1,
604 				     mock_env->buf, &len);
605 
606 	/* Should still work but with corrected length */
607 	KUNIT_EXPECT_EQ(test, 0, result);
608 	/*
609 	 * Length should be corrected to HFSPLUS_MAX_STRLEN
610 	 * and processed accordingly
611 	 */
612 	KUNIT_EXPECT_GT(test, len, 0);
613 
614 	free_mock_str_env(mock_env);
615 	free_mock_sb(mock_sb);
616 }
617 
618 /* Test edge cases and boundary conditions */
619 static void hfsplus_uni2asc_edge_cases_test(struct kunit *test)
620 {
621 	struct test_mock_sb *mock_sb;
622 	struct test_mock_string_env *mock_env;
623 	int len, result;
624 	int i;
625 
626 	mock_env = setup_mock_str_env(HFSPLUS_MAX_STRLEN * 2);
627 	KUNIT_ASSERT_NOT_NULL(test, mock_env);
628 
629 	mock_sb = setup_mock_sb();
630 	KUNIT_ASSERT_NOT_NULL(test, mock_sb);
631 
632 	mock_sb->nls.uni2char = test_uni2char;
633 
634 	/* Test maximum length string */
635 	mock_env->str1.length = cpu_to_be16(HFSPLUS_MAX_STRLEN);
636 	for (i = 0; i < HFSPLUS_MAX_STRLEN; i++)
637 		mock_env->str1.unicode[i] = cpu_to_be16('a');
638 
639 	len = mock_env->buf_size;
640 	result = hfsplus_uni2asc_str(&mock_sb->sb, &mock_env->str1,
641 				     mock_env->buf, &len);
642 
643 	KUNIT_EXPECT_EQ(test, 0, result);
644 	KUNIT_EXPECT_EQ(test, HFSPLUS_MAX_STRLEN, len);
645 
646 	/* Verify all characters are 'a' */
647 	for (i = 0; i < HFSPLUS_MAX_STRLEN; i++)
648 		KUNIT_EXPECT_EQ(test, 'a', mock_env->buf[i]);
649 
650 	/* Test string with high Unicode values (non-ASCII) */
651 	mock_env->str1.length = cpu_to_be16(3);
652 	mock_env->str1.unicode[0] = cpu_to_be16(0x00E9); /* é */
653 	mock_env->str1.unicode[1] = cpu_to_be16(0x00F1); /* ñ */
654 	mock_env->str1.unicode[2] = cpu_to_be16(0x00FC); /* ü */
655 	len = mock_env->buf_size;
656 	result = hfsplus_uni2asc_str(&mock_sb->sb, &mock_env->str1,
657 				     mock_env->buf, &len);
658 
659 	KUNIT_EXPECT_EQ(test, 0, result);
660 	KUNIT_EXPECT_EQ(test, 3, len);
661 	/* Our test implementation converts non-ASCII to '?' */
662 	KUNIT_EXPECT_EQ(test, '?', mock_env->buf[0]);
663 	KUNIT_EXPECT_EQ(test, '?', mock_env->buf[1]);
664 	KUNIT_EXPECT_EQ(test, '?', mock_env->buf[2]);
665 
666 	free_mock_str_env(mock_env);
667 	free_mock_sb(mock_sb);
668 }
669 
670 /* Simple char2uni implementation for testing */
671 static int test_char2uni(const unsigned char *rawstring,
672 			 int boundlen, wchar_t *uni)
673 {
674 	if (boundlen <= 0)
675 		return -EINVAL;
676 
677 	*uni = (wchar_t)*rawstring;
678 	return 1;
679 }
680 
681 /* Helper function to check unicode string contents */
682 static void check_unistr_content(struct kunit *test,
683 				 struct hfsplus_unistr *ustr,
684 				 const char *expected_ascii)
685 {
686 	int expected_len = strlen(expected_ascii);
687 	int actual_len = be16_to_cpu(ustr->length);
688 	int i;
689 
690 	KUNIT_EXPECT_EQ(test, expected_len, actual_len);
691 
692 	for (i = 0; i < expected_len && i < actual_len; i++) {
693 		u16 expected_char = (u16)expected_ascii[i];
694 		u16 actual_char = be16_to_cpu(ustr->unicode[i]);
695 
696 		KUNIT_EXPECT_EQ(test, expected_char, actual_char);
697 	}
698 }
699 
700 /* Test hfsplus_asc2uni basic functionality */
701 static void hfsplus_asc2uni_basic_test(struct kunit *test)
702 {
703 	struct test_mock_sb *mock_sb;
704 	struct test_mock_string_env *mock_env;
705 	int result;
706 
707 	mock_env = setup_mock_str_env(HFSPLUS_MAX_STRLEN + 1);
708 	KUNIT_ASSERT_NOT_NULL(test, mock_env);
709 
710 	mock_sb = setup_mock_sb();
711 	KUNIT_ASSERT_NOT_NULL(test, mock_sb);
712 
713 	mock_sb->nls.char2uni = test_char2uni;
714 
715 	/* Test simple ASCII string conversion */
716 	result = hfsplus_asc2uni(&mock_sb->sb, &mock_env->str1,
717 				 HFSPLUS_MAX_STRLEN, "hello", 5,
718 				 HFS_REGULAR_NAME);
719 
720 	KUNIT_EXPECT_EQ(test, 0, result);
721 	check_unistr_content(test, &mock_env->str1, "hello");
722 
723 	/* Test empty string */
724 	result = hfsplus_asc2uni(&mock_sb->sb, &mock_env->str1,
725 				 HFSPLUS_MAX_STRLEN, "", 0,
726 				 HFS_REGULAR_NAME);
727 
728 	KUNIT_EXPECT_EQ(test, 0, result);
729 	KUNIT_EXPECT_EQ(test, 0, be16_to_cpu(mock_env->str1.length));
730 
731 	/* Test single character */
732 	result = hfsplus_asc2uni(&mock_sb->sb, &mock_env->str1,
733 				 HFSPLUS_MAX_STRLEN, "A", 1,
734 				 HFS_REGULAR_NAME);
735 
736 	KUNIT_EXPECT_EQ(test, 0, result);
737 	check_unistr_content(test, &mock_env->str1, "A");
738 
739 	/* Test null-terminated string with explicit length */
740 	result = hfsplus_asc2uni(&mock_sb->sb, &mock_env->str1,
741 				 HFSPLUS_MAX_STRLEN, "test\0extra", 4,
742 				 HFS_REGULAR_NAME);
743 
744 	KUNIT_EXPECT_EQ(test, 0, result);
745 	check_unistr_content(test, &mock_env->str1, "test");
746 
747 	free_mock_str_env(mock_env);
748 	free_mock_sb(mock_sb);
749 }
750 
751 /* Test special character handling in asc2uni */
752 static void hfsplus_asc2uni_special_chars_test(struct kunit *test)
753 {
754 	struct test_mock_sb *mock_sb;
755 	struct test_mock_string_env *mock_env;
756 	int result;
757 
758 	mock_env = setup_mock_str_env(HFSPLUS_MAX_STRLEN + 1);
759 	KUNIT_ASSERT_NOT_NULL(test, mock_env);
760 
761 	mock_sb = setup_mock_sb();
762 	KUNIT_ASSERT_NOT_NULL(test, mock_sb);
763 
764 	mock_sb->nls.char2uni = test_char2uni;
765 
766 	/* Test colon conversion (should become forward slash) */
767 	result = hfsplus_asc2uni(&mock_sb->sb, &mock_env->str1,
768 				 HFSPLUS_MAX_STRLEN, ":", 1,
769 				 HFS_REGULAR_NAME);
770 
771 	KUNIT_EXPECT_EQ(test, 0, result);
772 	KUNIT_EXPECT_EQ(test, 1, be16_to_cpu(mock_env->str1.length));
773 	KUNIT_EXPECT_EQ(test, '/', be16_to_cpu(mock_env->str1.unicode[0]));
774 
775 	/* Test string with mixed special characters */
776 	result = hfsplus_asc2uni(&mock_sb->sb, &mock_env->str1,
777 				 HFSPLUS_MAX_STRLEN, "a:b", 3,
778 				 HFS_REGULAR_NAME);
779 
780 	KUNIT_EXPECT_EQ(test, 0, result);
781 	KUNIT_EXPECT_EQ(test, 3, be16_to_cpu(mock_env->str1.length));
782 	KUNIT_EXPECT_EQ(test, 'a', be16_to_cpu(mock_env->str1.unicode[0]));
783 	KUNIT_EXPECT_EQ(test, '/', be16_to_cpu(mock_env->str1.unicode[1]));
784 	KUNIT_EXPECT_EQ(test, 'b', be16_to_cpu(mock_env->str1.unicode[2]));
785 
786 	/* Test multiple special characters */
787 	result = hfsplus_asc2uni(&mock_sb->sb, &mock_env->str1,
788 				 HFSPLUS_MAX_STRLEN, ":::", 3,
789 				 HFS_REGULAR_NAME);
790 
791 	KUNIT_EXPECT_EQ(test, 0, result);
792 	KUNIT_EXPECT_EQ(test, 3, be16_to_cpu(mock_env->str1.length));
793 	KUNIT_EXPECT_EQ(test, '/', be16_to_cpu(mock_env->str1.unicode[0]));
794 	KUNIT_EXPECT_EQ(test, '/', be16_to_cpu(mock_env->str1.unicode[1]));
795 	KUNIT_EXPECT_EQ(test, '/', be16_to_cpu(mock_env->str1.unicode[2]));
796 
797 	free_mock_str_env(mock_env);
798 	free_mock_sb(mock_sb);
799 }
800 
801 /* Test buffer length limits */
802 static void hfsplus_asc2uni_buffer_limits_test(struct kunit *test)
803 {
804 	struct test_mock_sb *mock_sb;
805 	struct test_mock_string_env *mock_env;
806 	int result;
807 
808 	mock_env = setup_mock_str_env(HFSPLUS_MAX_STRLEN + 10);
809 	KUNIT_ASSERT_NOT_NULL(test, mock_env);
810 
811 	mock_sb = setup_mock_sb();
812 	KUNIT_ASSERT_NOT_NULL(test, mock_sb);
813 
814 	mock_sb->nls.char2uni = test_char2uni;
815 
816 	/* Test exact maximum length */
817 	memset(mock_env->buf, 'a', HFSPLUS_MAX_STRLEN);
818 	result = hfsplus_asc2uni(&mock_sb->sb,
819 				 &mock_env->str1, HFSPLUS_MAX_STRLEN,
820 				 mock_env->buf, HFSPLUS_MAX_STRLEN,
821 				 HFS_REGULAR_NAME);
822 
823 	KUNIT_EXPECT_EQ(test, 0, result);
824 	KUNIT_EXPECT_EQ(test, HFSPLUS_MAX_STRLEN,
825 			be16_to_cpu(mock_env->str1.length));
826 
827 	/* Test exceeding maximum length */
828 	memset(mock_env->buf, 'a', HFSPLUS_MAX_STRLEN + 5);
829 	result = hfsplus_asc2uni(&mock_sb->sb,
830 				 &mock_env->str1, HFSPLUS_MAX_STRLEN,
831 				 mock_env->buf, HFSPLUS_MAX_STRLEN + 5,
832 				 HFS_REGULAR_NAME);
833 
834 	KUNIT_EXPECT_EQ(test, -ENAMETOOLONG, result);
835 	KUNIT_EXPECT_EQ(test, HFSPLUS_MAX_STRLEN,
836 			be16_to_cpu(mock_env->str1.length));
837 
838 	/* Test with smaller max_unistr_len */
839 	result = hfsplus_asc2uni(&mock_sb->sb,
840 				 &mock_env->str1, 5, "toolongstring", 13,
841 				 HFS_REGULAR_NAME);
842 
843 	KUNIT_EXPECT_EQ(test, -ENAMETOOLONG, result);
844 	KUNIT_EXPECT_EQ(test, 5, be16_to_cpu(mock_env->str1.length));
845 
846 	/* Test zero max length */
847 	result = hfsplus_asc2uni(&mock_sb->sb, &mock_env->str1, 0, "test", 4,
848 				 HFS_REGULAR_NAME);
849 
850 	KUNIT_EXPECT_EQ(test, -ENAMETOOLONG, result);
851 	KUNIT_EXPECT_EQ(test, 0, be16_to_cpu(mock_env->str1.length));
852 
853 	free_mock_str_env(mock_env);
854 	free_mock_sb(mock_sb);
855 }
856 
857 /* Test error handling and edge cases */
858 static void hfsplus_asc2uni_edge_cases_test(struct kunit *test)
859 {
860 	struct test_mock_sb *mock_sb;
861 	struct hfsplus_unistr ustr;
862 	char test_str[] = {'a', '\0', 'b'};
863 	int result;
864 
865 	mock_sb = setup_mock_sb();
866 	KUNIT_ASSERT_NOT_NULL(test, mock_sb);
867 
868 	mock_sb->nls.char2uni = test_char2uni;
869 
870 	/* Test zero length input */
871 	result = hfsplus_asc2uni(&mock_sb->sb,
872 				 &ustr, HFSPLUS_MAX_STRLEN, "test", 0,
873 				 HFS_REGULAR_NAME);
874 
875 	KUNIT_EXPECT_EQ(test, 0, result);
876 	KUNIT_EXPECT_EQ(test, 0, be16_to_cpu(ustr.length));
877 
878 	/* Test input with length mismatch */
879 	result = hfsplus_asc2uni(&mock_sb->sb,
880 				 &ustr, HFSPLUS_MAX_STRLEN, "hello", 3,
881 				 HFS_REGULAR_NAME);
882 
883 	KUNIT_EXPECT_EQ(test, 0, result);
884 	check_unistr_content(test, &ustr, "hel");
885 
886 	/* Test with various printable ASCII characters */
887 	result = hfsplus_asc2uni(&mock_sb->sb,
888 				 &ustr, HFSPLUS_MAX_STRLEN, "ABC123!@#", 9,
889 				 HFS_REGULAR_NAME);
890 
891 	KUNIT_EXPECT_EQ(test, 0, result);
892 	check_unistr_content(test, &ustr, "ABC123!@#");
893 
894 	/* Test null character in the middle */
895 	result = hfsplus_asc2uni(&mock_sb->sb,
896 				 &ustr, HFSPLUS_MAX_STRLEN, test_str, 3,
897 				 HFS_REGULAR_NAME);
898 
899 	KUNIT_EXPECT_EQ(test, 0, result);
900 	KUNIT_EXPECT_EQ(test, 3, be16_to_cpu(ustr.length));
901 	KUNIT_EXPECT_EQ(test, 'a', be16_to_cpu(ustr.unicode[0]));
902 	KUNIT_EXPECT_EQ(test, 0, be16_to_cpu(ustr.unicode[1]));
903 	KUNIT_EXPECT_EQ(test, 'b', be16_to_cpu(ustr.unicode[2]));
904 
905 	free_mock_sb(mock_sb);
906 }
907 
908 /* Test decomposition flag behavior */
909 static void hfsplus_asc2uni_decompose_test(struct kunit *test)
910 {
911 	struct test_mock_sb *mock_sb;
912 	struct test_mock_string_env *mock_env;
913 	int result;
914 
915 	mock_env = setup_mock_str_env(HFSPLUS_MAX_STRLEN + 1);
916 	KUNIT_ASSERT_NOT_NULL(test, mock_env);
917 
918 	mock_sb = setup_mock_sb();
919 	KUNIT_ASSERT_NOT_NULL(test, mock_sb);
920 
921 	mock_sb->nls.char2uni = test_char2uni;
922 
923 	/* Test with decomposition disabled (default) */
924 	clear_bit(HFSPLUS_SB_NODECOMPOSE, &mock_sb->sb_info.flags);
925 	result = hfsplus_asc2uni(&mock_sb->sb, &mock_env->str1,
926 				 HFSPLUS_MAX_STRLEN, "test", 4,
927 				 HFS_REGULAR_NAME);
928 
929 	KUNIT_EXPECT_EQ(test, 0, result);
930 	check_unistr_content(test, &mock_env->str1, "test");
931 
932 	/* Test with decomposition enabled */
933 	set_bit(HFSPLUS_SB_NODECOMPOSE, &mock_sb->sb_info.flags);
934 	result = hfsplus_asc2uni(&mock_sb->sb, &mock_env->str2,
935 				 HFSPLUS_MAX_STRLEN, "test", 4,
936 				 HFS_REGULAR_NAME);
937 
938 	KUNIT_EXPECT_EQ(test, 0, result);
939 	check_unistr_content(test, &mock_env->str2, "test");
940 
941 	/* For simple ASCII, both should produce the same result */
942 	KUNIT_EXPECT_EQ(test,
943 			be16_to_cpu(mock_env->str1.length),
944 			be16_to_cpu(mock_env->str2.length));
945 
946 	free_mock_str_env(mock_env);
947 	free_mock_sb(mock_sb);
948 }
949 
950 /* Mock dentry for testing hfsplus_hash_dentry */
951 static struct dentry test_dentry;
952 
953 static void setup_mock_dentry(struct super_block *sb)
954 {
955 	memset(&test_dentry, 0, sizeof(test_dentry));
956 	test_dentry.d_sb = sb;
957 }
958 
959 /* Helper function to create qstr */
960 static void create_qstr(struct qstr *str, const char *name)
961 {
962 	str->name = name;
963 	str->len = strlen(name);
964 	str->hash = 0; /* Will be set by hash function */
965 }
966 
967 /* Test hfsplus_hash_dentry basic functionality */
968 static void hfsplus_hash_dentry_basic_test(struct kunit *test)
969 {
970 	struct test_mock_sb *mock_sb;
971 	struct qstr str1, str2;
972 	int result;
973 
974 	mock_sb = setup_mock_sb();
975 	KUNIT_ASSERT_NOT_NULL(test, mock_sb);
976 
977 	setup_mock_dentry(&mock_sb->sb);
978 	mock_sb->nls.char2uni = test_char2uni;
979 
980 	/* Test basic string hashing */
981 	create_qstr(&str1, "hello");
982 	result = hfsplus_hash_dentry(&test_dentry, &str1);
983 
984 	KUNIT_EXPECT_EQ(test, 0, result);
985 	KUNIT_EXPECT_NE(test, 0, str1.hash);
986 
987 	/* Test that identical strings produce identical hashes */
988 	create_qstr(&str2, "hello");
989 	result = hfsplus_hash_dentry(&test_dentry, &str2);
990 
991 	KUNIT_EXPECT_EQ(test, 0, result);
992 	KUNIT_EXPECT_EQ(test, str1.hash, str2.hash);
993 
994 	/* Test empty string */
995 	create_qstr(&str1, "");
996 	result = hfsplus_hash_dentry(&test_dentry, &str1);
997 
998 	/* Empty string should still produce a hash */
999 	KUNIT_EXPECT_EQ(test, 0, result);
1000 
1001 	/* Test single character */
1002 	create_qstr(&str1, "A");
1003 	result = hfsplus_hash_dentry(&test_dentry, &str1);
1004 
1005 	KUNIT_EXPECT_EQ(test, 0, result);
1006 	KUNIT_EXPECT_NE(test, 0, str1.hash);
1007 
1008 	free_mock_sb(mock_sb);
1009 }
1010 
1011 /* Test case folding behavior in hash */
1012 static void hfsplus_hash_dentry_casefold_test(struct kunit *test)
1013 {
1014 	struct test_mock_sb *mock_sb;
1015 	struct qstr str1, str2;
1016 	int result;
1017 
1018 	mock_sb = setup_mock_sb();
1019 	KUNIT_ASSERT_NOT_NULL(test, mock_sb);
1020 
1021 	setup_mock_dentry(&mock_sb->sb);
1022 	mock_sb->nls.char2uni = test_char2uni;
1023 
1024 	/* Test with case folding disabled (default) */
1025 	clear_bit(HFSPLUS_SB_CASEFOLD, &mock_sb->sb_info.flags);
1026 
1027 	create_qstr(&str1, "Hello");
1028 	result = hfsplus_hash_dentry(&test_dentry, &str1);
1029 	KUNIT_EXPECT_EQ(test, 0, result);
1030 
1031 	create_qstr(&str2, "hello");
1032 	result = hfsplus_hash_dentry(&test_dentry, &str2);
1033 	KUNIT_EXPECT_EQ(test, 0, result);
1034 
1035 	/*
1036 	 * Without case folding, different cases
1037 	 * should produce different hashes
1038 	 */
1039 	KUNIT_EXPECT_NE(test, str1.hash, str2.hash);
1040 
1041 	/* Test with case folding enabled */
1042 	set_bit(HFSPLUS_SB_CASEFOLD, &mock_sb->sb_info.flags);
1043 
1044 	create_qstr(&str1, "Hello");
1045 	result = hfsplus_hash_dentry(&test_dentry, &str1);
1046 	KUNIT_EXPECT_EQ(test, 0, result);
1047 
1048 	create_qstr(&str2, "hello");
1049 	result = hfsplus_hash_dentry(&test_dentry, &str2);
1050 	KUNIT_EXPECT_EQ(test, 0, result);
1051 
1052 	/* With case folding, different cases should produce same hash */
1053 	KUNIT_EXPECT_EQ(test, str1.hash, str2.hash);
1054 
1055 	/* Test mixed case */
1056 	create_qstr(&str1, "HeLLo");
1057 	result = hfsplus_hash_dentry(&test_dentry, &str1);
1058 	KUNIT_EXPECT_EQ(test, 0, result);
1059 	KUNIT_EXPECT_EQ(test, str1.hash, str2.hash);
1060 
1061 	free_mock_sb(mock_sb);
1062 }
1063 
1064 /* Test special character handling in hash */
1065 static void hfsplus_hash_dentry_special_chars_test(struct kunit *test)
1066 {
1067 	struct test_mock_sb *mock_sb;
1068 	struct qstr str1, str2;
1069 	int result;
1070 
1071 	mock_sb = setup_mock_sb();
1072 	KUNIT_ASSERT_NOT_NULL(test, mock_sb);
1073 
1074 	setup_mock_dentry(&mock_sb->sb);
1075 	mock_sb->nls.char2uni = test_char2uni;
1076 
1077 	/* Test colon conversion (: becomes /) */
1078 	create_qstr(&str1, "file:name");
1079 	result = hfsplus_hash_dentry(&test_dentry, &str1);
1080 	KUNIT_EXPECT_EQ(test, 0, result);
1081 
1082 	create_qstr(&str2, "file/name");
1083 	result = hfsplus_hash_dentry(&test_dentry, &str2);
1084 	KUNIT_EXPECT_EQ(test, 0, result);
1085 
1086 	/* After conversion, these should produce the same hash */
1087 	KUNIT_EXPECT_EQ(test, str1.hash, str2.hash);
1088 
1089 	/* Test multiple special characters */
1090 	create_qstr(&str1, ":::");
1091 	result = hfsplus_hash_dentry(&test_dentry, &str1);
1092 	KUNIT_EXPECT_EQ(test, 0, result);
1093 
1094 	create_qstr(&str2, "///");
1095 	result = hfsplus_hash_dentry(&test_dentry, &str2);
1096 	KUNIT_EXPECT_EQ(test, 0, result);
1097 
1098 	KUNIT_EXPECT_EQ(test, str1.hash, str2.hash);
1099 
1100 	free_mock_sb(mock_sb);
1101 }
1102 
1103 /* Test decomposition flag behavior in hash */
1104 static void hfsplus_hash_dentry_decompose_test(struct kunit *test)
1105 {
1106 	struct test_mock_sb *mock_sb;
1107 	struct qstr str1, str2;
1108 	int result;
1109 
1110 	mock_sb = setup_mock_sb();
1111 	KUNIT_ASSERT_NOT_NULL(test, mock_sb);
1112 
1113 	setup_mock_dentry(&mock_sb->sb);
1114 	mock_sb->nls.char2uni = test_char2uni;
1115 
1116 	/* Test with decomposition disabled (default) */
1117 	clear_bit(HFSPLUS_SB_NODECOMPOSE, &mock_sb->sb_info.flags);
1118 
1119 	create_qstr(&str1, "test");
1120 	result = hfsplus_hash_dentry(&test_dentry, &str1);
1121 	KUNIT_EXPECT_EQ(test, 0, result);
1122 
1123 	/* Test with decomposition enabled */
1124 	set_bit(HFSPLUS_SB_NODECOMPOSE, &mock_sb->sb_info.flags);
1125 
1126 	create_qstr(&str2, "test");
1127 	result = hfsplus_hash_dentry(&test_dentry, &str2);
1128 	KUNIT_EXPECT_EQ(test, 0, result);
1129 
1130 	/*
1131 	 * For simple ASCII, decomposition shouldn't change
1132 	 * the hash much but the function should still work correctly
1133 	 */
1134 	KUNIT_EXPECT_NE(test, 0, str2.hash);
1135 
1136 	free_mock_sb(mock_sb);
1137 }
1138 
1139 /* Test hash consistency and distribution */
1140 static void hfsplus_hash_dentry_consistency_test(struct kunit *test)
1141 {
1142 	struct test_mock_sb *mock_sb;
1143 	struct qstr str1, str2, str3;
1144 	unsigned long hash1;
1145 	int result;
1146 
1147 	mock_sb = setup_mock_sb();
1148 	KUNIT_ASSERT_NOT_NULL(test, mock_sb);
1149 
1150 	setup_mock_dentry(&mock_sb->sb);
1151 	mock_sb->nls.char2uni = test_char2uni;
1152 
1153 	/* Test that same string always produces same hash */
1154 	create_qstr(&str1, "consistent");
1155 	result = hfsplus_hash_dentry(&test_dentry, &str1);
1156 	KUNIT_EXPECT_EQ(test, 0, result);
1157 	hash1 = str1.hash;
1158 
1159 	create_qstr(&str2, "consistent");
1160 	result = hfsplus_hash_dentry(&test_dentry, &str2);
1161 	KUNIT_EXPECT_EQ(test, 0, result);
1162 
1163 	KUNIT_EXPECT_EQ(test, hash1, str2.hash);
1164 
1165 	/* Test that different strings produce different hashes */
1166 	create_qstr(&str3, "different");
1167 	result = hfsplus_hash_dentry(&test_dentry, &str3);
1168 	KUNIT_EXPECT_EQ(test, 0, result);
1169 
1170 	KUNIT_EXPECT_NE(test, str1.hash, str3.hash);
1171 
1172 	/* Test similar strings should have different hashes */
1173 	create_qstr(&str1, "file1");
1174 	result = hfsplus_hash_dentry(&test_dentry, &str1);
1175 	KUNIT_EXPECT_EQ(test, 0, result);
1176 
1177 	create_qstr(&str2, "file2");
1178 	result = hfsplus_hash_dentry(&test_dentry, &str2);
1179 	KUNIT_EXPECT_EQ(test, 0, result);
1180 
1181 	KUNIT_EXPECT_NE(test, str1.hash, str2.hash);
1182 
1183 	free_mock_sb(mock_sb);
1184 }
1185 
1186 /* Test edge cases and boundary conditions */
1187 static void hfsplus_hash_dentry_edge_cases_test(struct kunit *test)
1188 {
1189 	struct test_mock_sb *mock_sb;
1190 	struct test_mock_string_env *mock_env;
1191 	struct qstr str;
1192 	int result;
1193 
1194 	mock_env = setup_mock_str_env(HFSPLUS_MAX_STRLEN + 1);
1195 	KUNIT_ASSERT_NOT_NULL(test, mock_env);
1196 
1197 	mock_sb = setup_mock_sb();
1198 	KUNIT_ASSERT_NOT_NULL(test, mock_sb);
1199 
1200 	setup_mock_dentry(&mock_sb->sb);
1201 	mock_sb->nls.char2uni = test_char2uni;
1202 
1203 	/* Test very long filename */
1204 	memset(mock_env->buf, 'a', mock_env->buf_size - 1);
1205 	mock_env->buf[mock_env->buf_size - 1] = '\0';
1206 
1207 	create_qstr(&str, mock_env->buf);
1208 	result = hfsplus_hash_dentry(&test_dentry, &str);
1209 
1210 	KUNIT_EXPECT_EQ(test, 0, result);
1211 	KUNIT_EXPECT_NE(test, 0, str.hash);
1212 
1213 	/* Test filename with all printable ASCII characters */
1214 	create_qstr(&str, "!@#$%^&*()_+-=[]{}|;':\",./<>?");
1215 	result = hfsplus_hash_dentry(&test_dentry, &str);
1216 
1217 	KUNIT_EXPECT_EQ(test, 0, result);
1218 	KUNIT_EXPECT_NE(test, 0, str.hash);
1219 
1220 	/* Test with embedded null (though not typical for filenames) */
1221 	str.name = "file\0hidden";
1222 	str.len = 11; /* Include the null and text after it */
1223 	str.hash = 0;
1224 	result = hfsplus_hash_dentry(&test_dentry, &str);
1225 
1226 	KUNIT_EXPECT_EQ(test, 0, result);
1227 	KUNIT_EXPECT_NE(test, 0, str.hash);
1228 
1229 	free_mock_str_env(mock_env);
1230 	free_mock_sb(mock_sb);
1231 }
1232 
1233 /* Test hfsplus_compare_dentry basic functionality */
1234 static void hfsplus_compare_dentry_basic_test(struct kunit *test)
1235 {
1236 	struct test_mock_sb *mock_sb;
1237 	struct qstr name;
1238 	int result;
1239 
1240 	mock_sb = setup_mock_sb();
1241 	KUNIT_ASSERT_NOT_NULL(test, mock_sb);
1242 
1243 	setup_mock_dentry(&mock_sb->sb);
1244 	mock_sb->nls.char2uni = test_char2uni;
1245 
1246 	/* Test identical strings */
1247 	create_qstr(&name, "hello");
1248 	result = hfsplus_compare_dentry(&test_dentry, 5, "hello", &name);
1249 	KUNIT_EXPECT_EQ(test, 0, result);
1250 
1251 	/* Test different strings - lexicographic order */
1252 	create_qstr(&name, "world");
1253 	result = hfsplus_compare_dentry(&test_dentry, 5, "hello", &name);
1254 	KUNIT_EXPECT_LT(test, result, 0); /* "hello" < "world" */
1255 
1256 	result = hfsplus_compare_dentry(&test_dentry, 5, "world", &name);
1257 	KUNIT_EXPECT_EQ(test, 0, result);
1258 
1259 	create_qstr(&name, "hello");
1260 	result = hfsplus_compare_dentry(&test_dentry, 5, "world", &name);
1261 	KUNIT_EXPECT_GT(test, result, 0); /* "world" > "hello" */
1262 
1263 	/* Test empty strings */
1264 	create_qstr(&name, "");
1265 	result = hfsplus_compare_dentry(&test_dentry, 0, "", &name);
1266 	KUNIT_EXPECT_EQ(test, 0, result);
1267 
1268 	/* Test one empty, one non-empty */
1269 	create_qstr(&name, "test");
1270 	result = hfsplus_compare_dentry(&test_dentry, 0, "", &name);
1271 	KUNIT_EXPECT_LT(test, result, 0); /* "" < "test" */
1272 
1273 	create_qstr(&name, "");
1274 	result = hfsplus_compare_dentry(&test_dentry, 4, "test", &name);
1275 	KUNIT_EXPECT_GT(test, result, 0); /* "test" > "" */
1276 
1277 	free_mock_sb(mock_sb);
1278 }
1279 
1280 /* Test case folding behavior in comparison */
1281 static void hfsplus_compare_dentry_casefold_test(struct kunit *test)
1282 {
1283 	struct test_mock_sb *mock_sb;
1284 	struct qstr name;
1285 	int result;
1286 
1287 	mock_sb = setup_mock_sb();
1288 	KUNIT_ASSERT_NOT_NULL(test, mock_sb);
1289 
1290 	setup_mock_dentry(&mock_sb->sb);
1291 	mock_sb->nls.char2uni = test_char2uni;
1292 
1293 	/* Test with case folding disabled (default) */
1294 	clear_bit(HFSPLUS_SB_CASEFOLD, &mock_sb->sb_info.flags);
1295 
1296 	create_qstr(&name, "hello");
1297 	result = hfsplus_compare_dentry(&test_dentry, 5, "Hello", &name);
1298 	/* Case sensitive: "Hello" != "hello" */
1299 	KUNIT_EXPECT_NE(test, 0, result);
1300 
1301 	create_qstr(&name, "Hello");
1302 	result = hfsplus_compare_dentry(&test_dentry, 5, "hello", &name);
1303 	/* Case sensitive: "hello" != "Hello" */
1304 	KUNIT_EXPECT_NE(test, 0, result);
1305 
1306 	/* Test with case folding enabled */
1307 	set_bit(HFSPLUS_SB_CASEFOLD, &mock_sb->sb_info.flags);
1308 
1309 	create_qstr(&name, "hello");
1310 	result = hfsplus_compare_dentry(&test_dentry, 5, "Hello", &name);
1311 	/* Case insensitive: "Hello" == "hello" */
1312 	KUNIT_EXPECT_EQ(test, 0, result);
1313 
1314 	create_qstr(&name, "Hello");
1315 	result = hfsplus_compare_dentry(&test_dentry, 5, "hello", &name);
1316 	/* Case insensitive: "hello" == "Hello" */
1317 	KUNIT_EXPECT_EQ(test, 0, result);
1318 
1319 	/* Test mixed case */
1320 	create_qstr(&name, "TeSt");
1321 	result = hfsplus_compare_dentry(&test_dentry, 4, "test", &name);
1322 	KUNIT_EXPECT_EQ(test, 0, result);
1323 
1324 	create_qstr(&name, "test");
1325 	result = hfsplus_compare_dentry(&test_dentry, 4, "TEST", &name);
1326 	KUNIT_EXPECT_EQ(test, 0, result);
1327 
1328 	free_mock_sb(mock_sb);
1329 }
1330 
1331 /* Test special character handling in comparison */
1332 static void hfsplus_compare_dentry_special_chars_test(struct kunit *test)
1333 {
1334 	struct test_mock_sb *mock_sb;
1335 	struct qstr name;
1336 	int result;
1337 
1338 	mock_sb = setup_mock_sb();
1339 	KUNIT_ASSERT_NOT_NULL(test, mock_sb);
1340 
1341 	setup_mock_dentry(&mock_sb->sb);
1342 	mock_sb->nls.char2uni = test_char2uni;
1343 
1344 	/* Test colon conversion (: becomes /) */
1345 	create_qstr(&name, "file/name");
1346 	result = hfsplus_compare_dentry(&test_dentry, 9, "file:name", &name);
1347 	/* "file:name" == "file/name" after conversion */
1348 	KUNIT_EXPECT_EQ(test, 0, result);
1349 
1350 	create_qstr(&name, "file:name");
1351 	result = hfsplus_compare_dentry(&test_dentry, 9, "file/name", &name);
1352 	/* "file/name" == "file:name" after conversion */
1353 	KUNIT_EXPECT_EQ(test, 0, result);
1354 
1355 	/* Test multiple special characters */
1356 	create_qstr(&name, "///");
1357 	result = hfsplus_compare_dentry(&test_dentry, 3, ":::", &name);
1358 	KUNIT_EXPECT_EQ(test, 0, result);
1359 
1360 	/* Test mixed special and regular characters */
1361 	create_qstr(&name, "a/b:c");
1362 	result = hfsplus_compare_dentry(&test_dentry, 5, "a:b/c", &name);
1363 	/* Both become "a/b/c" after conversion */
1364 	KUNIT_EXPECT_EQ(test, 0, result);
1365 
1366 	free_mock_sb(mock_sb);
1367 }
1368 
1369 /* Test length differences */
1370 static void hfsplus_compare_dentry_length_test(struct kunit *test)
1371 {
1372 	struct test_mock_sb *mock_sb;
1373 	struct qstr name;
1374 	int result;
1375 
1376 	mock_sb = setup_mock_sb();
1377 	KUNIT_ASSERT_NOT_NULL(test, mock_sb);
1378 
1379 	setup_mock_dentry(&mock_sb->sb);
1380 	mock_sb->nls.char2uni = test_char2uni;
1381 
1382 	/* Test different lengths with common prefix */
1383 	create_qstr(&name, "testing");
1384 	result = hfsplus_compare_dentry(&test_dentry, 4, "test", &name);
1385 	KUNIT_EXPECT_LT(test, result, 0); /* "test" < "testing" */
1386 
1387 	create_qstr(&name, "test");
1388 	result = hfsplus_compare_dentry(&test_dentry, 7, "testing", &name);
1389 	KUNIT_EXPECT_GT(test, result, 0); /* "testing" > "test" */
1390 
1391 	/* Test exact length match */
1392 	create_qstr(&name, "exact");
1393 	result = hfsplus_compare_dentry(&test_dentry, 5, "exact", &name);
1394 	KUNIT_EXPECT_EQ(test, 0, result);
1395 
1396 	/* Test length parameter vs actual string content */
1397 	create_qstr(&name, "hello");
1398 	result = hfsplus_compare_dentry(&test_dentry, 3, "hel", &name);
1399 	KUNIT_EXPECT_LT(test, result, 0); /* "hel" < "hello" */
1400 
1401 	/* Test longer first string but shorter length parameter */
1402 	create_qstr(&name, "hi");
1403 	result = hfsplus_compare_dentry(&test_dentry, 2, "hello", &name);
1404 	/* "he" < "hi" (only first 2 chars compared) */
1405 	KUNIT_EXPECT_LT(test, result, 0);
1406 
1407 	free_mock_sb(mock_sb);
1408 }
1409 
1410 /* Test decomposition flag behavior */
1411 static void hfsplus_compare_dentry_decompose_test(struct kunit *test)
1412 {
1413 	struct test_mock_sb *mock_sb;
1414 	struct qstr name;
1415 	int result;
1416 
1417 	mock_sb = setup_mock_sb();
1418 	KUNIT_ASSERT_NOT_NULL(test, mock_sb);
1419 
1420 	setup_mock_dentry(&mock_sb->sb);
1421 	mock_sb->nls.char2uni = test_char2uni;
1422 
1423 	/* Test with decomposition disabled (default) */
1424 	clear_bit(HFSPLUS_SB_NODECOMPOSE, &mock_sb->sb_info.flags);
1425 
1426 	create_qstr(&name, "test");
1427 	result = hfsplus_compare_dentry(&test_dentry, 4, "test", &name);
1428 	KUNIT_EXPECT_EQ(test, 0, result);
1429 
1430 	/* Test with decomposition enabled */
1431 	set_bit(HFSPLUS_SB_NODECOMPOSE, &mock_sb->sb_info.flags);
1432 
1433 	create_qstr(&name, "test");
1434 	result = hfsplus_compare_dentry(&test_dentry, 4, "test", &name);
1435 	KUNIT_EXPECT_EQ(test, 0, result);
1436 
1437 	/* For simple ASCII, decomposition shouldn't affect the result */
1438 	create_qstr(&name, "different");
1439 	result = hfsplus_compare_dentry(&test_dentry, 4, "test", &name);
1440 	KUNIT_EXPECT_NE(test, 0, result);
1441 
1442 	free_mock_sb(mock_sb);
1443 }
1444 
1445 /* Test edge cases and boundary conditions */
1446 static void hfsplus_compare_dentry_edge_cases_test(struct kunit *test)
1447 {
1448 	struct test_mock_sb *mock_sb;
1449 	struct qstr name;
1450 	char *long_str;
1451 	char *long_str2;
1452 	u32 str_size = HFSPLUS_MAX_STRLEN + 1;
1453 	struct qstr null_name = {
1454 		.name = "a\0b",
1455 		.len = 3,
1456 		.hash = 0
1457 	};
1458 	int result;
1459 
1460 	mock_sb = setup_mock_sb();
1461 	KUNIT_ASSERT_NOT_NULL(test, mock_sb);
1462 
1463 	setup_mock_dentry(&mock_sb->sb);
1464 	mock_sb->nls.char2uni = test_char2uni;
1465 
1466 	long_str = kzalloc(str_size, GFP_KERNEL);
1467 	KUNIT_ASSERT_NOT_NULL(test, long_str);
1468 
1469 	long_str2 = kzalloc(str_size, GFP_KERNEL);
1470 	KUNIT_ASSERT_NOT_NULL(test, long_str2);
1471 
1472 	/* Test very long strings */
1473 	memset(long_str, 'a', str_size - 1);
1474 	long_str[str_size - 1] = '\0';
1475 
1476 	create_qstr(&name, long_str);
1477 	result = hfsplus_compare_dentry(&test_dentry, str_size - 1,
1478 					long_str, &name);
1479 	KUNIT_EXPECT_EQ(test, 0, result);
1480 
1481 	/* Test with difference at the end of long strings */
1482 	memset(long_str2, 'a', str_size - 1);
1483 	long_str2[str_size - 1] = '\0';
1484 	long_str2[str_size - 2] = 'b';
1485 	create_qstr(&name, long_str2);
1486 	result = hfsplus_compare_dentry(&test_dentry, str_size - 1,
1487 					long_str, &name);
1488 	KUNIT_EXPECT_LT(test, result, 0); /* 'a' < 'b' */
1489 
1490 	/* Test single character differences */
1491 	create_qstr(&name, "b");
1492 	result = hfsplus_compare_dentry(&test_dentry, 1, "a", &name);
1493 	KUNIT_EXPECT_LT(test, result, 0); /* 'a' < 'b' */
1494 
1495 	create_qstr(&name, "a");
1496 	result = hfsplus_compare_dentry(&test_dentry, 1, "b", &name);
1497 	KUNIT_EXPECT_GT(test, result, 0); /* 'b' > 'a' */
1498 
1499 	/* Test with null characters in the middle */
1500 	result = hfsplus_compare_dentry(&test_dentry, 3, "a\0b", &null_name);
1501 	KUNIT_EXPECT_EQ(test, 0, result);
1502 
1503 	/* Test all printable ASCII characters */
1504 	create_qstr(&name, "!@#$%^&*()");
1505 	result = hfsplus_compare_dentry(&test_dentry, 10, "!@#$%^&*()", &name);
1506 	KUNIT_EXPECT_EQ(test, 0, result);
1507 
1508 	kfree(long_str);
1509 	kfree(long_str2);
1510 	free_mock_sb(mock_sb);
1511 }
1512 
1513 /* Test combined flag behaviors */
1514 static void hfsplus_compare_dentry_combined_flags_test(struct kunit *test)
1515 {
1516 	struct test_mock_sb *mock_sb;
1517 	struct qstr name;
1518 	int result;
1519 
1520 	mock_sb = setup_mock_sb();
1521 	KUNIT_ASSERT_NOT_NULL(test, mock_sb);
1522 
1523 	setup_mock_dentry(&mock_sb->sb);
1524 	mock_sb->nls.char2uni = test_char2uni;
1525 
1526 	/* Test with both casefold and decompose enabled */
1527 	set_bit(HFSPLUS_SB_CASEFOLD, &mock_sb->sb_info.flags);
1528 	set_bit(HFSPLUS_SB_NODECOMPOSE, &mock_sb->sb_info.flags);
1529 
1530 	create_qstr(&name, "hello");
1531 	result = hfsplus_compare_dentry(&test_dentry, 5, "HELLO", &name);
1532 	KUNIT_EXPECT_EQ(test, 0, result);
1533 
1534 	/* Test special chars with case folding */
1535 	create_qstr(&name, "File/Name");
1536 	result = hfsplus_compare_dentry(&test_dentry, 9, "file:name", &name);
1537 	KUNIT_EXPECT_EQ(test, 0, result);
1538 
1539 	/* Test with both flags disabled */
1540 	clear_bit(HFSPLUS_SB_CASEFOLD, &mock_sb->sb_info.flags);
1541 	clear_bit(HFSPLUS_SB_NODECOMPOSE, &mock_sb->sb_info.flags);
1542 
1543 	create_qstr(&name, "hello");
1544 	result = hfsplus_compare_dentry(&test_dentry, 5, "HELLO", &name);
1545 	KUNIT_EXPECT_NE(test, 0, result); /* Case sensitive */
1546 
1547 	/* But special chars should still be converted */
1548 	create_qstr(&name, "file/name");
1549 	result = hfsplus_compare_dentry(&test_dentry, 9, "file:name", &name);
1550 	KUNIT_EXPECT_EQ(test, 0, result);
1551 
1552 	free_mock_sb(mock_sb);
1553 }
1554 
1555 static struct kunit_case hfsplus_unicode_test_cases[] = {
1556 	KUNIT_CASE(hfsplus_strcasecmp_test),
1557 	KUNIT_CASE(hfsplus_strcmp_test),
1558 	KUNIT_CASE(hfsplus_unicode_edge_cases_test),
1559 	KUNIT_CASE(hfsplus_unicode_boundary_test),
1560 	KUNIT_CASE(hfsplus_uni2asc_basic_test),
1561 	KUNIT_CASE(hfsplus_uni2asc_special_chars_test),
1562 	KUNIT_CASE(hfsplus_uni2asc_buffer_test),
1563 	KUNIT_CASE(hfsplus_uni2asc_corrupted_test),
1564 	KUNIT_CASE(hfsplus_uni2asc_edge_cases_test),
1565 	KUNIT_CASE(hfsplus_asc2uni_basic_test),
1566 	KUNIT_CASE(hfsplus_asc2uni_special_chars_test),
1567 	KUNIT_CASE(hfsplus_asc2uni_buffer_limits_test),
1568 	KUNIT_CASE(hfsplus_asc2uni_edge_cases_test),
1569 	KUNIT_CASE(hfsplus_asc2uni_decompose_test),
1570 	KUNIT_CASE(hfsplus_hash_dentry_basic_test),
1571 	KUNIT_CASE(hfsplus_hash_dentry_casefold_test),
1572 	KUNIT_CASE(hfsplus_hash_dentry_special_chars_test),
1573 	KUNIT_CASE(hfsplus_hash_dentry_decompose_test),
1574 	KUNIT_CASE(hfsplus_hash_dentry_consistency_test),
1575 	KUNIT_CASE(hfsplus_hash_dentry_edge_cases_test),
1576 	KUNIT_CASE(hfsplus_compare_dentry_basic_test),
1577 	KUNIT_CASE(hfsplus_compare_dentry_casefold_test),
1578 	KUNIT_CASE(hfsplus_compare_dentry_special_chars_test),
1579 	KUNIT_CASE(hfsplus_compare_dentry_length_test),
1580 	KUNIT_CASE(hfsplus_compare_dentry_decompose_test),
1581 	KUNIT_CASE(hfsplus_compare_dentry_edge_cases_test),
1582 	KUNIT_CASE(hfsplus_compare_dentry_combined_flags_test),
1583 	{}
1584 };
1585 
1586 static struct kunit_suite hfsplus_unicode_test_suite = {
1587 	.name = "hfsplus_unicode",
1588 	.test_cases = hfsplus_unicode_test_cases,
1589 };
1590 
1591 kunit_test_suite(hfsplus_unicode_test_suite);
1592 
1593 MODULE_DESCRIPTION("KUnit tests for HFS+ Unicode string operations");
1594 MODULE_LICENSE("GPL");
1595 MODULE_IMPORT_NS("EXPORTED_FOR_KUNIT_TESTING");
1596