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