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(sizeof(struct test_mock_string_env), GFP_KERNEL); 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(sizeof(struct test_mock_sb), GFP_KERNEL); 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 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 727 KUNIT_EXPECT_EQ(test, 0, result); 728 KUNIT_EXPECT_EQ(test, 0, be16_to_cpu(mock_env->str1.length)); 729 730 /* Test single character */ 731 result = hfsplus_asc2uni(&mock_sb->sb, &mock_env->str1, 732 HFSPLUS_MAX_STRLEN, "A", 1); 733 734 KUNIT_EXPECT_EQ(test, 0, result); 735 check_unistr_content(test, &mock_env->str1, "A"); 736 737 /* Test null-terminated string with explicit length */ 738 result = hfsplus_asc2uni(&mock_sb->sb, &mock_env->str1, 739 HFSPLUS_MAX_STRLEN, "test\0extra", 4); 740 741 KUNIT_EXPECT_EQ(test, 0, result); 742 check_unistr_content(test, &mock_env->str1, "test"); 743 744 free_mock_str_env(mock_env); 745 free_mock_sb(mock_sb); 746 } 747 748 /* Test special character handling in asc2uni */ 749 static void hfsplus_asc2uni_special_chars_test(struct kunit *test) 750 { 751 struct test_mock_sb *mock_sb; 752 struct test_mock_string_env *mock_env; 753 int result; 754 755 mock_env = setup_mock_str_env(HFSPLUS_MAX_STRLEN + 1); 756 KUNIT_ASSERT_NOT_NULL(test, mock_env); 757 758 mock_sb = setup_mock_sb(); 759 KUNIT_ASSERT_NOT_NULL(test, mock_sb); 760 761 mock_sb->nls.char2uni = test_char2uni; 762 763 /* Test colon conversion (should become forward slash) */ 764 result = hfsplus_asc2uni(&mock_sb->sb, &mock_env->str1, 765 HFSPLUS_MAX_STRLEN, ":", 1); 766 767 KUNIT_EXPECT_EQ(test, 0, result); 768 KUNIT_EXPECT_EQ(test, 1, be16_to_cpu(mock_env->str1.length)); 769 KUNIT_EXPECT_EQ(test, '/', be16_to_cpu(mock_env->str1.unicode[0])); 770 771 /* Test string with mixed special characters */ 772 result = hfsplus_asc2uni(&mock_sb->sb, &mock_env->str1, 773 HFSPLUS_MAX_STRLEN, "a:b", 3); 774 775 KUNIT_EXPECT_EQ(test, 0, result); 776 KUNIT_EXPECT_EQ(test, 3, be16_to_cpu(mock_env->str1.length)); 777 KUNIT_EXPECT_EQ(test, 'a', be16_to_cpu(mock_env->str1.unicode[0])); 778 KUNIT_EXPECT_EQ(test, '/', be16_to_cpu(mock_env->str1.unicode[1])); 779 KUNIT_EXPECT_EQ(test, 'b', be16_to_cpu(mock_env->str1.unicode[2])); 780 781 /* Test multiple special characters */ 782 result = hfsplus_asc2uni(&mock_sb->sb, &mock_env->str1, 783 HFSPLUS_MAX_STRLEN, ":::", 3); 784 785 KUNIT_EXPECT_EQ(test, 0, result); 786 KUNIT_EXPECT_EQ(test, 3, be16_to_cpu(mock_env->str1.length)); 787 KUNIT_EXPECT_EQ(test, '/', be16_to_cpu(mock_env->str1.unicode[0])); 788 KUNIT_EXPECT_EQ(test, '/', be16_to_cpu(mock_env->str1.unicode[1])); 789 KUNIT_EXPECT_EQ(test, '/', be16_to_cpu(mock_env->str1.unicode[2])); 790 791 free_mock_str_env(mock_env); 792 free_mock_sb(mock_sb); 793 } 794 795 /* Test buffer length limits */ 796 static void hfsplus_asc2uni_buffer_limits_test(struct kunit *test) 797 { 798 struct test_mock_sb *mock_sb; 799 struct test_mock_string_env *mock_env; 800 int result; 801 802 mock_env = setup_mock_str_env(HFSPLUS_MAX_STRLEN + 10); 803 KUNIT_ASSERT_NOT_NULL(test, mock_env); 804 805 mock_sb = setup_mock_sb(); 806 KUNIT_ASSERT_NOT_NULL(test, mock_sb); 807 808 mock_sb->nls.char2uni = test_char2uni; 809 810 /* Test exact maximum length */ 811 memset(mock_env->buf, 'a', HFSPLUS_MAX_STRLEN); 812 result = hfsplus_asc2uni(&mock_sb->sb, 813 &mock_env->str1, HFSPLUS_MAX_STRLEN, 814 mock_env->buf, HFSPLUS_MAX_STRLEN); 815 816 KUNIT_EXPECT_EQ(test, 0, result); 817 KUNIT_EXPECT_EQ(test, HFSPLUS_MAX_STRLEN, 818 be16_to_cpu(mock_env->str1.length)); 819 820 /* Test exceeding maximum length */ 821 memset(mock_env->buf, 'a', HFSPLUS_MAX_STRLEN + 5); 822 result = hfsplus_asc2uni(&mock_sb->sb, 823 &mock_env->str1, HFSPLUS_MAX_STRLEN, 824 mock_env->buf, HFSPLUS_MAX_STRLEN + 5); 825 826 KUNIT_EXPECT_EQ(test, -ENAMETOOLONG, result); 827 KUNIT_EXPECT_EQ(test, HFSPLUS_MAX_STRLEN, 828 be16_to_cpu(mock_env->str1.length)); 829 830 /* Test with smaller max_unistr_len */ 831 result = hfsplus_asc2uni(&mock_sb->sb, 832 &mock_env->str1, 5, "toolongstring", 13); 833 834 KUNIT_EXPECT_EQ(test, -ENAMETOOLONG, result); 835 KUNIT_EXPECT_EQ(test, 5, be16_to_cpu(mock_env->str1.length)); 836 837 /* Test zero max length */ 838 result = hfsplus_asc2uni(&mock_sb->sb, &mock_env->str1, 0, "test", 4); 839 840 KUNIT_EXPECT_EQ(test, -ENAMETOOLONG, result); 841 KUNIT_EXPECT_EQ(test, 0, be16_to_cpu(mock_env->str1.length)); 842 843 free_mock_str_env(mock_env); 844 free_mock_sb(mock_sb); 845 } 846 847 /* Test error handling and edge cases */ 848 static void hfsplus_asc2uni_edge_cases_test(struct kunit *test) 849 { 850 struct test_mock_sb *mock_sb; 851 struct hfsplus_unistr ustr; 852 char test_str[] = {'a', '\0', 'b'}; 853 int result; 854 855 mock_sb = setup_mock_sb(); 856 KUNIT_ASSERT_NOT_NULL(test, mock_sb); 857 858 mock_sb->nls.char2uni = test_char2uni; 859 860 /* Test zero length input */ 861 result = hfsplus_asc2uni(&mock_sb->sb, 862 &ustr, HFSPLUS_MAX_STRLEN, "test", 0); 863 864 KUNIT_EXPECT_EQ(test, 0, result); 865 KUNIT_EXPECT_EQ(test, 0, be16_to_cpu(ustr.length)); 866 867 /* Test input with length mismatch */ 868 result = hfsplus_asc2uni(&mock_sb->sb, 869 &ustr, HFSPLUS_MAX_STRLEN, "hello", 3); 870 871 KUNIT_EXPECT_EQ(test, 0, result); 872 check_unistr_content(test, &ustr, "hel"); 873 874 /* Test with various printable ASCII characters */ 875 result = hfsplus_asc2uni(&mock_sb->sb, 876 &ustr, HFSPLUS_MAX_STRLEN, "ABC123!@#", 9); 877 878 KUNIT_EXPECT_EQ(test, 0, result); 879 check_unistr_content(test, &ustr, "ABC123!@#"); 880 881 /* Test null character in the middle */ 882 result = hfsplus_asc2uni(&mock_sb->sb, 883 &ustr, HFSPLUS_MAX_STRLEN, test_str, 3); 884 885 KUNIT_EXPECT_EQ(test, 0, result); 886 KUNIT_EXPECT_EQ(test, 3, be16_to_cpu(ustr.length)); 887 KUNIT_EXPECT_EQ(test, 'a', be16_to_cpu(ustr.unicode[0])); 888 KUNIT_EXPECT_EQ(test, 0, be16_to_cpu(ustr.unicode[1])); 889 KUNIT_EXPECT_EQ(test, 'b', be16_to_cpu(ustr.unicode[2])); 890 891 free_mock_sb(mock_sb); 892 } 893 894 /* Test decomposition flag behavior */ 895 static void hfsplus_asc2uni_decompose_test(struct kunit *test) 896 { 897 struct test_mock_sb *mock_sb; 898 struct test_mock_string_env *mock_env; 899 int result; 900 901 mock_env = setup_mock_str_env(HFSPLUS_MAX_STRLEN + 1); 902 KUNIT_ASSERT_NOT_NULL(test, mock_env); 903 904 mock_sb = setup_mock_sb(); 905 KUNIT_ASSERT_NOT_NULL(test, mock_sb); 906 907 mock_sb->nls.char2uni = test_char2uni; 908 909 /* Test with decomposition disabled (default) */ 910 clear_bit(HFSPLUS_SB_NODECOMPOSE, &mock_sb->sb_info.flags); 911 result = hfsplus_asc2uni(&mock_sb->sb, &mock_env->str1, 912 HFSPLUS_MAX_STRLEN, "test", 4); 913 914 KUNIT_EXPECT_EQ(test, 0, result); 915 check_unistr_content(test, &mock_env->str1, "test"); 916 917 /* Test with decomposition enabled */ 918 set_bit(HFSPLUS_SB_NODECOMPOSE, &mock_sb->sb_info.flags); 919 result = hfsplus_asc2uni(&mock_sb->sb, &mock_env->str2, 920 HFSPLUS_MAX_STRLEN, "test", 4); 921 922 KUNIT_EXPECT_EQ(test, 0, result); 923 check_unistr_content(test, &mock_env->str2, "test"); 924 925 /* For simple ASCII, both should produce the same result */ 926 KUNIT_EXPECT_EQ(test, 927 be16_to_cpu(mock_env->str1.length), 928 be16_to_cpu(mock_env->str2.length)); 929 930 free_mock_str_env(mock_env); 931 free_mock_sb(mock_sb); 932 } 933 934 /* Mock dentry for testing hfsplus_hash_dentry */ 935 static struct dentry test_dentry; 936 937 static void setup_mock_dentry(struct super_block *sb) 938 { 939 memset(&test_dentry, 0, sizeof(test_dentry)); 940 test_dentry.d_sb = sb; 941 } 942 943 /* Helper function to create qstr */ 944 static void create_qstr(struct qstr *str, const char *name) 945 { 946 str->name = name; 947 str->len = strlen(name); 948 str->hash = 0; /* Will be set by hash function */ 949 } 950 951 /* Test hfsplus_hash_dentry basic functionality */ 952 static void hfsplus_hash_dentry_basic_test(struct kunit *test) 953 { 954 struct test_mock_sb *mock_sb; 955 struct qstr str1, str2; 956 int result; 957 958 mock_sb = setup_mock_sb(); 959 KUNIT_ASSERT_NOT_NULL(test, mock_sb); 960 961 setup_mock_dentry(&mock_sb->sb); 962 mock_sb->nls.char2uni = test_char2uni; 963 964 /* Test basic string hashing */ 965 create_qstr(&str1, "hello"); 966 result = hfsplus_hash_dentry(&test_dentry, &str1); 967 968 KUNIT_EXPECT_EQ(test, 0, result); 969 KUNIT_EXPECT_NE(test, 0, str1.hash); 970 971 /* Test that identical strings produce identical hashes */ 972 create_qstr(&str2, "hello"); 973 result = hfsplus_hash_dentry(&test_dentry, &str2); 974 975 KUNIT_EXPECT_EQ(test, 0, result); 976 KUNIT_EXPECT_EQ(test, str1.hash, str2.hash); 977 978 /* Test empty string */ 979 create_qstr(&str1, ""); 980 result = hfsplus_hash_dentry(&test_dentry, &str1); 981 982 /* Empty string should still produce a hash */ 983 KUNIT_EXPECT_EQ(test, 0, result); 984 985 /* Test single character */ 986 create_qstr(&str1, "A"); 987 result = hfsplus_hash_dentry(&test_dentry, &str1); 988 989 KUNIT_EXPECT_EQ(test, 0, result); 990 KUNIT_EXPECT_NE(test, 0, str1.hash); 991 992 free_mock_sb(mock_sb); 993 } 994 995 /* Test case folding behavior in hash */ 996 static void hfsplus_hash_dentry_casefold_test(struct kunit *test) 997 { 998 struct test_mock_sb *mock_sb; 999 struct qstr str1, str2; 1000 int result; 1001 1002 mock_sb = setup_mock_sb(); 1003 KUNIT_ASSERT_NOT_NULL(test, mock_sb); 1004 1005 setup_mock_dentry(&mock_sb->sb); 1006 mock_sb->nls.char2uni = test_char2uni; 1007 1008 /* Test with case folding disabled (default) */ 1009 clear_bit(HFSPLUS_SB_CASEFOLD, &mock_sb->sb_info.flags); 1010 1011 create_qstr(&str1, "Hello"); 1012 result = hfsplus_hash_dentry(&test_dentry, &str1); 1013 KUNIT_EXPECT_EQ(test, 0, result); 1014 1015 create_qstr(&str2, "hello"); 1016 result = hfsplus_hash_dentry(&test_dentry, &str2); 1017 KUNIT_EXPECT_EQ(test, 0, result); 1018 1019 /* 1020 * Without case folding, different cases 1021 * should produce different hashes 1022 */ 1023 KUNIT_EXPECT_NE(test, str1.hash, str2.hash); 1024 1025 /* Test with case folding enabled */ 1026 set_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 /* With case folding, different cases should produce same hash */ 1037 KUNIT_EXPECT_EQ(test, str1.hash, str2.hash); 1038 1039 /* Test mixed case */ 1040 create_qstr(&str1, "HeLLo"); 1041 result = hfsplus_hash_dentry(&test_dentry, &str1); 1042 KUNIT_EXPECT_EQ(test, 0, result); 1043 KUNIT_EXPECT_EQ(test, str1.hash, str2.hash); 1044 1045 free_mock_sb(mock_sb); 1046 } 1047 1048 /* Test special character handling in hash */ 1049 static void hfsplus_hash_dentry_special_chars_test(struct kunit *test) 1050 { 1051 struct test_mock_sb *mock_sb; 1052 struct qstr str1, str2; 1053 int result; 1054 1055 mock_sb = setup_mock_sb(); 1056 KUNIT_ASSERT_NOT_NULL(test, mock_sb); 1057 1058 setup_mock_dentry(&mock_sb->sb); 1059 mock_sb->nls.char2uni = test_char2uni; 1060 1061 /* Test colon conversion (: becomes /) */ 1062 create_qstr(&str1, "file:name"); 1063 result = hfsplus_hash_dentry(&test_dentry, &str1); 1064 KUNIT_EXPECT_EQ(test, 0, result); 1065 1066 create_qstr(&str2, "file/name"); 1067 result = hfsplus_hash_dentry(&test_dentry, &str2); 1068 KUNIT_EXPECT_EQ(test, 0, result); 1069 1070 /* After conversion, these should produce the same hash */ 1071 KUNIT_EXPECT_EQ(test, str1.hash, str2.hash); 1072 1073 /* Test multiple special characters */ 1074 create_qstr(&str1, ":::"); 1075 result = hfsplus_hash_dentry(&test_dentry, &str1); 1076 KUNIT_EXPECT_EQ(test, 0, result); 1077 1078 create_qstr(&str2, "///"); 1079 result = hfsplus_hash_dentry(&test_dentry, &str2); 1080 KUNIT_EXPECT_EQ(test, 0, result); 1081 1082 KUNIT_EXPECT_EQ(test, str1.hash, str2.hash); 1083 1084 free_mock_sb(mock_sb); 1085 } 1086 1087 /* Test decomposition flag behavior in hash */ 1088 static void hfsplus_hash_dentry_decompose_test(struct kunit *test) 1089 { 1090 struct test_mock_sb *mock_sb; 1091 struct qstr str1, str2; 1092 int result; 1093 1094 mock_sb = setup_mock_sb(); 1095 KUNIT_ASSERT_NOT_NULL(test, mock_sb); 1096 1097 setup_mock_dentry(&mock_sb->sb); 1098 mock_sb->nls.char2uni = test_char2uni; 1099 1100 /* Test with decomposition disabled (default) */ 1101 clear_bit(HFSPLUS_SB_NODECOMPOSE, &mock_sb->sb_info.flags); 1102 1103 create_qstr(&str1, "test"); 1104 result = hfsplus_hash_dentry(&test_dentry, &str1); 1105 KUNIT_EXPECT_EQ(test, 0, result); 1106 1107 /* Test with decomposition enabled */ 1108 set_bit(HFSPLUS_SB_NODECOMPOSE, &mock_sb->sb_info.flags); 1109 1110 create_qstr(&str2, "test"); 1111 result = hfsplus_hash_dentry(&test_dentry, &str2); 1112 KUNIT_EXPECT_EQ(test, 0, result); 1113 1114 /* 1115 * For simple ASCII, decomposition shouldn't change 1116 * the hash much but the function should still work correctly 1117 */ 1118 KUNIT_EXPECT_NE(test, 0, str2.hash); 1119 1120 free_mock_sb(mock_sb); 1121 } 1122 1123 /* Test hash consistency and distribution */ 1124 static void hfsplus_hash_dentry_consistency_test(struct kunit *test) 1125 { 1126 struct test_mock_sb *mock_sb; 1127 struct qstr str1, str2, str3; 1128 unsigned long hash1; 1129 int result; 1130 1131 mock_sb = setup_mock_sb(); 1132 KUNIT_ASSERT_NOT_NULL(test, mock_sb); 1133 1134 setup_mock_dentry(&mock_sb->sb); 1135 mock_sb->nls.char2uni = test_char2uni; 1136 1137 /* Test that same string always produces same hash */ 1138 create_qstr(&str1, "consistent"); 1139 result = hfsplus_hash_dentry(&test_dentry, &str1); 1140 KUNIT_EXPECT_EQ(test, 0, result); 1141 hash1 = str1.hash; 1142 1143 create_qstr(&str2, "consistent"); 1144 result = hfsplus_hash_dentry(&test_dentry, &str2); 1145 KUNIT_EXPECT_EQ(test, 0, result); 1146 1147 KUNIT_EXPECT_EQ(test, hash1, str2.hash); 1148 1149 /* Test that different strings produce different hashes */ 1150 create_qstr(&str3, "different"); 1151 result = hfsplus_hash_dentry(&test_dentry, &str3); 1152 KUNIT_EXPECT_EQ(test, 0, result); 1153 1154 KUNIT_EXPECT_NE(test, str1.hash, str3.hash); 1155 1156 /* Test similar strings should have different hashes */ 1157 create_qstr(&str1, "file1"); 1158 result = hfsplus_hash_dentry(&test_dentry, &str1); 1159 KUNIT_EXPECT_EQ(test, 0, result); 1160 1161 create_qstr(&str2, "file2"); 1162 result = hfsplus_hash_dentry(&test_dentry, &str2); 1163 KUNIT_EXPECT_EQ(test, 0, result); 1164 1165 KUNIT_EXPECT_NE(test, str1.hash, str2.hash); 1166 1167 free_mock_sb(mock_sb); 1168 } 1169 1170 /* Test edge cases and boundary conditions */ 1171 static void hfsplus_hash_dentry_edge_cases_test(struct kunit *test) 1172 { 1173 struct test_mock_sb *mock_sb; 1174 struct test_mock_string_env *mock_env; 1175 struct qstr str; 1176 int result; 1177 1178 mock_env = setup_mock_str_env(HFSPLUS_MAX_STRLEN + 1); 1179 KUNIT_ASSERT_NOT_NULL(test, mock_env); 1180 1181 mock_sb = setup_mock_sb(); 1182 KUNIT_ASSERT_NOT_NULL(test, mock_sb); 1183 1184 setup_mock_dentry(&mock_sb->sb); 1185 mock_sb->nls.char2uni = test_char2uni; 1186 1187 /* Test very long filename */ 1188 memset(mock_env->buf, 'a', mock_env->buf_size - 1); 1189 mock_env->buf[mock_env->buf_size - 1] = '\0'; 1190 1191 create_qstr(&str, mock_env->buf); 1192 result = hfsplus_hash_dentry(&test_dentry, &str); 1193 1194 KUNIT_EXPECT_EQ(test, 0, result); 1195 KUNIT_EXPECT_NE(test, 0, str.hash); 1196 1197 /* Test filename with all printable ASCII characters */ 1198 create_qstr(&str, "!@#$%^&*()_+-=[]{}|;':\",./<>?"); 1199 result = hfsplus_hash_dentry(&test_dentry, &str); 1200 1201 KUNIT_EXPECT_EQ(test, 0, result); 1202 KUNIT_EXPECT_NE(test, 0, str.hash); 1203 1204 /* Test with embedded null (though not typical for filenames) */ 1205 str.name = "file\0hidden"; 1206 str.len = 11; /* Include the null and text after it */ 1207 str.hash = 0; 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 free_mock_str_env(mock_env); 1214 free_mock_sb(mock_sb); 1215 } 1216 1217 /* Test hfsplus_compare_dentry basic functionality */ 1218 static void hfsplus_compare_dentry_basic_test(struct kunit *test) 1219 { 1220 struct test_mock_sb *mock_sb; 1221 struct qstr name; 1222 int result; 1223 1224 mock_sb = setup_mock_sb(); 1225 KUNIT_ASSERT_NOT_NULL(test, mock_sb); 1226 1227 setup_mock_dentry(&mock_sb->sb); 1228 mock_sb->nls.char2uni = test_char2uni; 1229 1230 /* Test identical strings */ 1231 create_qstr(&name, "hello"); 1232 result = hfsplus_compare_dentry(&test_dentry, 5, "hello", &name); 1233 KUNIT_EXPECT_EQ(test, 0, result); 1234 1235 /* Test different strings - lexicographic order */ 1236 create_qstr(&name, "world"); 1237 result = hfsplus_compare_dentry(&test_dentry, 5, "hello", &name); 1238 KUNIT_EXPECT_LT(test, result, 0); /* "hello" < "world" */ 1239 1240 result = hfsplus_compare_dentry(&test_dentry, 5, "world", &name); 1241 KUNIT_EXPECT_EQ(test, 0, result); 1242 1243 create_qstr(&name, "hello"); 1244 result = hfsplus_compare_dentry(&test_dentry, 5, "world", &name); 1245 KUNIT_EXPECT_GT(test, result, 0); /* "world" > "hello" */ 1246 1247 /* Test empty strings */ 1248 create_qstr(&name, ""); 1249 result = hfsplus_compare_dentry(&test_dentry, 0, "", &name); 1250 KUNIT_EXPECT_EQ(test, 0, result); 1251 1252 /* Test one empty, one non-empty */ 1253 create_qstr(&name, "test"); 1254 result = hfsplus_compare_dentry(&test_dentry, 0, "", &name); 1255 KUNIT_EXPECT_LT(test, result, 0); /* "" < "test" */ 1256 1257 create_qstr(&name, ""); 1258 result = hfsplus_compare_dentry(&test_dentry, 4, "test", &name); 1259 KUNIT_EXPECT_GT(test, result, 0); /* "test" > "" */ 1260 1261 free_mock_sb(mock_sb); 1262 } 1263 1264 /* Test case folding behavior in comparison */ 1265 static void hfsplus_compare_dentry_casefold_test(struct kunit *test) 1266 { 1267 struct test_mock_sb *mock_sb; 1268 struct qstr name; 1269 int result; 1270 1271 mock_sb = setup_mock_sb(); 1272 KUNIT_ASSERT_NOT_NULL(test, mock_sb); 1273 1274 setup_mock_dentry(&mock_sb->sb); 1275 mock_sb->nls.char2uni = test_char2uni; 1276 1277 /* Test with case folding disabled (default) */ 1278 clear_bit(HFSPLUS_SB_CASEFOLD, &mock_sb->sb_info.flags); 1279 1280 create_qstr(&name, "hello"); 1281 result = hfsplus_compare_dentry(&test_dentry, 5, "Hello", &name); 1282 /* Case sensitive: "Hello" != "hello" */ 1283 KUNIT_EXPECT_NE(test, 0, result); 1284 1285 create_qstr(&name, "Hello"); 1286 result = hfsplus_compare_dentry(&test_dentry, 5, "hello", &name); 1287 /* Case sensitive: "hello" != "Hello" */ 1288 KUNIT_EXPECT_NE(test, 0, result); 1289 1290 /* Test with case folding enabled */ 1291 set_bit(HFSPLUS_SB_CASEFOLD, &mock_sb->sb_info.flags); 1292 1293 create_qstr(&name, "hello"); 1294 result = hfsplus_compare_dentry(&test_dentry, 5, "Hello", &name); 1295 /* Case insensitive: "Hello" == "hello" */ 1296 KUNIT_EXPECT_EQ(test, 0, result); 1297 1298 create_qstr(&name, "Hello"); 1299 result = hfsplus_compare_dentry(&test_dentry, 5, "hello", &name); 1300 /* Case insensitive: "hello" == "Hello" */ 1301 KUNIT_EXPECT_EQ(test, 0, result); 1302 1303 /* Test mixed case */ 1304 create_qstr(&name, "TeSt"); 1305 result = hfsplus_compare_dentry(&test_dentry, 4, "test", &name); 1306 KUNIT_EXPECT_EQ(test, 0, result); 1307 1308 create_qstr(&name, "test"); 1309 result = hfsplus_compare_dentry(&test_dentry, 4, "TEST", &name); 1310 KUNIT_EXPECT_EQ(test, 0, result); 1311 1312 free_mock_sb(mock_sb); 1313 } 1314 1315 /* Test special character handling in comparison */ 1316 static void hfsplus_compare_dentry_special_chars_test(struct kunit *test) 1317 { 1318 struct test_mock_sb *mock_sb; 1319 struct qstr name; 1320 int result; 1321 1322 mock_sb = setup_mock_sb(); 1323 KUNIT_ASSERT_NOT_NULL(test, mock_sb); 1324 1325 setup_mock_dentry(&mock_sb->sb); 1326 mock_sb->nls.char2uni = test_char2uni; 1327 1328 /* Test colon conversion (: becomes /) */ 1329 create_qstr(&name, "file/name"); 1330 result = hfsplus_compare_dentry(&test_dentry, 9, "file:name", &name); 1331 /* "file:name" == "file/name" after conversion */ 1332 KUNIT_EXPECT_EQ(test, 0, result); 1333 1334 create_qstr(&name, "file:name"); 1335 result = hfsplus_compare_dentry(&test_dentry, 9, "file/name", &name); 1336 /* "file/name" == "file:name" after conversion */ 1337 KUNIT_EXPECT_EQ(test, 0, result); 1338 1339 /* Test multiple special characters */ 1340 create_qstr(&name, "///"); 1341 result = hfsplus_compare_dentry(&test_dentry, 3, ":::", &name); 1342 KUNIT_EXPECT_EQ(test, 0, result); 1343 1344 /* Test mixed special and regular characters */ 1345 create_qstr(&name, "a/b:c"); 1346 result = hfsplus_compare_dentry(&test_dentry, 5, "a:b/c", &name); 1347 /* Both become "a/b/c" after conversion */ 1348 KUNIT_EXPECT_EQ(test, 0, result); 1349 1350 free_mock_sb(mock_sb); 1351 } 1352 1353 /* Test length differences */ 1354 static void hfsplus_compare_dentry_length_test(struct kunit *test) 1355 { 1356 struct test_mock_sb *mock_sb; 1357 struct qstr name; 1358 int result; 1359 1360 mock_sb = setup_mock_sb(); 1361 KUNIT_ASSERT_NOT_NULL(test, mock_sb); 1362 1363 setup_mock_dentry(&mock_sb->sb); 1364 mock_sb->nls.char2uni = test_char2uni; 1365 1366 /* Test different lengths with common prefix */ 1367 create_qstr(&name, "testing"); 1368 result = hfsplus_compare_dentry(&test_dentry, 4, "test", &name); 1369 KUNIT_EXPECT_LT(test, result, 0); /* "test" < "testing" */ 1370 1371 create_qstr(&name, "test"); 1372 result = hfsplus_compare_dentry(&test_dentry, 7, "testing", &name); 1373 KUNIT_EXPECT_GT(test, result, 0); /* "testing" > "test" */ 1374 1375 /* Test exact length match */ 1376 create_qstr(&name, "exact"); 1377 result = hfsplus_compare_dentry(&test_dentry, 5, "exact", &name); 1378 KUNIT_EXPECT_EQ(test, 0, result); 1379 1380 /* Test length parameter vs actual string content */ 1381 create_qstr(&name, "hello"); 1382 result = hfsplus_compare_dentry(&test_dentry, 3, "hel", &name); 1383 KUNIT_EXPECT_LT(test, result, 0); /* "hel" < "hello" */ 1384 1385 /* Test longer first string but shorter length parameter */ 1386 create_qstr(&name, "hi"); 1387 result = hfsplus_compare_dentry(&test_dentry, 2, "hello", &name); 1388 /* "he" < "hi" (only first 2 chars compared) */ 1389 KUNIT_EXPECT_LT(test, result, 0); 1390 1391 free_mock_sb(mock_sb); 1392 } 1393 1394 /* Test decomposition flag behavior */ 1395 static void hfsplus_compare_dentry_decompose_test(struct kunit *test) 1396 { 1397 struct test_mock_sb *mock_sb; 1398 struct qstr name; 1399 int result; 1400 1401 mock_sb = setup_mock_sb(); 1402 KUNIT_ASSERT_NOT_NULL(test, mock_sb); 1403 1404 setup_mock_dentry(&mock_sb->sb); 1405 mock_sb->nls.char2uni = test_char2uni; 1406 1407 /* Test with decomposition disabled (default) */ 1408 clear_bit(HFSPLUS_SB_NODECOMPOSE, &mock_sb->sb_info.flags); 1409 1410 create_qstr(&name, "test"); 1411 result = hfsplus_compare_dentry(&test_dentry, 4, "test", &name); 1412 KUNIT_EXPECT_EQ(test, 0, result); 1413 1414 /* Test with decomposition enabled */ 1415 set_bit(HFSPLUS_SB_NODECOMPOSE, &mock_sb->sb_info.flags); 1416 1417 create_qstr(&name, "test"); 1418 result = hfsplus_compare_dentry(&test_dentry, 4, "test", &name); 1419 KUNIT_EXPECT_EQ(test, 0, result); 1420 1421 /* For simple ASCII, decomposition shouldn't affect the result */ 1422 create_qstr(&name, "different"); 1423 result = hfsplus_compare_dentry(&test_dentry, 4, "test", &name); 1424 KUNIT_EXPECT_NE(test, 0, result); 1425 1426 free_mock_sb(mock_sb); 1427 } 1428 1429 /* Test edge cases and boundary conditions */ 1430 static void hfsplus_compare_dentry_edge_cases_test(struct kunit *test) 1431 { 1432 struct test_mock_sb *mock_sb; 1433 struct qstr name; 1434 char *long_str; 1435 char *long_str2; 1436 u32 str_size = HFSPLUS_MAX_STRLEN + 1; 1437 struct qstr null_name = { 1438 .name = "a\0b", 1439 .len = 3, 1440 .hash = 0 1441 }; 1442 int result; 1443 1444 mock_sb = setup_mock_sb(); 1445 KUNIT_ASSERT_NOT_NULL(test, mock_sb); 1446 1447 setup_mock_dentry(&mock_sb->sb); 1448 mock_sb->nls.char2uni = test_char2uni; 1449 1450 long_str = kzalloc(str_size, GFP_KERNEL); 1451 KUNIT_ASSERT_NOT_NULL(test, long_str); 1452 1453 long_str2 = kzalloc(str_size, GFP_KERNEL); 1454 KUNIT_ASSERT_NOT_NULL(test, long_str2); 1455 1456 /* Test very long strings */ 1457 memset(long_str, 'a', str_size - 1); 1458 long_str[str_size - 1] = '\0'; 1459 1460 create_qstr(&name, long_str); 1461 result = hfsplus_compare_dentry(&test_dentry, str_size - 1, 1462 long_str, &name); 1463 KUNIT_EXPECT_EQ(test, 0, result); 1464 1465 /* Test with difference at the end of long strings */ 1466 memset(long_str2, 'a', str_size - 1); 1467 long_str2[str_size - 1] = '\0'; 1468 long_str2[str_size - 2] = 'b'; 1469 create_qstr(&name, long_str2); 1470 result = hfsplus_compare_dentry(&test_dentry, str_size - 1, 1471 long_str, &name); 1472 KUNIT_EXPECT_LT(test, result, 0); /* 'a' < 'b' */ 1473 1474 /* Test single character differences */ 1475 create_qstr(&name, "b"); 1476 result = hfsplus_compare_dentry(&test_dentry, 1, "a", &name); 1477 KUNIT_EXPECT_LT(test, result, 0); /* 'a' < 'b' */ 1478 1479 create_qstr(&name, "a"); 1480 result = hfsplus_compare_dentry(&test_dentry, 1, "b", &name); 1481 KUNIT_EXPECT_GT(test, result, 0); /* 'b' > 'a' */ 1482 1483 /* Test with null characters in the middle */ 1484 result = hfsplus_compare_dentry(&test_dentry, 3, "a\0b", &null_name); 1485 KUNIT_EXPECT_EQ(test, 0, result); 1486 1487 /* Test all printable ASCII characters */ 1488 create_qstr(&name, "!@#$%^&*()"); 1489 result = hfsplus_compare_dentry(&test_dentry, 10, "!@#$%^&*()", &name); 1490 KUNIT_EXPECT_EQ(test, 0, result); 1491 1492 kfree(long_str); 1493 kfree(long_str2); 1494 free_mock_sb(mock_sb); 1495 } 1496 1497 /* Test combined flag behaviors */ 1498 static void hfsplus_compare_dentry_combined_flags_test(struct kunit *test) 1499 { 1500 struct test_mock_sb *mock_sb; 1501 struct qstr name; 1502 int result; 1503 1504 mock_sb = setup_mock_sb(); 1505 KUNIT_ASSERT_NOT_NULL(test, mock_sb); 1506 1507 setup_mock_dentry(&mock_sb->sb); 1508 mock_sb->nls.char2uni = test_char2uni; 1509 1510 /* Test with both casefold and decompose enabled */ 1511 set_bit(HFSPLUS_SB_CASEFOLD, &mock_sb->sb_info.flags); 1512 set_bit(HFSPLUS_SB_NODECOMPOSE, &mock_sb->sb_info.flags); 1513 1514 create_qstr(&name, "hello"); 1515 result = hfsplus_compare_dentry(&test_dentry, 5, "HELLO", &name); 1516 KUNIT_EXPECT_EQ(test, 0, result); 1517 1518 /* Test special chars with case folding */ 1519 create_qstr(&name, "File/Name"); 1520 result = hfsplus_compare_dentry(&test_dentry, 9, "file:name", &name); 1521 KUNIT_EXPECT_EQ(test, 0, result); 1522 1523 /* Test with both flags disabled */ 1524 clear_bit(HFSPLUS_SB_CASEFOLD, &mock_sb->sb_info.flags); 1525 clear_bit(HFSPLUS_SB_NODECOMPOSE, &mock_sb->sb_info.flags); 1526 1527 create_qstr(&name, "hello"); 1528 result = hfsplus_compare_dentry(&test_dentry, 5, "HELLO", &name); 1529 KUNIT_EXPECT_NE(test, 0, result); /* Case sensitive */ 1530 1531 /* But special chars should still be converted */ 1532 create_qstr(&name, "file/name"); 1533 result = hfsplus_compare_dentry(&test_dentry, 9, "file:name", &name); 1534 KUNIT_EXPECT_EQ(test, 0, result); 1535 1536 free_mock_sb(mock_sb); 1537 } 1538 1539 static struct kunit_case hfsplus_unicode_test_cases[] = { 1540 KUNIT_CASE(hfsplus_strcasecmp_test), 1541 KUNIT_CASE(hfsplus_strcmp_test), 1542 KUNIT_CASE(hfsplus_unicode_edge_cases_test), 1543 KUNIT_CASE(hfsplus_unicode_boundary_test), 1544 KUNIT_CASE(hfsplus_uni2asc_basic_test), 1545 KUNIT_CASE(hfsplus_uni2asc_special_chars_test), 1546 KUNIT_CASE(hfsplus_uni2asc_buffer_test), 1547 KUNIT_CASE(hfsplus_uni2asc_corrupted_test), 1548 KUNIT_CASE(hfsplus_uni2asc_edge_cases_test), 1549 KUNIT_CASE(hfsplus_asc2uni_basic_test), 1550 KUNIT_CASE(hfsplus_asc2uni_special_chars_test), 1551 KUNIT_CASE(hfsplus_asc2uni_buffer_limits_test), 1552 KUNIT_CASE(hfsplus_asc2uni_edge_cases_test), 1553 KUNIT_CASE(hfsplus_asc2uni_decompose_test), 1554 KUNIT_CASE(hfsplus_hash_dentry_basic_test), 1555 KUNIT_CASE(hfsplus_hash_dentry_casefold_test), 1556 KUNIT_CASE(hfsplus_hash_dentry_special_chars_test), 1557 KUNIT_CASE(hfsplus_hash_dentry_decompose_test), 1558 KUNIT_CASE(hfsplus_hash_dentry_consistency_test), 1559 KUNIT_CASE(hfsplus_hash_dentry_edge_cases_test), 1560 KUNIT_CASE(hfsplus_compare_dentry_basic_test), 1561 KUNIT_CASE(hfsplus_compare_dentry_casefold_test), 1562 KUNIT_CASE(hfsplus_compare_dentry_special_chars_test), 1563 KUNIT_CASE(hfsplus_compare_dentry_length_test), 1564 KUNIT_CASE(hfsplus_compare_dentry_decompose_test), 1565 KUNIT_CASE(hfsplus_compare_dentry_edge_cases_test), 1566 KUNIT_CASE(hfsplus_compare_dentry_combined_flags_test), 1567 {} 1568 }; 1569 1570 static struct kunit_suite hfsplus_unicode_test_suite = { 1571 .name = "hfsplus_unicode", 1572 .test_cases = hfsplus_unicode_test_cases, 1573 }; 1574 1575 kunit_test_suite(hfsplus_unicode_test_suite); 1576 1577 MODULE_DESCRIPTION("KUnit tests for HFS+ Unicode string operations"); 1578 MODULE_LICENSE("GPL"); 1579 MODULE_IMPORT_NS("EXPORTED_FOR_KUNIT_TESTING"); 1580