* @brief Tests equivalence of case folding implementations (serial vs SIMD). * * Generates random UTF-8 strings containing: * - ASCII text (uppercase and lowercase) * - Multi-byte UTF-8 characters from various scripts (Cyrillic, Greek, Latin Extended) * - Special cases like German ß * * For each generated string, compares byte-by-byte output of both implementations. */
| 541 | * For each generated string, compares byte-by-byte output of both implementations. |
| 542 | */ |
| 543 | void test_utf8_case_fold_equivalence( // |
| 544 | sz_utf8_case_fold_t fold_base, sz_utf8_case_fold_t fold_simd, // |
| 545 | std::size_t min_text_length = 4000, std::size_t min_iterations = 10000) { |
| 546 | |
| 547 | // Output buffers (3x input for worst-case expansion) |
| 548 | std::vector<char> output_base(min_text_length * 3 + 256); |
| 549 | std::vector<char> output_simd(min_text_length * 3 + 256); |
| 550 | |
| 551 | auto check = [&](std::string const &text) { |
| 552 | // Ensure buffers are large enough |
| 553 | if (output_base.size() < text.size() * 3 + 64) { |
| 554 | output_base.resize(text.size() * 3 + 64); |
| 555 | output_simd.resize(text.size() * 3 + 64); |
| 556 | } |
| 557 | |
| 558 | sz_size_t len_base = fold_base(text.data(), text.size(), output_base.data()); |
| 559 | sz_size_t len_simd = fold_simd(text.data(), text.size(), output_simd.data()); |
| 560 | |
| 561 | if (len_base != len_simd) { |
| 562 | std::fprintf(stderr, "Case fold length mismatch: base=%zu, simd=%zu, input_len=%zu\n", // |
| 563 | len_base, len_simd, text.size()); |
| 564 | // Print first divergence |
| 565 | for (std::size_t i = 0; i < std::min(len_base, len_simd); ++i) { |
| 566 | if (output_base[i] != output_simd[i]) { |
| 567 | std::fprintf(stderr, "First byte diff at output[%zu]: base=0x%02X, simd=0x%02X\n", // |
| 568 | i, (unsigned char)output_base[i], (unsigned char)output_simd[i]); |
| 569 | break; |
| 570 | } |
| 571 | } |
| 572 | assert(len_base == len_simd && "Case fold length mismatch"); |
| 573 | } |
| 574 | |
| 575 | for (sz_size_t i = 0; i < len_base; ++i) { |
| 576 | if (output_base[i] != output_simd[i]) { |
| 577 | std::fprintf(stderr, "Case fold content mismatch at byte %zu: base=0x%02X, simd=0x%02X\n", // |
| 578 | i, (unsigned char)output_base[i], (unsigned char)output_simd[i]); |
| 579 | // Show context around the mismatch |
| 580 | std::size_t start = i > 10 ? i - 10 : 0; |
| 581 | std::size_t end = std::min(i + 10, (std::size_t)len_base); |
| 582 | std::fprintf(stderr, "Base output[%zu..%zu]: ", start, end); |
| 583 | for (std::size_t j = start; j < end; ++j) std::fprintf(stderr, "%02X ", (unsigned char)output_base[j]); |
| 584 | std::fprintf(stderr, "\nSIMD output[%zu..%zu]: ", start, end); |
| 585 | for (std::size_t j = start; j < end; ++j) std::fprintf(stderr, "%02X ", (unsigned char)output_simd[j]); |
| 586 | std::fprintf(stderr, "\n"); |
| 587 | assert(output_base[i] == output_simd[i] && "Case fold content mismatch"); |
| 588 | } |
| 589 | } |
| 590 | }; |
| 591 | |
| 592 | // Test content - mix of scripts with case folding rules |
| 593 | static char const *utf8_content[] = { |
| 594 | // ASCII |
| 595 | "", |
| 596 | "a", |
| 597 | "A", |
| 598 | "hello", |
| 599 | "HELLO", |
| 600 | "Hello World", |
no test coverage detected
searching dependent graphs…