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