OXYGENHUB
◆ v0.4.4 oxygen / vendor / crc-fast / src / test / future_proof_tests.rs
52.1 KiB · Rust · last changed Strata: the cloud stores send through ureq, so every release target links 1 month ago source blame history raw
2cd40ea1 Andy McCall ↶ 1
// Copyright 2025 Don MacAskill. Licensed under MIT or Apache-2.0.
2
3
//! Tests for future-proof CrcKeysStorage and CrcParams functionality
4
5
#![cfg(test)]
6
7
use crate::{CrcAlgorithm, CrcKeysStorage, CrcParams};
8
9
#[test]
10
fn test_crc_keys_storage_bounds_checking() {
11
    // Test KeysFold256 variant (23 keys)
12
    let keys_23 = [1u64; 23];
13
    let storage_23 = CrcKeysStorage::from_keys_fold_256(keys_23);
14
15
    // Test valid indices
16
    for i in 0..23 {
17
        assert_eq!(
18
            storage_23.get_key(i),
19
            1,
20
            "Valid index {} should return key value",
21
            i
22
        );
23
    }
24
25
    // Test out-of-bounds indices return 0
26
    assert_eq!(
27
        storage_23.get_key(23),
28
        0,
29
        "Index 23 should return 0 for 23-key storage"
30
    );
31
    assert_eq!(
32
        storage_23.get_key(24),
33
        0,
34
        "Index 24 should return 0 for 23-key storage"
35
    );
36
    assert_eq!(
37
        storage_23.get_key(100),
38
        0,
39
        "Large index should return 0 for 23-key storage"
40
    );
41
42
    // Test KeysFutureTest variant (25 keys)
43
    let keys_25 = [2u64; 25];
44
    let storage_25 = CrcKeysStorage::from_keys_fold_future_test(keys_25);
45
46
    // Test valid indices
47
    for i in 0..25 {
48
        assert_eq!(
49
            storage_25.get_key(i),
50
            2,
51
            "Valid index {} should return key value",
52
            i
53
        );
54
    }
55
56
    // Test out-of-bounds indices return 0
57
    assert_eq!(
58
        storage_25.get_key(25),
59
        0,
60
        "Index 25 should return 0 for 25-key storage"
61
    );
62
    assert_eq!(
63
        storage_25.get_key(26),
64
        0,
65
        "Index 26 should return 0 for 25-key storage"
66
    );
67
    assert_eq!(
68
        storage_25.get_key(100),
69
        0,
70
        "Large index should return 0 for 25-key storage"
71
    );
72
}
73
74
#[test]
75
#[allow(deprecated)]
76
fn test_crc_params_get_key_checked() {
77
    // Create test CrcParams with 23-key storage
78
    let keys_23 = [42u64; 23];
79
    let params_23 = CrcParams {
80
        algorithm: CrcAlgorithm::Crc32Custom,
81
        name: "Test CRC",
82
        width: 32,
83
        poly: 0x1EDC6F41,
84
        init: 0xFFFFFFFF,
85
        init_algorithm: 0xFFFFFFFF,
86
        refin: true,
87
        refout: true,
88
        xorout: 0xFFFFFFFF,
89
        check: 0x12345678,
90
        keys: CrcKeysStorage::from_keys_fold_256(keys_23),
91
    };
92
93
    // Test valid indices return Some(value)
94
    for i in 0..23 {
95
        assert_eq!(
96
            params_23.get_key_checked(i),
97
            Some(42),
98
            "Valid index {} should return Some(42)",
99
            i
100
        );
101
    }
102
103
    // Test out-of-bounds indices return None
104
    assert_eq!(
105
        params_23.get_key_checked(23),
106
        None,
107
        "Index 23 should return None for 23-key params"
108
    );
109
    assert_eq!(
110
        params_23.get_key_checked(24),
111
        None,
112
        "Index 24 should return None for 23-key params"
113
    );
114
    assert_eq!(
115
        params_23.get_key_checked(100),
116
        None,
117
        "Large index should return None for 23-key params"
118
    );
119
120
    // Create test CrcParams with 25-key storage
121
    let keys_25 = [84u64; 25];
122
    let params_25 = CrcParams {
123
        algorithm: CrcAlgorithm::Crc64Custom,
124
        name: "Test CRC 64",
125
        width: 64,
126
        poly: 0x42F0E1EBA9EA3693,
127
        init: 0xFFFFFFFFFFFFFFFF,
128
        init_algorithm: 0xFFFFFFFFFFFFFFFF,
129
        refin: true,
130
        refout: true,
131
        xorout: 0xFFFFFFFFFFFFFFFF,
132
        check: 0x123456789ABCDEF0,
133
        keys: CrcKeysStorage::from_keys_fold_future_test(keys_25),
134
    };
135
136
    // Test valid indices return Some(value)
137
    for i in 0..25 {
138
        assert_eq!(
139
            params_25.get_key_checked(i),
140
            Some(84),
141
            "Valid index {} should return Some(84)",
142
            i
143
        );
144
    }
145
146
    // Test out-of-bounds indices return None
147
    assert_eq!(
148
        params_25.get_key_checked(25),
149
        None,
150
        "Index 25 should return None for 25-key params"
151
    );
152
    assert_eq!(
153
        params_25.get_key_checked(26),
154
        None,
155
        "Index 26 should return None for 25-key params"
156
    );
157
    assert_eq!(
158
        params_25.get_key_checked(100),
159
        None,
160
        "Large index should return None for 25-key params"
161
    );
162
}
163
164
#[test]
165
#[allow(deprecated)]
166
fn test_key_count_returns_correct_values() {
167
    // Test KeysFold256 variant
168
    let keys_23 = [1u64; 23];
169
    let storage_23 = CrcKeysStorage::from_keys_fold_256(keys_23);
170
    assert_eq!(
171
        storage_23.key_count(),
172
        23,
173
        "KeysFold256 should report 23 keys"
174
    );
175
176
    let params_23 = CrcParams {
177
        algorithm: CrcAlgorithm::Crc32Custom,
178
        name: "Test CRC",
179
        width: 32,
180
        poly: 0x1EDC6F41,
181
        init: 0xFFFFFFFF,
182
        init_algorithm: 0xFFFFFFFF,
183
        refin: true,
184
        refout: true,
185
        xorout: 0xFFFFFFFF,
186
        check: 0x12345678,
187
        keys: storage_23,
188
    };
189
    assert_eq!(
190
        params_23.key_count(),
191
        23,
192
        "CrcParams with KeysFold256 should report 23 keys"
193
    );
194
195
    // Test KeysFutureTest variant
196
    let keys_25 = [2u64; 25];
197
    let storage_25 = CrcKeysStorage::from_keys_fold_future_test(keys_25);
198
    assert_eq!(
199
        storage_25.key_count(),
200
        25,
201
        "KeysFutureTest should report 25 keys"
202
    );
203
204
    let params_25 = CrcParams {
205
        algorithm: CrcAlgorithm::Crc64Custom,
206
        name: "Test CRC 64",
207
        width: 64,
208
        poly: 0x42F0E1EBA9EA3693,
209
        init: 0xFFFFFFFFFFFFFFFF,
210
        init_algorithm: 0xFFFFFFFFFFFFFFFF,
211
        refin: true,
212
        refout: true,
213
        xorout: 0xFFFFFFFFFFFFFFFF,
214
        check: 0x123456789ABCDEF0,
215
        keys: storage_25,
216
    };
217
    assert_eq!(
218
        params_25.key_count(),
219
        25,
220
        "CrcParams with KeysFutureTest should report 25 keys"
221
    );
222
}
223
224
#[test]
225
#[allow(deprecated)]
226
fn test_crc_params_get_key_bounds_checking() {
227
    // Create test CrcParams with 23-key storage
228
    let keys_23 = [99u64; 23];
229
    let params_23 = CrcParams {
230
        algorithm: CrcAlgorithm::Crc32Custom,
231
        name: "Test CRC",
232
        width: 32,
233
        poly: 0x1EDC6F41,
234
        init: 0xFFFFFFFF,
235
        init_algorithm: 0xFFFFFFFF,
236
        refin: true,
237
        refout: true,
238
        xorout: 0xFFFFFFFF,
239
        check: 0x12345678,
240
        keys: CrcKeysStorage::from_keys_fold_256(keys_23),
241
    };
242
243
    // Test valid indices
244
    for i in 0..23 {
245
        assert_eq!(
246
            params_23.get_key(i),
247
            99,
248
            "Valid index {} should return 99",
249
            i
250
        );
251
    }
252
253
    // Test out-of-bounds indices return 0
254
    assert_eq!(
255
        params_23.get_key(23),
256
        0,
257
        "Index 23 should return 0 for 23-key params"
258
    );
259
    assert_eq!(
260
        params_23.get_key(24),
261
        0,
262
        "Index 24 should return 0 for 23-key params"
263
    );
264
    assert_eq!(
265
        params_23.get_key(100),
266
        0,
267
        "Large index should return 0 for 23-key params"
268
    );
269
}
270
271
#[test]
272
#[allow(deprecated)]
273
fn test_third_party_const_definitions_compatibility() {
274
    // Mock third-party const definitions using the new format
275
    // These simulate how third-party applications would define custom CrcParams
276
277
    // Mock third-party CRC-32 definition (similar to existing library constants)
278
    const MOCK_THIRD_PARTY_CRC32: CrcParams = CrcParams {
279
        algorithm: CrcAlgorithm::Crc32Custom,
280
        name: "Mock Third Party CRC-32",
281
        width: 32,
282
        poly: 0x1EDC6F41,
283
        init: 0xFFFFFFFF,
284
        init_algorithm: 0xFFFFFFFF,
285
        refin: true,
286
        refout: true,
287
        xorout: 0xFFFFFFFF,
288
        check: 0xE3069283,
289
        keys: CrcKeysStorage::from_keys_fold_256([
290
            0x1234567890ABCDEF,
291
            0x2345678901BCDEF0,
292
            0x3456789012CDEF01,
293
            0x456789023DEF012,
294
            0x56789034EF0123,
295
            0x6789045F01234,
296
            0x789056012345,
297
            0x89067123456,
298
            0x9078234567,
299
            0xA089345678,
300
            0xB09A456789,
301
            0xC0AB56789A,
302
            0xD0BC6789AB,
303
            0xE0CD789ABC,
304
            0xF0DE89ABCD,
305
            0x10EF9ABCDE,
306
            0x210ABCDEF0,
307
            0x321BCDEF01,
308
            0x432CDEF012,
309
            0x543DEF0123,
310
            0x654EF01234,
311
            0x765F012345,
312
            0x876012345,
313
        ]),
314
    };
315
316
    // Mock third-party CRC-64 definition
317
    const MOCK_THIRD_PARTY_CRC64: CrcParams = CrcParams {
318
        algorithm: CrcAlgorithm::Crc64Custom,
319
        name: "Mock Third Party CRC-64",
320
        width: 64,
321
        poly: 0x42F0E1EBA9EA3693,
322
        init: 0xFFFFFFFFFFFFFFFF,
323
        init_algorithm: 0xFFFFFFFFFFFFFFFF,
324
        refin: true,
325
        refout: true,
326
        xorout: 0xFFFFFFFFFFFFFFFF,
327
        check: 0x6C40DF5F0B497347,
328
        keys: CrcKeysStorage::from_keys_fold_256([
329
            0xFEDCBA0987654321,
330
            0xEDCBA09876543210,
331
            0xDCBA098765432101,
332
            0xCBA0987654321012,
333
            0xBA09876543210123,
334
            0xA098765432101234,
335
            0x9087654321012345,
336
            0x8076543210123456,
337
            0x7065432101234567,
338
            0x6054321012345678,
339
            0x5043210123456789,
340
            0x403210123456789A,
341
            0x3210123456789AB,
342
            0x210123456789ABC,
343
            0x10123456789ABCD,
344
            0x123456789ABCDE,
345
            0x23456789ABCDEF,
346
            0x3456789ABCDEF0,
347
            0x456789ABCDEF01,
348
            0x56789ABCDEF012,
349
            0x6789ABCDEF0123,
350
            0x789ABCDEF01234,
351
            0x89ABCDEF012345,
352
        ]),
353
    };
354
355
    // Test that third-party const definitions work correctly
356
    assert_eq!(MOCK_THIRD_PARTY_CRC32.key_count(), 23);
357
    assert_eq!(MOCK_THIRD_PARTY_CRC64.key_count(), 23);
358
359
    // Test key access patterns that third-party code might use
360
    assert_eq!(MOCK_THIRD_PARTY_CRC32.get_key(0), 0x1234567890ABCDEF);
361
    assert_eq!(MOCK_THIRD_PARTY_CRC32.get_key(22), 0x876012345);
362
    assert_eq!(MOCK_THIRD_PARTY_CRC32.get_key(23), 0); // Out of bounds
363
364
    assert_eq!(MOCK_THIRD_PARTY_CRC64.get_key(0), 0xFEDCBA0987654321);
365
    assert_eq!(MOCK_THIRD_PARTY_CRC64.get_key(22), 0x89ABCDEF012345);
366
    assert_eq!(MOCK_THIRD_PARTY_CRC64.get_key(23), 0); // Out of bounds
367
368
    // Test that checked access works as expected
369
    assert_eq!(
370
        MOCK_THIRD_PARTY_CRC32.get_key_checked(0),
371
        Some(0x1234567890ABCDEF)
372
    );
373
    assert_eq!(
374
        MOCK_THIRD_PARTY_CRC32.get_key_checked(22),
375
        Some(0x876012345)
376
    );
377
    assert_eq!(MOCK_THIRD_PARTY_CRC32.get_key_checked(23), None);
378
379
    assert_eq!(
380
        MOCK_THIRD_PARTY_CRC64.get_key_checked(0),
381
        Some(0xFEDCBA0987654321)
382
    );
383
    assert_eq!(
384
        MOCK_THIRD_PARTY_CRC64.get_key_checked(22),
385
        Some(0x89ABCDEF012345)
386
    );
387
    assert_eq!(MOCK_THIRD_PARTY_CRC64.get_key_checked(23), None);
388
}
389
390
#[test]
391
#[allow(clippy::needless_range_loop)] // Intentionally testing indexed key access patterns
392
#[allow(deprecated)]
393
fn test_existing_key_access_patterns_continue_to_work() {
394
    // Test that common key access patterns used by existing code continue to work
395
396
    let test_keys = [
397
        0x1111111111111111,
398
        0x2222222222222222,
399
        0x3333333333333333,
400
        0x4444444444444444,
401
        0x5555555555555555,
402
        0x6666666666666666,
403
        0x7777777777777777,
404
        0x8888888888888888,
405
        0x9999999999999999,
406
        0xAAAAAAAAAAAAAAAA,
407
        0xBBBBBBBBBBBBBBBB,
408
        0xCCCCCCCCCCCCCCCC,
409
        0xDDDDDDDDDDDDDDDD,
410
        0xEEEEEEEEEEEEEEEE,
411
        0xFFFFFFFFFFFFFFFF,
412
        0x1010101010101010,
413
        0x2020202020202020,
414
        0x3030303030303030,
415
        0x4040404040404040,
416
        0x5050505050505050,
417
        0x6060606060606060,
418
        0x7070707070707070,
419
        0x8080808080808080,
420
    ];
421
422
    let params = CrcParams {
423
        algorithm: CrcAlgorithm::Crc32Custom,
424
        name: "Test Pattern Access",
425
        width: 32,
426
        poly: 0x1EDC6F41,
427
        init: 0xFFFFFFFF,
428
        init_algorithm: 0xFFFFFFFF,
429
        refin: true,
430
        refout: true,
431
        xorout: 0xFFFFFFFF,
432
        check: 0x12345678,
433
        keys: CrcKeysStorage::from_keys_fold_256(test_keys),
434
    };
435
436
    // Pattern 1: Sequential access (common in folding algorithms)
437
    for i in 0..23 {
438
        let expected = test_keys[i];
439
        assert_eq!(
440
            params.get_key(i),
441
            expected,
442
            "Sequential access failed at index {}",
443
            i
444
        );
445
    }
446
447
    // Pattern 2: Reverse access (sometimes used in algorithms)
448
    for i in (0..23).rev() {
449
        let expected = test_keys[i];
450
        assert_eq!(
451
            params.get_key(i),
452
            expected,
453
            "Reverse access failed at index {}",
454
            i
455
        );
456
    }
457
458
    // Pattern 3: Specific indices commonly used in folding (powers of 2, etc.)
459
    let common_indices = [0, 1, 2, 4, 8, 16, 22];
460
    for &i in &common_indices {
461
        if i < 23 {
462
            let expected = test_keys[i];
463
            assert_eq!(
464
                params.get_key(i),
465
                expected,
466
                "Common index access failed at index {}",
467
                i
468
            );
469
        }
470
    }
471
472
    // Pattern 4: Bounds checking that third-party code might rely on
473
    assert_eq!(
474
        params.get_key(23),
475
        0,
476
        "Out-of-bounds access should return 0"
477
    );
478
    assert_eq!(
479
        params.get_key(100),
480
        0,
481
        "Large out-of-bounds access should return 0"
482
    );
483
}
484
485
#[test]
486
#[allow(clippy::needless_range_loop)] // Intentionally testing indexed key access for backwards compatibility
487
#[allow(deprecated)]
488
fn test_backwards_compatibility_throughout_migration_phases() {
489
    // This test simulates the migration phases to ensure backwards compatibility
490
491
    // Phase 1 & 2: Original array-based access patterns (simulated)
492
    let test_keys = [0x123456789ABCDEF0u64; 23];
493
    let storage = CrcKeysStorage::from_keys_fold_256(test_keys);
494
495
    // Verify that the storage behaves identically to direct array access
496
    for i in 0..23 {
497
        assert_eq!(
498
            storage.get_key(i),
499
            test_keys[i],
500
            "Storage access should match array access at index {}",
501
            i
502
        );
503
    }
504
505
    // Phase 3: New CrcKeysStorage-based access
506
    let params = CrcParams {
507
        algorithm: CrcAlgorithm::Crc64Custom,
508
        name: "Migration Test",
509
        width: 64,
510
        poly: 0x42F0E1EBA9EA3693,
511
        init: 0x0000000000000000,
512
        init_algorithm: 0x0000000000000000,
513
        refin: false,
514
        refout: false,
515
        xorout: 0x0000000000000000,
516
        check: 0x6C40DF5F0B497347,
517
        keys: storage,
518
    };
519
520
    // Verify that CrcParams provides the same access patterns
521
    for i in 0..23 {
522
        assert_eq!(
523
            params.get_key(i),
524
            test_keys[i],
525
            "CrcParams access should match array access at index {}",
526
            i
527
        );
528
        assert_eq!(
529
            params.get_key_checked(i),
530
            Some(test_keys[i]),
531
            "CrcParams checked access should match array access at index {}",
532
            i
533
        );
534
    }
535
536
    // Verify bounds checking works consistently
537
    assert_eq!(params.get_key(23), 0, "Out-of-bounds should return 0");
538
    assert_eq!(
539
        params.get_key_checked(23),
540
        None,
541
        "Out-of-bounds checked should return None"
542
    );
543
544
    // Verify key count is correct
545
    assert_eq!(params.key_count(), 23, "Key count should be 23");
546
547
    // Test compatibility with existing comparison operations
548
    assert_eq!(
549
        storage.to_keys_array_23(),
550
        test_keys,
551
        "Storage should convert back to original array"
552
    );
553
    assert_eq!(
554
        storage, test_keys,
555
        "Storage should compare equal to original array"
556
    );
557
    assert_eq!(
558
        test_keys, storage,
559
        "Original array should compare equal to storage"
560
    );
561
}
562
563
#[test]
564
#[allow(clippy::needless_range_loop)] // Intentionally testing indexed access performance
565
#[allow(deprecated)]
566
fn test_key_access_performance_matches_direct_array_access() {
567
    // This test verifies that CrcKeysStorage key access has zero runtime overhead
568
    // compared to direct array access. While we can't easily measure exact timing
569
    // in a unit test, we can verify that the compiler optimizations work correctly
570
    // by testing that the behavior is identical and that large-scale access works efficiently.
571
572
    // Create test keys with different values to avoid XOR cancellation
573
    let test_keys = [
574
        0x1111111111111111,
575
        0x2222222222222222,
576
        0x3333333333333333,
577
        0x4444444444444444,
578
        0x5555555555555555,
579
        0x6666666666666666,
580
        0x7777777777777777,
581
        0x8888888888888888,
582
        0x9999999999999999,
583
        0xAAAAAAAAAAAAAAAA,
584
        0xBBBBBBBBBBBBBBBB,
585
        0xCCCCCCCCCCCCCCCC,
586
        0xDDDDDDDDDDDDDDDD,
587
        0xEEEEEEEEEEEEEEEE,
588
        0xFFFFFFFFFFFFFFFF,
589
        0x1010101010101010,
590
        0x2020202020202020,
591
        0x3030303030303030,
592
        0x4040404040404040,
593
        0x5050505050505050,
594
        0x6060606060606060,
595
        0x7070707070707070,
596
        0x8080808080808080,
597
    ];
598
    let storage = CrcKeysStorage::from_keys_fold_256(test_keys);
599
600
    let params = CrcParams {
601
        algorithm: CrcAlgorithm::Crc32Custom,
602
        name: "Performance Test",
603
        width: 32,
604
        poly: 0x1EDC6F41,
605
        init: 0xFFFFFFFF,
606
        init_algorithm: 0xFFFFFFFF,
607
        refin: true,
608
        refout: true,
609
        xorout: 0xFFFFFFFF,
610
        check: 0x12345678,
611
        keys: storage,
612
    };
613
614
    // Simulate intensive key access patterns that would reveal performance issues
615
    let iterations = 1000;
616
    let mut checksum = 0u64;
617
618
    // Pattern 1: Sequential access (most common in real algorithms)
619
    for iteration in 0..iterations {
620
        for i in 0..23 {
621
            checksum = checksum.wrapping_add(params.get_key(i).wrapping_mul(iteration as u64 + 1));
622
        }
623
    }
624
625
    // Pattern 2: Random access pattern
626
    let access_pattern = [
627
        0, 5, 12, 3, 18, 7, 22, 1, 15, 9, 20, 4, 11, 16, 2, 19, 8, 14, 6, 21, 10, 17, 13,
628
    ];
629
    for iteration in 0..iterations {
630
        for &i in &access_pattern {
631
            checksum = checksum.wrapping_add(params.get_key(i).wrapping_mul(iteration as u64 + 2));
632
        }
633
    }
634
635
    // Verify that we actually accessed the keys (checksum should be non-zero)
636
    assert_ne!(checksum, 0, "Performance test should have accessed keys");
637
638
    // Test that bounds checking doesn't significantly impact performance
639
    let mut bounds_checksum = 0u64;
640
    for iteration in 0..iterations {
641
        for i in 0..30 {
642
            // Include some out-of-bounds accesses
643
            bounds_checksum =
644
                bounds_checksum.wrapping_add(params.get_key(i).wrapping_mul(iteration as u64 + 3));
645
        }
646
    }
647
648
    // The bounds-checked version should still work correctly
649
    assert_ne!(
650
        bounds_checksum, 0,
651
        "Bounds checking performance test should work"
652
    );
653
}
654
655
#[test]
656
fn test_crc_calculation_performance_before_and_after_changes() {
657
    // Test that CRC calculation performance remains identical with the new key storage
658
    use crate::{checksum, CrcAlgorithm};
659
660
    // Test data of various sizes to ensure performance across different scenarios
661
    let test_data_small = b"123456789";
662
    let test_data_medium = vec![0xAAu8; 1024]; // 1KB
663
    let test_data_large = vec![0x55u8; 65536]; // 64KB
664
665
    // Test multiple CRC algorithms to ensure consistent performance
666
    let algorithms = [
667
        CrcAlgorithm::Crc32IsoHdlc,
668
        CrcAlgorithm::Crc32Iscsi,
669
        CrcAlgorithm::Crc64Nvme,
670
        CrcAlgorithm::Crc64Ecma182,
671
    ];
672
673
    for algorithm in algorithms {
674
        // Small data performance
675
        let result_small = checksum(algorithm, test_data_small);
676
        assert_ne!(
677
            result_small, 0,
678
            "Small data CRC should produce non-zero result"
679
        );
680
681
        // Medium data performance
682
        let result_medium = checksum(algorithm, &test_data_medium);
683
        assert_ne!(
684
            result_medium, 0,
685
            "Medium data CRC should produce non-zero result"
686
        );
687
688
        // Large data performance (this would reveal significant performance regressions)
689
        let result_large = checksum(algorithm, &test_data_large);
690
        assert_ne!(
691
            result_large, 0,
692
            "Large data CRC should produce non-zero result"
693
        );
694
695
        // Verify consistency across multiple runs (performance should be deterministic)
696
        let result_small_2 = checksum(algorithm, test_data_small);
697
        assert_eq!(
698
            result_small, result_small_2,
699
            "CRC results should be consistent"
700
        );
701
    }
702
}
703
704
#[test]
705
#[allow(deprecated)]
706
fn test_memory_usage_impact_of_enum_based_storage() {
707
    // Test that enum-based storage doesn't significantly increase memory usage
708
    use std::mem;
709
710
    // Test memory size of different storage variants
711
    let keys_23 = [0u64; 23];
712
    let keys_25 = [0u64; 25];
713
714
    let storage_23 = CrcKeysStorage::from_keys_fold_256(keys_23);
715
    let storage_25 = CrcKeysStorage::from_keys_fold_future_test(keys_25);
716
717
    // Verify that enum storage size is reasonable
718
    let storage_23_size = mem::size_of_val(&storage_23);
719
    let storage_25_size = mem::size_of_val(&storage_25);
720
    let _array_23_size = mem::size_of_val(&keys_23);
721
    let array_25_size = mem::size_of_val(&keys_25);
722
723
    // Rust enums use the size of the largest variant plus discriminant/alignment
724
    // Both variants will be the same size (size of largest variant)
725
    assert_eq!(
726
        storage_23_size, storage_25_size,
727
        "Both enum variants should have the same size"
728
    );
729
730
    // The enum size should be reasonable (largest variant + small overhead)
731
    assert!(
732
        storage_23_size >= array_25_size,
733
        "Enum should be at least as large as the largest variant"
734
    );
735
    assert!(
736
        storage_23_size <= array_25_size + 16,
737
        "Enum should not add excessive overhead beyond largest variant"
738
    );
739
740
    // Test CrcParams memory usage
741
    let params_23 = CrcParams {
742
        algorithm: CrcAlgorithm::Crc32Custom,
743
        name: "Memory Test 23",
744
        width: 32,
745
        poly: 0x1EDC6F41,
746
        init: 0xFFFFFFFF,
747
        init_algorithm: 0xFFFFFFFF,
748
        refin: true,
749
        refout: true,
750
        xorout: 0xFFFFFFFF,
751
        check: 0x12345678,
752
        keys: storage_23,
753
    };
754
755
    let params_25 = CrcParams {
756
        algorithm: CrcAlgorithm::Crc64Custom,
757
        name: "Memory Test 25",
758
        width: 64,
759
        poly: 0x42F0E1EBA9EA3693,
760
        init: 0xFFFFFFFFFFFFFFFF,
761
        init_algorithm: 0xFFFFFFFFFFFFFFFF,
762
        refin: true,
763
        refout: true,
764
        xorout: 0xFFFFFFFFFFFFFFFF,
765
        check: 0x123456789ABCDEF0,
766
        keys: storage_25,
767
    };
768
769
    let params_23_size = mem::size_of_val(&params_23);
770
    let params_25_size = mem::size_of_val(&params_25);
771
772
    // CrcParams should have reasonable size differences based on key storage
773
    assert!(
774
        params_25_size >= params_23_size,
775
        "25-key params should be at least as large as 23-key params"
776
    );
777
    assert!(
778
        params_25_size - params_23_size <= 16,
779
        "Size difference should be reasonable (just the extra keys)"
780
    );
781
782
    // Verify that the structs are still reasonably sized
783
    assert!(
784
        params_23_size < 512,
785
        "CrcParams should not be excessively large"
786
    );
787
    assert!(
788
        params_25_size < 512,
789
        "CrcParams should not be excessively large"
790
    );
791
}
792
793
#[test]
794
fn test_compiler_optimizations_eliminate_enum_dispatch() {
795
    // This test verifies that compiler optimizations work correctly by testing
796
    // that enum dispatch doesn't introduce runtime branching in hot paths
797
798
    // Create different keys to avoid XOR cancellation
799
    let keys_23 = [
800
        0x1111111111111111,
801
        0x2222222222222222,
802
        0x3333333333333333,
803
        0x4444444444444444,
804
        0x5555555555555555,
805
        0x6666666666666666,
806
        0x7777777777777777,
807
        0x8888888888888888,
808
        0x9999999999999999,
809
        0xAAAAAAAAAAAAAAAA,
810
        0xBBBBBBBBBBBBBBBB,
811
        0xCCCCCCCCCCCCCCCC,
812
        0xDDDDDDDDDDDDDDDD,
813
        0xEEEEEEEEEEEEEEEE,
814
        0xFFFFFFFFFFFFFFFF,
815
        0x1010101010101010,
816
        0x2020202020202020,
817
        0x3030303030303030,
818
        0x4040404040404040,
819
        0x5050505050505050,
820
        0x6060606060606060,
821
        0x7070707070707070,
822
        0x8080808080808080,
823
    ];
824
    let keys_25 = [
825
        0x1111111111111111,
826
        0x2222222222222222,
827
        0x3333333333333333,
828
        0x4444444444444444,
829
        0x5555555555555555,
830
        0x6666666666666666,
831
        0x7777777777777777,
832
        0x8888888888888888,
833
        0x9999999999999999,
834
        0xAAAAAAAAAAAAAAAA,
835
        0xBBBBBBBBBBBBBBBB,
836
        0xCCCCCCCCCCCCCCCC,
837
        0xDDDDDDDDDDDDDDDD,
838
        0xEEEEEEEEEEEEEEEE,
839
        0xFFFFFFFFFFFFFFFF,
840
        0x1010101010101010,
841
        0x2020202020202020,
842
        0x3030303030303030,
843
        0x4040404040404040,
844
        0x5050505050505050,
845
        0x6060606060606060,
846
        0x7070707070707070,
847
        0x8080808080808080,
848
        0x9090909090909090,
849
        0xA0A0A0A0A0A0A0A0,
850
    ];
851
852
    let storage_23 = CrcKeysStorage::from_keys_fold_256(keys_23);
853
    let storage_25 = CrcKeysStorage::from_keys_fold_future_test(keys_25);
854
855
    // Test that repeated access to the same storage type is efficient
856
    // (compiler should optimize away the enum matching)
857
    let mut sum_23 = 0u64;
858
    for iteration in 0..100 {
859
        for i in 0..23 {
860
            sum_23 = sum_23.wrapping_add(storage_23.get_key(i).wrapping_mul(iteration + 1));
861
        }
862
    }
863
864
    let mut sum_25 = 0u64;
865
    for iteration in 0..100 {
866
        for i in 0..25 {
867
            sum_25 = sum_25.wrapping_add(storage_25.get_key(i).wrapping_mul(iteration + 1));
868
        }
869
    }
870
871
    // Verify that the operations actually happened
872
    assert_ne!(
873
        sum_23, 0,
874
        "23-key operations should produce non-zero result"
875
    );
876
    assert_ne!(
877
        sum_25, 0,
878
        "25-key operations should produce non-zero result"
879
    );
880
881
    // Test mixed access patterns (this would reveal optimization issues)
882
    let storages = [storage_23, storage_25];
883
    let mut mixed_sum = 0u64;
884
885
    for iteration in 0..100 {
886
        for (storage_idx, storage) in storages.iter().enumerate() {
887
            let key_count = storage.key_count();
888
            for i in 0..key_count {
889
                mixed_sum = mixed_sum.wrapping_add(
890
                    storage
891
                        .get_key(i)
892
                        .wrapping_mul((iteration + storage_idx + 1) as u64),
893
                );
894
            }
895
        }
896
    }
897
898
    assert_ne!(mixed_sum, 0, "Mixed access should produce non-zero result");
899
}
900
#[test]
901
#[allow(clippy::needless_range_loop)] // Intentionally testing indexed key access for future variant
902
#[allow(deprecated)]
903
fn test_create_crc_params_using_keys_future_test_variant() {
904
    // Create test CrcParams using KeysFutureTest variant with 25 keys
905
    let test_keys_25 = [
906
        0x1111111111111111,
907
        0x2222222222222222,
908
        0x3333333333333333,
909
        0x4444444444444444,
910
        0x5555555555555555,
911
        0x6666666666666666,
912
        0x7777777777777777,
913
        0x8888888888888888,
914
        0x9999999999999999,
915
        0xAAAAAAAAAAAAAAAA,
916
        0xBBBBBBBBBBBBBBBB,
917
        0xCCCCCCCCCCCCCCCC,
918
        0xDDDDDDDDDDDDDDDD,
919
        0xEEEEEEEEEEEEEEEE,
920
        0xFFFFFFFFFFFFFFFF,
921
        0x1010101010101010,
922
        0x2020202020202020,
923
        0x3030303030303030,
924
        0x4040404040404040,
925
        0x5050505050505050,
926
        0x6060606060606060,
927
        0x7070707070707070,
928
        0x8080808080808080,
929
        0x9090909090909090,
930
        0xA0A0A0A0A0A0A0A0,
931
    ];
932
933
    let future_params = CrcParams {
934
        algorithm: CrcAlgorithm::Crc64Custom,
935
        name: "Future Test CRC-64",
936
        width: 64,
937
        poly: 0x42F0E1EBA9EA3693,
938
        init: 0xFFFFFFFFFFFFFFFF,
939
        init_algorithm: 0xFFFFFFFFFFFFFFFF,
940
        refin: true,
941
        refout: true,
942
        xorout: 0xFFFFFFFFFFFFFFFF,
943
        check: 0x123456789ABCDEF0,
944
        keys: CrcKeysStorage::from_keys_fold_future_test(test_keys_25),
945
    };
946
947
    // Verify that the future params work correctly
948
    assert_eq!(
949
        future_params.key_count(),
950
        25,
951
        "Future params should have 25 keys"
952
    );
953
954
    // Test access to all 25 keys
955
    for i in 0..25 {
956
        assert_eq!(
957
            future_params.get_key(i),
958
            test_keys_25[i],
959
            "Key {} should match expected value",
960
            i
961
        );
962
        assert_eq!(
963
            future_params.get_key_checked(i),
964
            Some(test_keys_25[i]),
965
            "Checked key {} should return Some(value)",
966
            i
967
        );
968
    }
969
970
    // Test out-of-bounds access
971
    assert_eq!(
972
        future_params.get_key(25),
973
        0,
974
        "Key 25 should return 0 (out of bounds)"
975
    );
976
    assert_eq!(
977
        future_params.get_key_checked(25),
978
        None,
979
        "Checked key 25 should return None"
980
    );
981
    assert_eq!(
982
        future_params.get_key(30),
983
        0,
984
        "Key 30 should return 0 (out of bounds)"
985
    );
986
    assert_eq!(
987
        future_params.get_key_checked(30),
988
        None,
989
        "Checked key 30 should return None"
990
    );
991
}
992
993
#[test]
994
#[allow(deprecated)]
995
fn test_code_gracefully_handles_different_key_array_sizes() {
996
    // Test that the same code can handle both 23-key and 25-key variants gracefully
997
998
    let keys_23 = [0x1234567890ABCDEFu64; 23];
999
    let keys_25 = [0xFEDCBA0987654321u64; 25];
1000
1001
    let params_23 = CrcParams {
1002
        algorithm: CrcAlgorithm::Crc32Custom,
1003
        name: "23-Key Test",
1004
        width: 32,
1005
        poly: 0x1EDC6F41,
1006
        init: 0xFFFFFFFF,
1007
        init_algorithm: 0xFFFFFFFF,
1008
        refin: true,
1009
        refout: true,
1010
        xorout: 0xFFFFFFFF,
1011
        check: 0x12345678,
1012
        keys: CrcKeysStorage::from_keys_fold_256(keys_23),
1013
    };
1014
1015
    let params_25 = CrcParams {
1016
        algorithm: CrcAlgorithm::Crc64Custom,
1017
        name: "25-Key Test",
1018
        width: 64,
1019
        poly: 0x42F0E1EBA9EA3693,
1020
        init: 0xFFFFFFFFFFFFFFFF,
1021
        init_algorithm: 0xFFFFFFFFFFFFFFFF,
1022
        refin: true,
1023
        refout: true,
1024
        xorout: 0xFFFFFFFFFFFFFFFF,
1025
        check: 0x123456789ABCDEF0,
1026
        keys: CrcKeysStorage::from_keys_fold_future_test(keys_25),
1027
    };
1028
1029
    // Generic function that works with any CrcParams regardless of key count
1030
    fn process_crc_params(params: CrcParams) -> (usize, u64, u64) {
1031
        let key_count = params.key_count();
1032
        let first_key = params.get_key(0);
1033
        let last_valid_key = if key_count > 0 {
1034
            params.get_key(key_count - 1)
1035
        } else {
1036
            0
1037
        };
1038
        (key_count, first_key, last_valid_key)
1039
    }
1040
1041
    // Test that the same function works with both variants
1042
    let (count_23, first_23, last_23) = process_crc_params(params_23);
1043
    let (count_25, first_25, last_25) = process_crc_params(params_25);
1044
1045
    assert_eq!(count_23, 23, "23-key params should report 23 keys");
1046
    assert_eq!(count_25, 25, "25-key params should report 25 keys");
1047
1048
    assert_eq!(
1049
        first_23, 0x1234567890ABCDEF,
1050
        "23-key first key should match"
1051
    );
1052
    assert_eq!(
1053
        first_25, 0xFEDCBA0987654321,
1054
        "25-key first key should match"
1055
    );
1056
1057
    assert_eq!(last_23, 0x1234567890ABCDEF, "23-key last key should match");
1058
    assert_eq!(last_25, 0xFEDCBA0987654321, "25-key last key should match");
1059
1060
    // Test that bounds checking works consistently across variants
1061
    assert_eq!(
1062
        params_23.get_key(23),
1063
        0,
1064
        "23-key params should return 0 for index 23"
1065
    );
1066
    assert_eq!(
1067
        params_23.get_key(25),
1068
        0,
1069
        "23-key params should return 0 for index 25"
1070
    );
1071
1072
    assert_eq!(
1073
        params_25.get_key(25),
1074
        0,
1075
        "25-key params should return 0 for index 25"
1076
    );
1077
    assert_eq!(
1078
        params_25.get_key(30),
1079
        0,
1080
        "25-key params should return 0 for index 30"
1081
    );
1082
}
1083
1084
#[test]
1085
#[allow(deprecated)]
1086
fn test_expansion_to_larger_key_arrays_works_as_designed() {
1087
    // Test that the design supports expansion to larger key arrays
1088
1089
    // Simulate a migration scenario where we add more keys
1090
    let original_keys = [0x1111111111111111u64; 23];
1091
    let expanded_keys = [
1092
        // Original 23 keys
1093
        0x1111111111111111,
1094
        0x1111111111111111,
1095
        0x1111111111111111,
1096
        0x1111111111111111,
1097
        0x1111111111111111,
1098
        0x1111111111111111,
1099
        0x1111111111111111,
1100
        0x1111111111111111,
1101
        0x1111111111111111,
1102
        0x1111111111111111,
1103
        0x1111111111111111,
1104
        0x1111111111111111,
1105
        0x1111111111111111,
1106
        0x1111111111111111,
1107
        0x1111111111111111,
1108
        0x1111111111111111,
1109
        0x1111111111111111,
1110
        0x1111111111111111,
1111
        0x1111111111111111,
1112
        0x1111111111111111,
1113
        0x1111111111111111,
1114
        0x1111111111111111,
1115
        0x1111111111111111,
1116
        // Additional 2 keys for future expansion
1117
        0x2222222222222222,
1118
        0x3333333333333333,
1119
    ];
1120
1121
    let original_params = CrcParams {
1122
        algorithm: CrcAlgorithm::Crc32Custom,
1123
        name: "Original CRC",
1124
        width: 32,
1125
        poly: 0x1EDC6F41,
1126
        init: 0xFFFFFFFF,
1127
        init_algorithm: 0xFFFFFFFF,
1128
        refin: true,
1129
        refout: true,
1130
        xorout: 0xFFFFFFFF,
1131
        check: 0x12345678,
1132
        keys: CrcKeysStorage::from_keys_fold_256(original_keys),
1133
    };
1134
1135
    let expanded_params = CrcParams {
1136
        algorithm: CrcAlgorithm::Crc64Custom,
1137
        name: "Expanded CRC",
1138
        width: 64,
1139
        poly: 0x42F0E1EBA9EA3693,
1140
        init: 0xFFFFFFFFFFFFFFFF,
1141
        init_algorithm: 0xFFFFFFFFFFFFFFFF,
1142
        refin: true,
1143
        refout: true,
1144
        xorout: 0xFFFFFFFFFFFFFFFF,
1145
        check: 0x123456789ABCDEF0,
1146
        keys: CrcKeysStorage::from_keys_fold_future_test(expanded_keys),
1147
    };
1148
1149
    // Test that existing key access patterns continue to work
1150
    for i in 0..23 {
1151
        assert_eq!(
1152
            original_params.get_key(i),
1153
            0x1111111111111111,
1154
            "Original key {} should match",
1155
            i
1156
        );
1157
        assert_eq!(
1158
            expanded_params.get_key(i),
1159
            0x1111111111111111,
1160
            "Expanded key {} should match original",
1161
            i
1162
        );
1163
    }
1164
1165
    // Test that new keys are accessible in expanded version
1166
    assert_eq!(
1167
        expanded_params.get_key(23),
1168
        0x2222222222222222,
1169
        "New key 23 should be accessible"
1170
    );
1171
    assert_eq!(
1172
        expanded_params.get_key(24),
1173
        0x3333333333333333,
1174
        "New key 24 should be accessible"
1175
    );
1176
1177
    // Test that original version handles new indices gracefully
1178
    assert_eq!(
1179
        original_params.get_key(23),
1180
        0,
1181
        "Original should return 0 for new key indices"
1182
    );
1183
    assert_eq!(
1184
        original_params.get_key(24),
1185
        0,
1186
        "Original should return 0 for new key indices"
1187
    );
1188
1189
    // Test that both versions handle out-of-bounds access consistently
1190
    assert_eq!(
1191
        original_params.get_key(30),
1192
        0,
1193
        "Original should return 0 for out-of-bounds"
1194
    );
1195
    assert_eq!(
1196
        expanded_params.get_key(30),
1197
        0,
1198
        "Expanded should return 0 for out-of-bounds"
1199
    );
1200
1201
    // Test key count differences
1202
    assert_eq!(
1203
        original_params.key_count(),
1204
        23,
1205
        "Original should have 23 keys"
1206
    );
1207
    assert_eq!(
1208
        expanded_params.key_count(),
1209
        25,
1210
        "Expanded should have 25 keys"
1211
    );
1212
1213
    // Test that checked access works correctly for both
1214
    assert_eq!(
1215
        original_params.get_key_checked(22),
1216
        Some(0x1111111111111111),
1217
        "Original last key should be accessible"
1218
    );
1219
    assert_eq!(
1220
        original_params.get_key_checked(23),
1221
        None,
1222
        "Original should return None for index 23"
1223
    );
1224
1225
    assert_eq!(
1226
        expanded_params.get_key_checked(22),
1227
        Some(0x1111111111111111),
1228
        "Expanded key 22 should be accessible"
1229
    );
1230
    assert_eq!(
1231
        expanded_params.get_key_checked(24),
1232
        Some(0x3333333333333333),
1233
        "Expanded last key should be accessible"
1234
    );
1235
    assert_eq!(
1236
        expanded_params.get_key_checked(25),
1237
        None,
1238
        "Expanded should return None for index 25"
1239
    );
1240
}
1241
1242
#[test]
1243
#[allow(deprecated)]
1244
fn test_future_expansion_backwards_compatibility() {
1245
    // Test that future expansion maintains backwards compatibility
1246
1247
    // This test simulates a scenario where:
1248
    // 1. Third-party code is written against 23-key CrcParams
1249
    // 2. Library is expanded to support 25-key CrcParams
1250
    // 3. Third-party code continues to work without modification
1251
1252
    // Mock third-party function that expects to work with any CrcParams
1253
    fn third_party_key_processor(params: CrcParams) -> Vec<u64> {
1254
        let mut result = Vec::new();
1255
1256
        // Third-party code might access keys in various patterns
1257
        // Pattern 1: Access first few keys
1258
        for i in 0..5 {
1259
            result.push(params.get_key(i));
1260
        }
1261
1262
        // Pattern 2: Access some middle keys
1263
        for i in 10..15 {
1264
            result.push(params.get_key(i));
1265
        }
1266
1267
        // Pattern 3: Access keys near the end (but within original 23-key range)
1268
        for i in 20..23 {
1269
            result.push(params.get_key(i));
1270
        }
1271
1272
        // Pattern 4: Attempt to access beyond both ranges (should return 0 for both)
1273
        result.push(params.get_key(30));
1274
        result.push(params.get_key(31));
1275
1276
        result
1277
    }
1278
1279
    // Test with original 23-key params
1280
    let keys_23 = [0xABCDEF0123456789u64; 23];
1281
    let params_23 = CrcParams {
1282
        algorithm: CrcAlgorithm::Crc32Custom,
1283
        name: "Backwards Compat Test 23",
1284
        width: 32,
1285
        poly: 0x1EDC6F41,
1286
        init: 0xFFFFFFFF,
1287
        init_algorithm: 0xFFFFFFFF,
1288
        refin: true,
1289
        refout: true,
1290
        xorout: 0xFFFFFFFF,
1291
        check: 0x12345678,
1292
        keys: CrcKeysStorage::from_keys_fold_256(keys_23),
1293
    };
1294
1295
    // Test with expanded 25-key params
1296
    let keys_25 = [0xABCDEF0123456789u64; 25];
1297
    let params_25 = CrcParams {
1298
        algorithm: CrcAlgorithm::Crc64Custom,
1299
        name: "Backwards Compat Test 25",
1300
        width: 64,
1301
        poly: 0x42F0E1EBA9EA3693,
1302
        init: 0xFFFFFFFFFFFFFFFF,
1303
        init_algorithm: 0xFFFFFFFFFFFFFFFF,
1304
        refin: true,
1305
        refout: true,
1306
        xorout: 0xFFFFFFFFFFFFFFFF,
1307
        check: 0x123456789ABCDEF0,
1308
        keys: CrcKeysStorage::from_keys_fold_future_test(keys_25),
1309
    };
1310
1311
    // Run third-party function with both variants
1312
    let result_23 = third_party_key_processor(params_23);
1313
    let result_25 = third_party_key_processor(params_25);
1314
1315
    // Results should be identical for the overlapping key ranges
1316
    assert_eq!(
1317
        result_23.len(),
1318
        result_25.len(),
1319
        "Results should have same length"
1320
    );
1321
1322
    // First 13 values should be identical (keys 0-4, 10-14, 20-22)
1323
    for i in 0..13 {
1324
        assert_eq!(
1325
            result_23[i], result_25[i],
1326
            "Result {} should be identical",
1327
            i
1328
        );
1329
        assert_eq!(
1330
            result_23[i], 0xABCDEF0123456789,
1331
            "Result {} should match key value",
1332
            i
1333
        );
1334
    }
1335
1336
    // Last 2 values should be 0 for both (out-of-bounds access to indices 30, 31)
1337
    assert_eq!(
1338
        result_23[13], 0,
1339
        "Out-of-bounds access should return 0 for 23-key"
1340
    );
1341
    assert_eq!(
1342
        result_23[14], 0,
1343
        "Out-of-bounds access should return 0 for 23-key"
1344
    );
1345
    assert_eq!(
1346
        result_25[13], 0,
1347
        "Out-of-bounds access should return 0 for 25-key"
1348
    );
1349
    assert_eq!(
1350
        result_25[14], 0,
1351
        "Out-of-bounds access should return 0 for 25-key"
1352
    );
1353
1354
    // This demonstrates that third-party code works identically with both variants
1355
    assert_eq!(
1356
        result_23, result_25,
1357
        "Third-party function should produce identical results"
1358
    );
1359
}
1360
// FFI Tests for future-proof CrcFastParams functionality
1361
1362
#[cfg(all(
1363
    feature = "ffi",
