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