#![cfg(test)]
use crate::{CrcAlgorithm, CrcKeysStorage, CrcParams};
#[test]
fn test_crc_keys_storage_bounds_checking() {
let keys_23 = [1u64; 23];
let storage_23 = CrcKeysStorage::from_keys_fold_256(keys_23);
for i in 0..23 {
assert_eq!(
storage_23.get_key(i),
1,
"Valid index {} should return key value",
i
);
}
assert_eq!(
storage_23.get_key(23),
0,
"Index 23 should return 0 for 23-key storage"
);
assert_eq!(
storage_23.get_key(24),
0,
"Index 24 should return 0 for 23-key storage"
);
assert_eq!(
storage_23.get_key(100),
0,
"Large index should return 0 for 23-key storage"
);
let keys_25 = [2u64; 25];
let storage_25 = CrcKeysStorage::from_keys_fold_future_test(keys_25);
for i in 0..25 {
assert_eq!(
storage_25.get_key(i),
2,
"Valid index {} should return key value",
i
);
}
assert_eq!(
storage_25.get_key(25),
0,
"Index 25 should return 0 for 25-key storage"
);
assert_eq!(
storage_25.get_key(26),
0,
"Index 26 should return 0 for 25-key storage"
);
assert_eq!(
storage_25.get_key(100),
0,
"Large index should return 0 for 25-key storage"
);
}
#[test]
#[allow(deprecated)]
fn test_crc_params_get_key_checked() {
let keys_23 = [42u64; 23];
let params_23 = CrcParams {
algorithm: CrcAlgorithm::Crc32Custom,
name: "Test CRC",
width: 32,
poly: 0x1EDC6F41,
init: 0xFFFFFFFF,
init_algorithm: 0xFFFFFFFF,
refin: true,
refout: true,
xorout: 0xFFFFFFFF,
check: 0x12345678,
keys: CrcKeysStorage::from_keys_fold_256(keys_23),
};
for i in 0..23 {
assert_eq!(
params_23.get_key_checked(i),
Some(42),
"Valid index {} should return Some(42)",
i
);
}
assert_eq!(
params_23.get_key_checked(23),
None,
"Index 23 should return None for 23-key params"
);
assert_eq!(
params_23.get_key_checked(24),
None,
"Index 24 should return None for 23-key params"
);
assert_eq!(
params_23.get_key_checked(100),
None,
"Large index should return None for 23-key params"
);
let keys_25 = [84u64; 25];
let params_25 = CrcParams {
algorithm: CrcAlgorithm::Crc64Custom,
name: "Test CRC 64",
width: 64,
poly: 0x42F0E1EBA9EA3693,
init: 0xFFFFFFFFFFFFFFFF,
init_algorithm: 0xFFFFFFFFFFFFFFFF,
refin: true,
refout: true,
xorout: 0xFFFFFFFFFFFFFFFF,
check: 0x123456789ABCDEF0,
keys: CrcKeysStorage::from_keys_fold_future_test(keys_25),
};
for i in 0..25 {
assert_eq!(
params_25.get_key_checked(i),
Some(84),
"Valid index {} should return Some(84)",
i
);
}
assert_eq!(
params_25.get_key_checked(25),
None,
"Index 25 should return None for 25-key params"
);
assert_eq!(
params_25.get_key_checked(26),
None,
"Index 26 should return None for 25-key params"
);
assert_eq!(
params_25.get_key_checked(100),
None,
"Large index should return None for 25-key params"
);
}
#[test]
#[allow(deprecated)]
fn test_key_count_returns_correct_values() {
let keys_23 = [1u64; 23];
let storage_23 = CrcKeysStorage::from_keys_fold_256(keys_23);
assert_eq!(
storage_23.key_count(),
23,
"KeysFold256 should report 23 keys"
);
let params_23 = CrcParams {
algorithm: CrcAlgorithm::Crc32Custom,
name: "Test CRC",
width: 32,
poly: 0x1EDC6F41,
init: 0xFFFFFFFF,
init_algorithm: 0xFFFFFFFF,
refin: true,
refout: true,
xorout: 0xFFFFFFFF,
check: 0x12345678,
keys: storage_23,
};
assert_eq!(
params_23.key_count(),
23,
"CrcParams with KeysFold256 should report 23 keys"
);
let keys_25 = [2u64; 25];
let storage_25 = CrcKeysStorage::from_keys_fold_future_test(keys_25);
assert_eq!(
storage_25.key_count(),
25,
"KeysFutureTest should report 25 keys"
);
let params_25 = CrcParams {
algorithm: CrcAlgorithm::Crc64Custom,
name: "Test CRC 64",
width: 64,
poly: 0x42F0E1EBA9EA3693,
init: 0xFFFFFFFFFFFFFFFF,
init_algorithm: 0xFFFFFFFFFFFFFFFF,
refin: true,
refout: true,
xorout: 0xFFFFFFFFFFFFFFFF,
check: 0x123456789ABCDEF0,
keys: storage_25,
};
assert_eq!(
params_25.key_count(),
25,
"CrcParams with KeysFutureTest should report 25 keys"
);
}
#[test]
#[allow(deprecated)]
fn test_crc_params_get_key_bounds_checking() {
let keys_23 = [99u64; 23];
let params_23 = CrcParams {
algorithm: CrcAlgorithm::Crc32Custom,
name: "Test CRC",
width: 32,
poly: 0x1EDC6F41,
init: 0xFFFFFFFF,
init_algorithm: 0xFFFFFFFF,
refin: true,
refout: true,
xorout: 0xFFFFFFFF,
check: 0x12345678,
keys: CrcKeysStorage::from_keys_fold_256(keys_23),
};
for i in 0..23 {
assert_eq!(
params_23.get_key(i),
99,
"Valid index {} should return 99",
i
);
}
assert_eq!(
params_23.get_key(23),
0,
"Index 23 should return 0 for 23-key params"
);
assert_eq!(
params_23.get_key(24),
0,
"Index 24 should return 0 for 23-key params"
);
assert_eq!(
params_23.get_key(100),
0,
"Large index should return 0 for 23-key params"
);
}
#[test]
#[allow(deprecated)]
fn test_third_party_const_definitions_compatibility() {
const MOCK_THIRD_PARTY_CRC32: CrcParams = CrcParams {
algorithm: CrcAlgorithm::Crc32Custom,
name: "Mock Third Party CRC-32",
width: 32,
poly: 0x1EDC6F41,
init: 0xFFFFFFFF,
init_algorithm: 0xFFFFFFFF,
refin: true,
refout: true,
xorout: 0xFFFFFFFF,
check: 0xE3069283,
keys: CrcKeysStorage::from_keys_fold_256([
0x1234567890ABCDEF,
0x2345678901BCDEF0,
0x3456789012CDEF01,
0x456789023DEF012,
0x56789034EF0123,
0x6789045F01234,
0x789056012345,
0x89067123456,
0x9078234567,
0xA089345678,
0xB09A456789,
0xC0AB56789A,
0xD0BC6789AB,
0xE0CD789ABC,
0xF0DE89ABCD,
0x10EF9ABCDE,
0x210ABCDEF0,
0x321BCDEF01,
0x432CDEF012,
0x543DEF0123,
0x654EF01234,
0x765F012345,
0x876012345,
]),
};
const MOCK_THIRD_PARTY_CRC64: CrcParams = CrcParams {
algorithm: CrcAlgorithm::Crc64Custom,
name: "Mock Third Party CRC-64",
width: 64,
poly: 0x42F0E1EBA9EA3693,
init: 0xFFFFFFFFFFFFFFFF,
init_algorithm: 0xFFFFFFFFFFFFFFFF,
refin: true,
refout: true,
xorout: 0xFFFFFFFFFFFFFFFF,
check: 0x6C40DF5F0B497347,
keys: CrcKeysStorage::from_keys_fold_256([
0xFEDCBA0987654321,
0xEDCBA09876543210,
0xDCBA098765432101,
0xCBA0987654321012,
0xBA09876543210123,
0xA098765432101234,
0x9087654321012345,
0x8076543210123456,
0x7065432101234567,
0x6054321012345678,
0x5043210123456789,
0x403210123456789A,
0x3210123456789AB,
0x210123456789ABC,
0x10123456789ABCD,
0x123456789ABCDE,
0x23456789ABCDEF,
0x3456789ABCDEF0,
0x456789ABCDEF01,
0x56789ABCDEF012,
0x6789ABCDEF0123,
0x789ABCDEF01234,
0x89ABCDEF012345,
]),
};
assert_eq!(MOCK_THIRD_PARTY_CRC32.key_count(), 23);
assert_eq!(MOCK_THIRD_PARTY_CRC64.key_count(), 23);
assert_eq!(MOCK_THIRD_PARTY_CRC32.get_key(0), 0x1234567890ABCDEF);
assert_eq!(MOCK_THIRD_PARTY_CRC32.get_key(22), 0x876012345);
assert_eq!(MOCK_THIRD_PARTY_CRC32.get_key(23), 0);
assert_eq!(MOCK_THIRD_PARTY_CRC64.get_key(0), 0xFEDCBA0987654321);
assert_eq!(MOCK_THIRD_PARTY_CRC64.get_key(22), 0x89ABCDEF012345);
assert_eq!(MOCK_THIRD_PARTY_CRC64.get_key(23), 0);
assert_eq!(
MOCK_THIRD_PARTY_CRC32.get_key_checked(0),
Some(0x1234567890ABCDEF)
);
assert_eq!(
MOCK_THIRD_PARTY_CRC32.get_key_checked(22),
Some(0x876012345)
);
assert_eq!(MOCK_THIRD_PARTY_CRC32.get_key_checked(23), None);
assert_eq!(
MOCK_THIRD_PARTY_CRC64.get_key_checked(0),
Some(0xFEDCBA0987654321)
);
assert_eq!(
MOCK_THIRD_PARTY_CRC64.get_key_checked(22),
Some(0x89ABCDEF012345)
);
assert_eq!(MOCK_THIRD_PARTY_CRC64.get_key_checked(23), None);
}
#[test]
#[allow(clippy::needless_range_loop)] #[allow(deprecated)]
fn test_existing_key_access_patterns_continue_to_work() {
let test_keys = [
0x1111111111111111,
0x2222222222222222,
0x3333333333333333,
0x4444444444444444,
0x5555555555555555,
0x6666666666666666,
0x7777777777777777,
0x8888888888888888,
0x9999999999999999,
0xAAAAAAAAAAAAAAAA,
0xBBBBBBBBBBBBBBBB,
0xCCCCCCCCCCCCCCCC,
0xDDDDDDDDDDDDDDDD,
0xEEEEEEEEEEEEEEEE,
0xFFFFFFFFFFFFFFFF,
0x1010101010101010,
0x2020202020202020,
0x3030303030303030,
0x4040404040404040,
0x5050505050505050,
0x6060606060606060,
0x7070707070707070,
0x8080808080808080,
];
let params = CrcParams {
algorithm: CrcAlgorithm::Crc32Custom,
name: "Test Pattern Access",
width: 32,
poly: 0x1EDC6F41,
init: 0xFFFFFFFF,
init_algorithm: 0xFFFFFFFF,
refin: true,
refout: true,
xorout: 0xFFFFFFFF,
check: 0x12345678,
keys: CrcKeysStorage::from_keys_fold_256(test_keys),
};
for i in 0..23 {
let expected = test_keys[i];
assert_eq!(
params.get_key(i),
expected,
"Sequential access failed at index {}",
i
);
}
for i in (0..23).rev() {
let expected = test_keys[i];
assert_eq!(
params.get_key(i),
expected,
"Reverse access failed at index {}",
i
);
}
let common_indices = [0, 1, 2, 4, 8, 16, 22];
for &i in &common_indices {
if i < 23 {
let expected = test_keys[i];
assert_eq!(
params.get_key(i),
expected,
"Common index access failed at index {}",
i
);
}
}
assert_eq!(
params.get_key(23),
0,
"Out-of-bounds access should return 0"
);
assert_eq!(
params.get_key(100),
0,
"Large out-of-bounds access should return 0"
);
}
#[test]
#[allow(clippy::needless_range_loop)] #[allow(deprecated)]
fn test_backwards_compatibility_throughout_migration_phases() {
let test_keys = [0x123456789ABCDEF0u64; 23];
let storage = CrcKeysStorage::from_keys_fold_256(test_keys);
for i in 0..23 {
assert_eq!(
storage.get_key(i),
test_keys[i],
"Storage access should match array access at index {}",
i
);
}
let params = CrcParams {
algorithm: CrcAlgorithm::Crc64Custom,
name: "Migration Test",
width: 64,
poly: 0x42F0E1EBA9EA3693,
init: 0x0000000000000000,
init_algorithm: 0x0000000000000000,
refin: false,
refout: false,
xorout: 0x0000000000000000,
check: 0x6C40DF5F0B497347,
keys: storage,
};
for i in 0..23 {
assert_eq!(
params.get_key(i),
test_keys[i],
"CrcParams access should match array access at index {}",
i
);
assert_eq!(
params.get_key_checked(i),
Some(test_keys[i]),
"CrcParams checked access should match array access at index {}",
i
);
}
assert_eq!(params.get_key(23), 0, "Out-of-bounds should return 0");
assert_eq!(
params.get_key_checked(23),
None,
"Out-of-bounds checked should return None"
);
assert_eq!(params.key_count(), 23, "Key count should be 23");
assert_eq!(
storage.to_keys_array_23(),
test_keys,
"Storage should convert back to original array"
);
assert_eq!(
storage, test_keys,
"Storage should compare equal to original array"
);
assert_eq!(
test_keys, storage,
"Original array should compare equal to storage"
);
}
#[test]
#[allow(clippy::needless_range_loop)] #[allow(deprecated)]
fn test_key_access_performance_matches_direct_array_access() {
let test_keys = [
0x1111111111111111,
0x2222222222222222,
0x3333333333333333,
0x4444444444444444,
0x5555555555555555,
0x6666666666666666,
0x7777777777777777,
0x8888888888888888,
0x9999999999999999,
0xAAAAAAAAAAAAAAAA,
0xBBBBBBBBBBBBBBBB,
0xCCCCCCCCCCCCCCCC,
0xDDDDDDDDDDDDDDDD,
0xEEEEEEEEEEEEEEEE,
0xFFFFFFFFFFFFFFFF,
0x1010101010101010,
0x2020202020202020,
0x3030303030303030,
0x4040404040404040,
0x5050505050505050,
0x6060606060606060,
0x7070707070707070,
0x8080808080808080,
];
let storage = CrcKeysStorage::from_keys_fold_256(test_keys);
let params = CrcParams {
algorithm: CrcAlgorithm::Crc32Custom,
name: "Performance Test",
width: 32,
poly: 0x1EDC6F41,
init: 0xFFFFFFFF,
init_algorithm: 0xFFFFFFFF,
refin: true,
refout: true,
xorout: 0xFFFFFFFF,
check: 0x12345678,
keys: storage,
};
let iterations = 1000;
let mut checksum = 0u64;
for iteration in 0..iterations {
for i in 0..23 {
checksum = checksum.wrapping_add(params.get_key(i).wrapping_mul(iteration as u64 + 1));
}
}
let access_pattern = [
0, 5, 12, 3, 18, 7, 22, 1, 15, 9, 20, 4, 11, 16, 2, 19, 8, 14, 6, 21, 10, 17, 13,
];
for iteration in 0..iterations {
for &i in &access_pattern {
checksum = checksum.wrapping_add(params.get_key(i).wrapping_mul(iteration as u64 + 2));
}
}
assert_ne!(checksum, 0, "Performance test should have accessed keys");
let mut bounds_checksum = 0u64;
for iteration in 0..iterations {
for i in 0..30 {
bounds_checksum =
bounds_checksum.wrapping_add(params.get_key(i).wrapping_mul(iteration as u64 + 3));
}
}
assert_ne!(
bounds_checksum, 0,
"Bounds checking performance test should work"
);
}
#[test]
fn test_crc_calculation_performance_before_and_after_changes() {
use crate::{checksum, CrcAlgorithm};
let test_data_small = b"123456789";
let test_data_medium = vec![0xAAu8; 1024]; let test_data_large = vec![0x55u8; 65536];
let algorithms = [
CrcAlgorithm::Crc32IsoHdlc,
CrcAlgorithm::Crc32Iscsi,
CrcAlgorithm::Crc64Nvme,
CrcAlgorithm::Crc64Ecma182,
];
for algorithm in algorithms {
let result_small = checksum(algorithm, test_data_small);
assert_ne!(
result_small, 0,
"Small data CRC should produce non-zero result"
);
let result_medium = checksum(algorithm, &test_data_medium);
assert_ne!(
result_medium, 0,
"Medium data CRC should produce non-zero result"
);
let result_large = checksum(algorithm, &test_data_large);
assert_ne!(
result_large, 0,
"Large data CRC should produce non-zero result"
);
let result_small_2 = checksum(algorithm, test_data_small);
assert_eq!(
result_small, result_small_2,
"CRC results should be consistent"
);
}
}
#[test]
#[allow(deprecated)]
fn test_memory_usage_impact_of_enum_based_storage() {
use std::mem;
let keys_23 = [0u64; 23];
let keys_25 = [0u64; 25];
let storage_23 = CrcKeysStorage::from_keys_fold_256(keys_23);
let storage_25 = CrcKeysStorage::from_keys_fold_future_test(keys_25);
let storage_23_size = mem::size_of_val(&storage_23);
let storage_25_size = mem::size_of_val(&storage_25);
let _array_23_size = mem::size_of_val(&keys_23);
let array_25_size = mem::size_of_val(&keys_25);
assert_eq!(
storage_23_size, storage_25_size,
"Both enum variants should have the same size"
);
assert!(
storage_23_size >= array_25_size,
"Enum should be at least as large as the largest variant"
);
assert!(
storage_23_size <= array_25_size + 16,
"Enum should not add excessive overhead beyond largest variant"
);
let params_23 = CrcParams {
algorithm: CrcAlgorithm::Crc32Custom,
name: "Memory Test 23",
width: 32,
poly: 0x1EDC6F41,
init: 0xFFFFFFFF,
init_algorithm: 0xFFFFFFFF,
refin: true,
refout: true,
xorout: 0xFFFFFFFF,
check: 0x12345678,
keys: storage_23,
};
let params_25 = CrcParams {
algorithm: CrcAlgorithm::Crc64Custom,
name: "Memory Test 25",
width: 64,
poly: 0x42F0E1EBA9EA3693,
init: 0xFFFFFFFFFFFFFFFF,
init_algorithm: 0xFFFFFFFFFFFFFFFF,
refin: true,
refout: true,
xorout: 0xFFFFFFFFFFFFFFFF,
check: 0x123456789ABCDEF0,
keys: storage_25,
};
let params_23_size = mem::size_of_val(¶ms_23);
let params_25_size = mem::size_of_val(¶ms_25);
assert!(
params_25_size >= params_23_size,
"25-key params should be at least as large as 23-key params"
);
assert!(
params_25_size - params_23_size <= 16,
"Size difference should be reasonable (just the extra keys)"
);
assert!(
params_23_size < 512,
"CrcParams should not be excessively large"
);
assert!(
params_25_size < 512,
"CrcParams should not be excessively large"
);
}
#[test]
fn test_compiler_optimizations_eliminate_enum_dispatch() {
let keys_23 = [
0x1111111111111111,
0x2222222222222222,
0x3333333333333333,
0x4444444444444444,
0x5555555555555555,
0x6666666666666666,
0x7777777777777777,
0x8888888888888888,
0x9999999999999999,
0xAAAAAAAAAAAAAAAA,
0xBBBBBBBBBBBBBBBB,
0xCCCCCCCCCCCCCCCC,
0xDDDDDDDDDDDDDDDD,
0xEEEEEEEEEEEEEEEE,
0xFFFFFFFFFFFFFFFF,
0x1010101010101010,
0x2020202020202020,
0x3030303030303030,
0x4040404040404040,
0x5050505050505050,
0x6060606060606060,
0x7070707070707070,
0x8080808080808080,
];
let keys_25 = [
0x1111111111111111,
0x2222222222222222,
0x3333333333333333,
0x4444444444444444,
0x5555555555555555,
0x6666666666666666,
0x7777777777777777,
0x8888888888888888,
0x9999999999999999,
0xAAAAAAAAAAAAAAAA,
0xBBBBBBBBBBBBBBBB,
0xCCCCCCCCCCCCCCCC,
0xDDDDDDDDDDDDDDDD,
0xEEEEEEEEEEEEEEEE,
0xFFFFFFFFFFFFFFFF,
0x1010101010101010,
0x2020202020202020,
0x3030303030303030,
0x4040404040404040,
0x5050505050505050,
0x6060606060606060,
0x7070707070707070,
0x8080808080808080,
0x9090909090909090,
0xA0A0A0A0A0A0A0A0,
];
let storage_23 = CrcKeysStorage::from_keys_fold_256(keys_23);
let storage_25 = CrcKeysStorage::from_keys_fold_future_test(keys_25);
let mut sum_23 = 0u64;
for iteration in 0..100 {
for i in 0..23 {
sum_23 = sum_23.wrapping_add(storage_23.get_key(i).wrapping_mul(iteration + 1));
}
}
let mut sum_25 = 0u64;
for iteration in 0..100 {
for i in 0..25 {
sum_25 = sum_25.wrapping_add(storage_25.get_key(i).wrapping_mul(iteration + 1));
}
}
assert_ne!(
sum_23, 0,
"23-key operations should produce non-zero result"
);
assert_ne!(
sum_25, 0,
"25-key operations should produce non-zero result"
);
let storages = [storage_23, storage_25];
let mut mixed_sum = 0u64;
for iteration in 0..100 {
for (storage_idx, storage) in storages.iter().enumerate() {
let key_count = storage.key_count();
for i in 0..key_count {
mixed_sum = mixed_sum.wrapping_add(
storage
.get_key(i)
.wrapping_mul((iteration + storage_idx + 1) as u64),
);
}
}
}
assert_ne!(mixed_sum, 0, "Mixed access should produce non-zero result");
}
#[test]
#[allow(clippy::needless_range_loop)] #[allow(deprecated)]
fn test_create_crc_params_using_keys_future_test_variant() {
let test_keys_25 = [
0x1111111111111111,
0x2222222222222222,
0x3333333333333333,
0x4444444444444444,
0x5555555555555555,
0x6666666666666666,
0x7777777777777777,
0x8888888888888888,
0x9999999999999999,
0xAAAAAAAAAAAAAAAA,
0xBBBBBBBBBBBBBBBB,
0xCCCCCCCCCCCCCCCC,
0xDDDDDDDDDDDDDDDD,
0xEEEEEEEEEEEEEEEE,
0xFFFFFFFFFFFFFFFF,
0x1010101010101010,
0x2020202020202020,
0x3030303030303030,
0x4040404040404040,
0x5050505050505050,
0x6060606060606060,
0x7070707070707070,
0x8080808080808080,
0x9090909090909090,
0xA0A0A0A0A0A0A0A0,
];
let future_params = CrcParams {
algorithm: CrcAlgorithm::Crc64Custom,
name: "Future Test CRC-64",
width: 64,
poly: 0x42F0E1EBA9EA3693,
init: 0xFFFFFFFFFFFFFFFF,
init_algorithm: 0xFFFFFFFFFFFFFFFF,
refin: true,
refout: true,
xorout: 0xFFFFFFFFFFFFFFFF,
check: 0x123456789ABCDEF0,
keys: CrcKeysStorage::from_keys_fold_future_test(test_keys_25),
};
assert_eq!(
future_params.key_count(),
25,
"Future params should have 25 keys"
);
for i in 0..25 {
assert_eq!(
future_params.get_key(i),
test_keys_25[i],
"Key {} should match expected value",
i
);
assert_eq!(
future_params.get_key_checked(i),
Some(test_keys_25[i]),
"Checked key {} should return Some(value)",
i
);
}
assert_eq!(
future_params.get_key(25),
0,
"Key 25 should return 0 (out of bounds)"
);
assert_eq!(
future_params.get_key_checked(25),
None,
"Checked key 25 should return None"
);
assert_eq!(
future_params.get_key(30),
0,
"Key 30 should return 0 (out of bounds)"
);
assert_eq!(
future_params.get_key_checked(30),
None,
"Checked key 30 should return None"
);
}
#[test]
#[allow(deprecated)]
fn test_code_gracefully_handles_different_key_array_sizes() {
let keys_23 = [0x1234567890ABCDEFu64; 23];
let keys_25 = [0xFEDCBA0987654321u64; 25];
let params_23 = CrcParams {
algorithm: CrcAlgorithm::Crc32Custom,
name: "23-Key Test",
width: 32,
poly: 0x1EDC6F41,
init: 0xFFFFFFFF,
init_algorithm: 0xFFFFFFFF,
refin: true,
refout: true,
xorout: 0xFFFFFFFF,
check: 0x12345678,
keys: CrcKeysStorage::from_keys_fold_256(keys_23),
};
let params_25 = CrcParams {
algorithm: CrcAlgorithm::Crc64Custom,
name: "25-Key Test",
width: 64,
poly: 0x42F0E1EBA9EA3693,
init: 0xFFFFFFFFFFFFFFFF,
init_algorithm: 0xFFFFFFFFFFFFFFFF,
refin: true,
refout: true,
xorout: 0xFFFFFFFFFFFFFFFF,
check: 0x123456789ABCDEF0,
keys: CrcKeysStorage::from_keys_fold_future_test(keys_25),
};
fn process_crc_params(params: CrcParams) -> (usize, u64, u64) {
let key_count = params.key_count();
let first_key = params.get_key(0);
let last_valid_key = if key_count > 0 {
params.get_key(key_count - 1)
} else {
0
};
(key_count, first_key, last_valid_key)
}
let (count_23, first_23, last_23) = process_crc_params(params_23);
let (count_25, first_25, last_25) = process_crc_params(params_25);
assert_eq!(count_23, 23, "23-key params should report 23 keys");
assert_eq!(count_25, 25, "25-key params should report 25 keys");
assert_eq!(
first_23, 0x1234567890ABCDEF,
"23-key first key should match"
);
assert_eq!(
first_25, 0xFEDCBA0987654321,
"25-key first key should match"
);
assert_eq!(last_23, 0x1234567890ABCDEF, "23-key last key should match");
assert_eq!(last_25, 0xFEDCBA0987654321, "25-key last key should match");
assert_eq!(
params_23.get_key(23),
0,
"23-key params should return 0 for index 23"
);
assert_eq!(
params_23.get_key(25),
0,
"23-key params should return 0 for index 25"
);
assert_eq!(
params_25.get_key(25),
0,
"25-key params should return 0 for index 25"
);
assert_eq!(
params_25.get_key(30),
0,
"25-key params should return 0 for index 30"
);
}
#[test]
#[allow(deprecated)]
fn test_expansion_to_larger_key_arrays_works_as_designed() {
let original_keys = [0x1111111111111111u64; 23];
let expanded_keys = [
0x1111111111111111,
0x1111111111111111,
0x1111111111111111,
0x1111111111111111,
0x1111111111111111,
0x1111111111111111,
0x1111111111111111,
0x1111111111111111,
0x1111111111111111,
0x1111111111111111,
0x1111111111111111,
0x1111111111111111,
0x1111111111111111,
0x1111111111111111,
0x1111111111111111,
0x1111111111111111,
0x1111111111111111,
0x1111111111111111,
0x1111111111111111,
0x1111111111111111,
0x1111111111111111,
0x1111111111111111,
0x1111111111111111,
0x2222222222222222,
0x3333333333333333,
];
let original_params = CrcParams {
algorithm: CrcAlgorithm::Crc32Custom,
name: "Original CRC",
width: 32,
poly: 0x1EDC6F41,
init: 0xFFFFFFFF,
init_algorithm: 0xFFFFFFFF,
refin: true,
refout: true,
xorout: 0xFFFFFFFF,
check: 0x12345678,
keys: CrcKeysStorage::from_keys_fold_256(original_keys),
};
let expanded_params = CrcParams {
algorithm: CrcAlgorithm::Crc64Custom,
name: "Expanded CRC",
width: 64,
poly: 0x42F0E1EBA9EA3693,
init: 0xFFFFFFFFFFFFFFFF,
init_algorithm: 0xFFFFFFFFFFFFFFFF,
refin: true,
refout: true,
xorout: 0xFFFFFFFFFFFFFFFF,
check: 0x123456789ABCDEF0,
keys: CrcKeysStorage::from_keys_fold_future_test(expanded_keys),
};
for i in 0..23 {
assert_eq!(
original_params.get_key(i),
0x1111111111111111,
"Original key {} should match",
i
);
assert_eq!(
expanded_params.get_key(i),
0x1111111111111111,
"Expanded key {} should match original",
i
);
}
assert_eq!(
expanded_params.get_key(23),
0x2222222222222222,
"New key 23 should be accessible"
);
assert_eq!(
expanded_params.get_key(24),
0x3333333333333333,
"New key 24 should be accessible"
);
assert_eq!(
original_params.get_key(23),
0,
"Original should return 0 for new key indices"
);
assert_eq!(
original_params.get_key(24),
0,
"Original should return 0 for new key indices"
);
assert_eq!(
original_params.get_key(30),
0,
"Original should return 0 for out-of-bounds"
);
assert_eq!(
expanded_params.get_key(30),
0,
"Expanded should return 0 for out-of-bounds"
);
assert_eq!(
original_params.key_count(),
23,
"Original should have 23 keys"
);
assert_eq!(
expanded_params.key_count(),
25,
"Expanded should have 25 keys"
);
assert_eq!(
original_params.get_key_checked(22),
Some(0x1111111111111111),
"Original last key should be accessible"
);
assert_eq!(
original_params.get_key_checked(23),
None,
"Original should return None for index 23"
);
assert_eq!(
expanded_params.get_key_checked(22),
Some(0x1111111111111111),
"Expanded key 22 should be accessible"
);
assert_eq!(
expanded_params.get_key_checked(24),
Some(0x3333333333333333),
"Expanded last key should be accessible"
);
assert_eq!(
expanded_params.get_key_checked(25),
None,
"Expanded should return None for index 25"
);
}
#[test]
#[allow(deprecated)]
fn test_future_expansion_backwards_compatibility() {
fn third_party_key_processor(params: CrcParams) -> Vec<u64> {
let mut result = Vec::new();
for i in 0..5 {
result.push(params.get_key(i));
}
for i in 10..15 {
result.push(params.get_key(i));
}
for i in 20..23 {
result.push(params.get_key(i));
}
result.push(params.get_key(30));
result.push(params.get_key(31));
result
}
let keys_23 = [0xABCDEF0123456789u64; 23];
let params_23 = CrcParams {
algorithm: CrcAlgorithm::Crc32Custom,
name: "Backwards Compat Test 23",
width: 32,
poly: 0x1EDC6F41,
init: 0xFFFFFFFF,
init_algorithm: 0xFFFFFFFF,
refin: true,
refout: true,
xorout: 0xFFFFFFFF,
check: 0x12345678,
keys: CrcKeysStorage::from_keys_fold_256(keys_23),
};
let keys_25 = [0xABCDEF0123456789u64; 25];
let params_25 = CrcParams {
algorithm: CrcAlgorithm::Crc64Custom,
name: "Backwards Compat Test 25",
width: 64,
poly: 0x42F0E1EBA9EA3693,
init: 0xFFFFFFFFFFFFFFFF,
init_algorithm: 0xFFFFFFFFFFFFFFFF,
refin: true,
refout: true,
xorout: 0xFFFFFFFFFFFFFFFF,
check: 0x123456789ABCDEF0,
keys: CrcKeysStorage::from_keys_fold_future_test(keys_25),
};
let result_23 = third_party_key_processor(params_23);
let result_25 = third_party_key_processor(params_25);
assert_eq!(
result_23.len(),
result_25.len(),
"Results should have same length"
);
for i in 0..13 {
assert_eq!(
result_23[i], result_25[i],
"Result {} should be identical",
i
);
assert_eq!(
result_23[i], 0xABCDEF0123456789,
"Result {} should match key value",
i
);
}
assert_eq!(
result_23[13], 0,
"Out-of-bounds access should return 0 for 23-key"
);
assert_eq!(
result_23[14], 0,
"Out-of-bounds access should return 0 for 23-key"
);
assert_eq!(
result_25[13], 0,
"Out-of-bounds access should return 0 for 25-key"
);
assert_eq!(
result_25[14], 0,
"Out-of-bounds access should return 0 for 25-key"
);
assert_eq!(
result_23, result_25,
"Third-party function should produce identical results"
);
}
#[cfg(all(
feature = "ffi",
any(target_arch = "aarch64", target_arch = "x86_64", target_arch = "x86")
))]
mod ffi_tests {
use crate::ffi::CrcFastParams;
use crate::{CrcAlgorithm, CrcKeysStorage, CrcParams};
#[test]
#[allow(deprecated)]
fn test_ffi_conversion_23_keys() {
let keys_23 = [0x1234567890ABCDEFu64; 23];
let original_params = CrcParams {
algorithm: CrcAlgorithm::Crc32Custom,
name: "FFI Test 23",
width: 32,
poly: 0x1EDC6F41,
init: 0xFFFFFFFF,
init_algorithm: 0xFFFFFFFF,
refin: true,
refout: true,
xorout: 0xFFFFFFFF,
check: 0x12345678,
keys: CrcKeysStorage::from_keys_fold_256(keys_23),
};
let ffi_params: CrcFastParams = original_params.into();
assert_eq!(ffi_params.key_count, 23, "FFI params should have 23 keys");
assert!(
!ffi_params.keys.is_null(),
"Keys pointer should not be null"
);
assert_eq!(ffi_params.width, 32, "Width should match");
assert_eq!(ffi_params.poly, 0x1EDC6F41, "Poly should match");
assert_eq!(ffi_params.init, 0xFFFFFFFF, "Init should match");
assert!(ffi_params.refin, "Refin should match");
assert!(ffi_params.refout, "Refout should match");
assert_eq!(ffi_params.xorout, 0xFFFFFFFF, "Xorout should match");
assert_eq!(ffi_params.check, 0x12345678, "Check should match");
unsafe {
for i in 0..23 {
let key_value = *ffi_params.keys.add(i);
assert_eq!(
key_value, 0x1234567890ABCDEF,
"Key {} should match expected value",
i
);
}
}
let converted_params: CrcParams = ffi_params.into();
assert_eq!(converted_params.algorithm, original_params.algorithm);
assert_eq!(converted_params.width, original_params.width);
assert_eq!(converted_params.poly, original_params.poly);
assert_eq!(converted_params.init, original_params.init);
assert_eq!(converted_params.refin, original_params.refin);
assert_eq!(converted_params.refout, original_params.refout);
assert_eq!(converted_params.xorout, original_params.xorout);
assert_eq!(converted_params.check, original_params.check);
assert_eq!(converted_params.key_count(), 23);
for i in 0..23 {
assert_eq!(
converted_params.get_key(i),
original_params.get_key(i),
"Converted key {} should match original",
i
);
}
}
#[test]
#[allow(deprecated)]
fn test_ffi_conversion_25_keys() {
let keys_25 = [0xFEDCBA0987654321u64; 25];
let original_params = CrcParams {
algorithm: CrcAlgorithm::Crc64Custom,
name: "FFI Test 25",
width: 64,
poly: 0x42F0E1EBA9EA3693,
init: 0xFFFFFFFFFFFFFFFF,
init_algorithm: 0xFFFFFFFFFFFFFFFF,
refin: true,
refout: true,
xorout: 0xFFFFFFFFFFFFFFFF,
check: 0x123456789ABCDEF0,
keys: CrcKeysStorage::from_keys_fold_future_test(keys_25),
};
let ffi_params: CrcFastParams = original_params.into();
assert_eq!(ffi_params.key_count, 25, "FFI params should have 25 keys");
assert!(
!ffi_params.keys.is_null(),
"Keys pointer should not be null"
);
assert_eq!(ffi_params.width, 64, "Width should match");
assert_eq!(ffi_params.poly, 0x42F0E1EBA9EA3693, "Poly should match");
unsafe {
for i in 0..25 {
let key_value = *ffi_params.keys.add(i);
assert_eq!(
key_value, 0xFEDCBA0987654321,
"Key {} should match expected value",
i
);
}
}
let converted_params: CrcParams = ffi_params.into();
assert_eq!(converted_params.key_count(), 25);
for i in 0..25 {
assert_eq!(
converted_params.get_key(i),
original_params.get_key(i),
"Converted key {} should match original",
i
);
}
}
#[test]
#[allow(deprecated)]
fn test_ffi_pointer_stability() {
let keys_23 = [0x1111111111111111u64; 23];
let params = CrcParams {
algorithm: CrcAlgorithm::Crc32Custom,
name: "Stability Test",
width: 32,
poly: 0x1EDC6F41,
init: 0xFFFFFFFF,
init_algorithm: 0xFFFFFFFF,
refin: true,
refout: true,
xorout: 0xFFFFFFFF,
check: 0x12345678,
keys: CrcKeysStorage::from_keys_fold_256(keys_23),
};
let ffi_params1: CrcFastParams = params.into();
let ffi_params2: CrcFastParams = params.into();
assert_eq!(
ffi_params1.keys, ffi_params2.keys,
"Identical key sets should get same stable pointer"
);
assert_eq!(
ffi_params1.key_count, ffi_params2.key_count,
"Key counts should match"
);
let different_keys = [0x2222222222222222u64; 23];
let different_params = CrcParams {
algorithm: CrcAlgorithm::Crc32Custom,
name: "Different Test",
width: 32,
poly: 0x1EDC6F41,
init: 0xFFFFFFFF,
init_algorithm: 0xFFFFFFFF,
refin: true,
refout: true,
xorout: 0xFFFFFFFF,
check: 0x12345678,
keys: CrcKeysStorage::from_keys_fold_256(different_keys),
};
let ffi_params3: CrcFastParams = different_params.into();
assert_ne!(
ffi_params1.keys, ffi_params3.keys,
"Different key sets should get different pointers"
);
}
#[test]
#[allow(deprecated)]
fn test_ffi_memory_safety() {
let keys_23 = [0xAAAAAAAAAAAAAAAAu64; 23];
let params = CrcParams {
algorithm: CrcAlgorithm::Crc32Custom,
name: "Memory Safety Test",
width: 32,
poly: 0x1EDC6F41,
init: 0xFFFFFFFF,
init_algorithm: 0xFFFFFFFF,
refin: true,
refout: true,
xorout: 0xFFFFFFFF,
check: 0x12345678,
keys: CrcKeysStorage::from_keys_fold_256(keys_23),
};
let ffi_params: CrcFastParams = params.into();
unsafe {
let keys_slice =
std::slice::from_raw_parts(ffi_params.keys, ffi_params.key_count as usize);
for (i, &key) in keys_slice.iter().enumerate() {
assert_eq!(
key, 0xAAAAAAAAAAAAAAAA,
"Key {} should be accessible and correct",
i
);
}
let keys_slice2 =
std::slice::from_raw_parts(ffi_params.keys, ffi_params.key_count as usize);
assert_eq!(
keys_slice, keys_slice2,
"Multiple slices should be identical"
);
}
let converted: CrcParams = ffi_params.into();
assert_eq!(converted.key_count(), 23);
for i in 0..23 {
assert_eq!(
converted.get_key(i),
0xAAAAAAAAAAAAAAAA,
"Converted key {} should match",
i
);
}
}
#[test]
#[allow(deprecated)]
fn test_ffi_different_key_counts() {
let keys_23 = [0x1111111111111111u64; 23];
let params_23 = CrcParams {
algorithm: CrcAlgorithm::Crc32Custom,
name: "23-Key FFI Test",
width: 32,
poly: 0x1EDC6F41,
init: 0xFFFFFFFF,
init_algorithm: 0xFFFFFFFF,
refin: true,
refout: true,
xorout: 0xFFFFFFFF,
check: 0x12345678,
keys: CrcKeysStorage::from_keys_fold_256(keys_23),
};
let keys_25 = [0x2222222222222222u64; 25];
let params_25 = CrcParams {
algorithm: CrcAlgorithm::Crc64Custom,
name: "25-Key FFI Test",
width: 64,
poly: 0x42F0E1EBA9EA3693,
init: 0xFFFFFFFFFFFFFFFF,
init_algorithm: 0xFFFFFFFFFFFFFFFF,
refin: true,
refout: true,
xorout: 0xFFFFFFFFFFFFFFFF,
check: 0x123456789ABCDEF0,
keys: CrcKeysStorage::from_keys_fold_future_test(keys_25),
};
let ffi_23: CrcFastParams = params_23.into();
let ffi_25: CrcFastParams = params_25.into();
assert_eq!(ffi_23.key_count, 23);
assert_eq!(ffi_25.key_count, 25);
unsafe {
for i in 0..23 {
let key = *ffi_23.keys.add(i);
assert_eq!(
key, 0x1111111111111111,
"23-key variant key {} should match",
i
);
}
for i in 0..25 {
let key = *ffi_25.keys.add(i);
assert_eq!(
key, 0x2222222222222222,
"25-key variant key {} should match",
i
);
}
for ffi_params in [&ffi_23, &ffi_25] {
for i in 0..ffi_params.key_count {
let key = *ffi_params.keys.add(i as usize);
assert_ne!(key, 0, "Key {} should not be zero", i);
}
}
}
let converted_23: CrcParams = ffi_23.into();
let converted_25: CrcParams = ffi_25.into();
assert_eq!(converted_23.key_count(), 23);
assert_eq!(converted_25.key_count(), 25);
for i in 0..23 {
assert_eq!(converted_23.get_key(i), 0x1111111111111111);
}
for i in 0..25 {
assert_eq!(converted_25.get_key(i), 0x2222222222222222);
}
}
#[test]
fn test_ffi_get_custom_params_function() {
use std::ffi::CString;
let name = CString::new("Test CRC").unwrap();
let ffi_params = crate::ffi::crc_fast_get_custom_params(
name.as_ptr(),
32,
0x1EDC6F41,
0xFFFFFFFF,
true,
0xFFFFFFFF,
0x12345678,
);
assert_eq!(ffi_params.width, 32);
assert_eq!(ffi_params.poly, 0x1EDC6F41);
assert_eq!(ffi_params.init, 0xFFFFFFFF);
assert!(ffi_params.refin);
assert!(ffi_params.refout);
assert_eq!(ffi_params.xorout, 0xFFFFFFFF);
assert_eq!(ffi_params.check, 0x12345678);
assert!(
!ffi_params.keys.is_null(),
"Keys pointer should not be null"
);
assert!(ffi_params.key_count > 0, "Should have keys");
unsafe {
for i in 0..ffi_params.key_count {
let _key = *ffi_params.keys.add(i as usize);
}
}
let params: CrcParams = ffi_params.into();
assert_eq!(params.width, 32);
assert_eq!(params.poly, 0x1EDC6F41);
assert_eq!(params.init, 0xFFFFFFFF);
assert!(params.refin);
assert!(params.refout);
assert_eq!(params.xorout, 0xFFFFFFFF);
assert_eq!(params.check, 0x12345678);
assert!(params.key_count() > 0);
}
}