1364
    any(target_arch = "aarch64", target_arch = "x86_64", target_arch = "x86")
1365
))]
1366
mod ffi_tests {
1367
    use crate::ffi::CrcFastParams;
1368
    use crate::{CrcAlgorithm, CrcKeysStorage, CrcParams};
1369
1370
    #[test]
1371
    #[allow(deprecated)]
1372
    fn test_ffi_conversion_23_keys() {
1373
        // Test conversion between CrcParams and CrcFastParams for 23-key variant
1374
        let keys_23 = [0x1234567890ABCDEFu64; 23];
1375
        let original_params = CrcParams {
1376
            algorithm: CrcAlgorithm::Crc32Custom,
1377
            name: "FFI Test 23",
1378
            width: 32,
1379
            poly: 0x1EDC6F41,
1380
            init: 0xFFFFFFFF,
1381
            init_algorithm: 0xFFFFFFFF,
1382
            refin: true,
1383
            refout: true,
1384
            xorout: 0xFFFFFFFF,
1385
            check: 0x12345678,
1386
            keys: CrcKeysStorage::from_keys_fold_256(keys_23),
1387
        };
1388
1389
        // Convert to FFI struct
1390
        let ffi_params: CrcFastParams = original_params.into();
1391
1392
        // Verify FFI struct fields
1393
        assert_eq!(ffi_params.key_count, 23, "FFI params should have 23 keys");
1394
        assert!(
1395
            !ffi_params.keys.is_null(),
1396
            "Keys pointer should not be null"
1397
        );
1398
        assert_eq!(ffi_params.width, 32, "Width should match");
1399
        assert_eq!(ffi_params.poly, 0x1EDC6F41, "Poly should match");
1400
        assert_eq!(ffi_params.init, 0xFFFFFFFF, "Init should match");
1401
        assert!(ffi_params.refin, "Refin should match");
1402
        assert!(ffi_params.refout, "Refout should match");
1403
        assert_eq!(ffi_params.xorout, 0xFFFFFFFF, "Xorout should match");
1404
        assert_eq!(ffi_params.check, 0x12345678, "Check should match");
1405
1406
        // Test direct pointer access to keys
1407
        unsafe {
1408
            for i in 0..23 {
1409
                let key_value = *ffi_params.keys.add(i);
1410
                assert_eq!(
1411
                    key_value, 0x1234567890ABCDEF,
1412
                    "Key {} should match expected value",
1413
                    i
1414
                );
1415
            }
1416
        }
1417
1418
        // Convert back to CrcParams
1419
        let converted_params: CrcParams = ffi_params.into();
1420
1421
        // Verify round-trip conversion
1422
        assert_eq!(converted_params.algorithm, original_params.algorithm);
1423
        assert_eq!(converted_params.width, original_params.width);
1424
        assert_eq!(converted_params.poly, original_params.poly);
1425
        assert_eq!(converted_params.init, original_params.init);
1426
        assert_eq!(converted_params.refin, original_params.refin);
1427
        assert_eq!(converted_params.refout, original_params.refout);
1428
        assert_eq!(converted_params.xorout, original_params.xorout);
1429
        assert_eq!(converted_params.check, original_params.check);
1430
        assert_eq!(converted_params.key_count(), 23);
1431
1432
        // Verify all keys match
1433
        for i in 0..23 {
1434
            assert_eq!(
1435
                converted_params.get_key(i),
1436
                original_params.get_key(i),
1437
                "Converted key {} should match original",
1438
                i
1439
            );
1440
        }
1441
    }
1442
1443
    #[test]
1444
    #[allow(deprecated)]
1445
    fn test_ffi_conversion_25_keys() {
1446
        // Test conversion between CrcParams and CrcFastParams for 25-key variant
1447
        let keys_25 = [0xFEDCBA0987654321u64; 25];
1448
        let original_params = CrcParams {
1449
            algorithm: CrcAlgorithm::Crc64Custom,
1450
            name: "FFI Test 25",
1451
            width: 64,
1452
            poly: 0x42F0E1EBA9EA3693,
1453
            init: 0xFFFFFFFFFFFFFFFF,
1454
            init_algorithm: 0xFFFFFFFFFFFFFFFF,
1455
            refin: true,
1456
            refout: true,
1457
            xorout: 0xFFFFFFFFFFFFFFFF,
1458
            check: 0x123456789ABCDEF0,
1459
            keys: CrcKeysStorage::from_keys_fold_future_test(keys_25),
1460
        };
1461
1462
        // Convert to FFI struct
1463
        let ffi_params: CrcFastParams = original_params.into();
1464
1465
        // Verify FFI struct fields
1466
        assert_eq!(ffi_params.key_count, 25, "FFI params should have 25 keys");
1467
        assert!(
1468
            !ffi_params.keys.is_null(),
1469
            "Keys pointer should not be null"
1470
        );
1471
        assert_eq!(ffi_params.width, 64, "Width should match");
1472
        assert_eq!(ffi_params.poly, 0x42F0E1EBA9EA3693, "Poly should match");
1473
1474
        // Test direct pointer access to keys
1475
        unsafe {
1476
            for i in 0..25 {
1477
                let key_value = *ffi_params.keys.add(i);
1478
                assert_eq!(
1479
                    key_value, 0xFEDCBA0987654321,
1480
                    "Key {} should match expected value",
1481
                    i
1482
                );
1483
            }
1484
        }
1485
1486
        // Convert back to CrcParams
1487
        let converted_params: CrcParams = ffi_params.into();
1488
1489
        // Verify round-trip conversion
1490
        assert_eq!(converted_params.key_count(), 25);
1491
        for i in 0..25 {
1492
            assert_eq!(
1493
                converted_params.get_key(i),
1494
                original_params.get_key(i),
1495
                "Converted key {} should match original",
1496
                i
1497
            );
1498
        }
1499
    }
1500
1501
    #[test]
1502
    #[allow(deprecated)]
1503
    fn test_ffi_pointer_stability() {
1504
        // Test that key pointers remain stable across multiple conversions
1505
        let keys_23 = [0x1111111111111111u64; 23];
1506
        let params = CrcParams {
1507
            algorithm: CrcAlgorithm::Crc32Custom,
1508
            name: "Stability Test",
1509
            width: 32,
1510
            poly: 0x1EDC6F41,
1511
            init: 0xFFFFFFFF,
1512
            init_algorithm: 0xFFFFFFFF,
1513
            refin: true,
1514
            refout: true,
1515
            xorout: 0xFFFFFFFF,
1516
            check: 0x12345678,
1517
            keys: CrcKeysStorage::from_keys_fold_256(keys_23),
1518
        };
1519
1520
        // Convert to FFI multiple times
1521
        let ffi_params1: CrcFastParams = params.into();
1522
        let ffi_params2: CrcFastParams = params.into();
1523
1524
        // Pointers should be stable (same keys should get same pointer)
1525
        assert_eq!(
1526
            ffi_params1.keys, ffi_params2.keys,
1527
            "Identical key sets should get same stable pointer"
1528
        );
1529
        assert_eq!(
1530
            ffi_params1.key_count, ffi_params2.key_count,
1531
            "Key counts should match"
1532
        );
1533
1534
        // Test that different key sets get different pointers
1535
        let different_keys = [0x2222222222222222u64; 23];
1536
        let different_params = CrcParams {
1537
            algorithm: CrcAlgorithm::Crc32Custom,
1538
            name: "Different Test",
1539
            width: 32,
1540
            poly: 0x1EDC6F41,
1541
            init: 0xFFFFFFFF,
1542
            init_algorithm: 0xFFFFFFFF,
1543
            refin: true,
1544
            refout: true,
1545
            xorout: 0xFFFFFFFF,
1546
            check: 0x12345678,
1547
            keys: CrcKeysStorage::from_keys_fold_256(different_keys),
1548
        };
1549
1550
        let ffi_params3: CrcFastParams = different_params.into();
1551
        assert_ne!(
1552
            ffi_params1.keys, ffi_params3.keys,
1553
            "Different key sets should get different pointers"
1554
        );
1555
    }
1556
1557
    #[test]
1558
    #[allow(deprecated)]
1559
    fn test_ffi_memory_safety() {
1560
        // Test that FFI conversions are memory safe
1561
        let keys_23 = [0xAAAAAAAAAAAAAAAAu64; 23];
1562
        let params = CrcParams {
1563
            algorithm: CrcAlgorithm::Crc32Custom,
1564
            name: "Memory Safety Test",
1565
            width: 32,
1566
            poly: 0x1EDC6F41,
1567
            init: 0xFFFFFFFF,
1568
            init_algorithm: 0xFFFFFFFF,
1569
            refin: true,
1570
            refout: true,
1571
            xorout: 0xFFFFFFFF,
1572
            check: 0x12345678,
1573
            keys: CrcKeysStorage::from_keys_fold_256(keys_23),
1574
        };
1575
1576
        let ffi_params: CrcFastParams = params.into();
1577
1578
        // Test that we can safely access all keys through the pointer
1579
        unsafe {
1580
            let keys_slice =
1581
                std::slice::from_raw_parts(ffi_params.keys, ffi_params.key_count as usize);
1582
1583
            // Verify all keys are accessible and correct
1584
            for (i, &key) in keys_slice.iter().enumerate() {
1585
                assert_eq!(
1586
                    key, 0xAAAAAAAAAAAAAAAA,
1587
                    "Key {} should be accessible and correct",
1588
                    i
1589
                );
1590
            }
1591
1592
            // Test that we can create multiple slices from the same pointer
1593
            let keys_slice2 =
1594
                std::slice::from_raw_parts(ffi_params.keys, ffi_params.key_count as usize);
1595
            assert_eq!(
1596
                keys_slice, keys_slice2,
1597
                "Multiple slices should be identical"
1598
            );
1599
        }
1600
1601
        // Test conversion back to CrcParams
1602
        let converted: CrcParams = ffi_params.into();
1603
        assert_eq!(converted.key_count(), 23);
1604
1605
        for i in 0..23 {
1606
            assert_eq!(
1607
                converted.get_key(i),
1608
                0xAAAAAAAAAAAAAAAA,
1609
                "Converted key {} should match",
1610
                i
1611
            );
1612
        }
1613
    }
1614
1615
    #[test]
1616
    #[allow(deprecated)]
1617
    fn test_ffi_different_key_counts() {
1618
        // Test FFI with different key count scenarios
1619
1620
        // Test 23-key variant
1621
        let keys_23 = [0x1111111111111111u64; 23];
1622
        let params_23 = CrcParams {
1623
            algorithm: CrcAlgorithm::Crc32Custom,
1624
            name: "23-Key FFI Test",
1625
            width: 32,
1626
            poly: 0x1EDC6F41,
1627
            init: 0xFFFFFFFF,
1628
            init_algorithm: 0xFFFFFFFF,
1629
            refin: true,
1630
            refout: true,
1631
            xorout: 0xFFFFFFFF,
1632
            check: 0x12345678,
1633
            keys: CrcKeysStorage::from_keys_fold_256(keys_23),
1634
        };
1635
1636
        // Test 25-key variant
1637
        let keys_25 = [0x2222222222222222u64; 25];
1638
        let params_25 = CrcParams {
1639
            algorithm: CrcAlgorithm::Crc64Custom,
1640
            name: "25-Key FFI Test",
1641
            width: 64,
1642
            poly: 0x42F0E1EBA9EA3693,
1643
            init: 0xFFFFFFFFFFFFFFFF,
1644
            init_algorithm: 0xFFFFFFFFFFFFFFFF,
1645
            refin: true,
1646
            refout: true,
1647
            xorout: 0xFFFFFFFFFFFFFFFF,
1648
            check: 0x123456789ABCDEF0,
1649
            keys: CrcKeysStorage::from_keys_fold_future_test(keys_25),
1650
        };
1651
1652
        // Convert both to FFI
1653
        let ffi_23: CrcFastParams = params_23.into();
1654
        let ffi_25: CrcFastParams = params_25.into();
1655
1656
        // Verify key counts
1657
        assert_eq!(ffi_23.key_count, 23);
1658
        assert_eq!(ffi_25.key_count, 25);
1659
1660
        // Test C-style access patterns
1661
        unsafe {
1662
            // Access all keys in 23-key variant
1663
            for i in 0..23 {
1664
                let key = *ffi_23.keys.add(i);
1665
                assert_eq!(
1666
                    key, 0x1111111111111111,
1667
                    "23-key variant key {} should match",
1668
                    i
1669
                );
1670
            }
1671
1672
            // Access all keys in 25-key variant
1673
            for i in 0..25 {
1674
                let key = *ffi_25.keys.add(i);
1675
                assert_eq!(
1676
                    key, 0x2222222222222222,
1677
                    "25-key variant key {} should match",
1678
                    i
1679
                );
1680
            }
1681
1682
            // Test bounds-aware C code pattern
1683
            for ffi_params in [&ffi_23, &ffi_25] {
1684
                for i in 0..ffi_params.key_count {
1685
                    let key = *ffi_params.keys.add(i as usize);
1686
                    assert_ne!(key, 0, "Key {} should not be zero", i);
1687
                }
1688
            }
1689
        }
1690
1691
        // Test round-trip conversions
1692
        let converted_23: CrcParams = ffi_23.into();
1693
        let converted_25: CrcParams = ffi_25.into();
1694
1695
        assert_eq!(converted_23.key_count(), 23);
1696
        assert_eq!(converted_25.key_count(), 25);
1697
1698
        // Verify all keys survived round-trip
1699
        for i in 0..23 {
1700
            assert_eq!(converted_23.get_key(i), 0x1111111111111111);
1701
        }
1702
        for i in 0..25 {
1703
            assert_eq!(converted_25.get_key(i), 0x2222222222222222);
1704
        }
1705
    }
1706
1707
    #[test]
1708
    fn test_ffi_get_custom_params_function() {
1709
        // Test the crc_fast_get_custom_params FFI function
1710
        use std::ffi::CString;
1711
1712
        let name = CString::new("Test CRC").unwrap();
1713
        let ffi_params = crate::ffi::crc_fast_get_custom_params(
1714
            name.as_ptr(),
1715
            32,
1716
            0x1EDC6F41,
1717
            0xFFFFFFFF,
1718
            true,
1719
            0xFFFFFFFF,
1720
            0x12345678,
1721
        );
1722
1723
        // Verify the returned FFI params
1724
        assert_eq!(ffi_params.width, 32);
1725
        assert_eq!(ffi_params.poly, 0x1EDC6F41);
1726
        assert_eq!(ffi_params.init, 0xFFFFFFFF);
1727
        assert!(ffi_params.refin);
1728
        assert!(ffi_params.refout);
1729
        assert_eq!(ffi_params.xorout, 0xFFFFFFFF);
1730
        assert_eq!(ffi_params.check, 0x12345678);
1731
        assert!(
1732
            !ffi_params.keys.is_null(),
1733
            "Keys pointer should not be null"
1734
        );
1735
        assert!(ffi_params.key_count > 0, "Should have keys");
1736
1737
        // Test that we can access the keys
1738
        unsafe {
1739
            for i in 0..ffi_params.key_count {
1740
                let _key = *ffi_params.keys.add(i as usize);
1741
                // Keys should be accessible without crashing
1742
            }
1743
        }
1744
1745
        // Test conversion to CrcParams
1746
        let params: CrcParams = ffi_params.into();
1747
        assert_eq!(params.width, 32);
1748
        assert_eq!(params.poly, 0x1EDC6F41);
1749
        assert_eq!(params.init, 0xFFFFFFFF);
1750
        assert!(params.refin);
1751
        assert!(params.refout);
1752
        assert_eq!(params.xorout, 0xFFFFFFFF);
1753
        assert_eq!(params.check, 0x12345678);
1754
        assert!(params.key_count() > 0);
1755
    }
1756
}