use tensogram_szip::{
AEC_DATA_PREPROCESS, AEC_NOT_ENFORCE, AEC_RESTRICTED, AecParams, aec_compress, aec_decompress,
aec_decompress_range,
};
fn default_params() -> AecParams {
AecParams {
bits_per_sample: 8,
block_size: 16,
rsi: 64,
flags: AEC_DATA_PREPROCESS,
}
}
fn compress_ramp() -> (Vec<u8>, Vec<u64>, usize) {
let data: Vec<u8> = (0..1024).map(|i| (i % 256) as u8).collect();
let len = data.len();
let (compressed, offsets) = aec_compress(&data, &default_params()).unwrap();
(compressed, offsets, len)
}
mod truncated {
use super::*;
#[test]
fn truncated_by_one_byte() {
let (mut compressed, _, len) = compress_ramp();
compressed.pop();
assert!(aec_decompress(&compressed, len, &default_params()).is_err());
}
#[test]
fn truncated_to_half() {
let (compressed, _, len) = compress_ramp();
let half = &compressed[..compressed.len() / 2];
assert!(aec_decompress(half, len, &default_params()).is_err());
}
#[test]
fn truncated_to_zero() {
let result = aec_decompress(&[], 1024, &default_params());
if let Ok(out) = result {
assert!(
out.len() < 1024,
"should not produce full output from empty input"
);
}
}
}
mod corrupt {
use super::*;
#[test]
fn flip_first_byte() {
let (mut compressed, _, len) = compress_ramp();
compressed[0] ^= 0xFF;
let _ = aec_decompress(&compressed, len, &default_params());
}
#[test]
fn flip_middle_byte() {
let (mut compressed, _, len) = compress_ramp();
let mid = compressed.len() / 2;
compressed[mid] ^= 0xFF;
let _ = aec_decompress(&compressed, len, &default_params());
}
#[test]
fn flip_last_byte() {
let (mut compressed, _, len) = compress_ramp();
let last = compressed.len() - 1;
compressed[last] ^= 0xFF;
let _ = aec_decompress(&compressed, len, &default_params());
}
#[test]
fn all_zeros() {
let compressed = vec![0u8; 100];
let _ = aec_decompress(&compressed, 1024, &default_params());
}
#[test]
fn all_ones() {
let compressed = vec![0xFFu8; 100];
let _ = aec_decompress(&compressed, 1024, &default_params());
}
}
mod invalid_params {
use super::*;
#[test]
fn bps_zero() {
let params = AecParams {
bits_per_sample: 0,
block_size: 16,
rsi: 64,
flags: 0,
};
assert!(aec_compress(&[0u8; 16], ¶ms).is_err());
}
#[test]
fn bps_33() {
let params = AecParams {
bits_per_sample: 33,
block_size: 16,
rsi: 64,
flags: 0,
};
assert!(aec_compress(&[0u8; 16], ¶ms).is_err());
}
#[test]
fn block_size_zero() {
let params = AecParams {
bits_per_sample: 8,
block_size: 0,
rsi: 64,
flags: 0,
};
assert!(aec_compress(&[0u8; 16], ¶ms).is_err());
}
#[test]
fn block_size_odd_without_not_enforce() {
let params = AecParams {
bits_per_sample: 8,
block_size: 3,
rsi: 64,
flags: 0,
};
assert!(aec_compress(&[0u8; 16], ¶ms).is_err());
}
#[test]
fn block_size_odd_with_not_enforce() {
let params = AecParams {
bits_per_sample: 8,
block_size: 7,
rsi: 64,
flags: AEC_NOT_ENFORCE,
};
assert!(aec_compress(&[0u8; 16], ¶ms).is_err());
}
#[test]
fn rsi_zero() {
let params = AecParams {
bits_per_sample: 8,
block_size: 16,
rsi: 0,
flags: 0,
};
assert!(aec_compress(&[0u8; 16], ¶ms).is_err());
}
#[test]
fn rsi_too_large() {
let params = AecParams {
bits_per_sample: 8,
block_size: 16,
rsi: 4097,
flags: 0,
};
assert!(aec_compress(&[0u8; 16], ¶ms).is_err());
}
#[test]
fn restricted_bps_5() {
let params = AecParams {
bits_per_sample: 5,
block_size: 16,
rsi: 64,
flags: AEC_RESTRICTED,
};
assert!(aec_compress(&[0u8; 16], ¶ms).is_err());
}
}
mod misaligned_data {
use super::*;
#[test]
fn bps16_odd_length() {
let params = AecParams {
bits_per_sample: 16,
block_size: 16,
rsi: 64,
flags: 0,
};
assert!(aec_compress(&[0u8; 3], ¶ms).is_err()); }
#[test]
fn bps32_non_multiple_of_4() {
let params = AecParams {
bits_per_sample: 32,
block_size: 16,
rsi: 64,
flags: 0,
};
assert!(aec_compress(&[0u8; 5], ¶ms).is_err()); }
}
mod range_errors {
use super::*;
#[test]
fn byte_pos_beyond_data() {
let (compressed, offsets, _) = compress_ramp();
let result = aec_decompress_range(&compressed, &offsets, 9999, 32, &default_params());
assert!(result.is_err());
}
#[test]
fn empty_offsets_with_nonzero_pos() {
let (compressed, _, _) = compress_ramp();
let result = aec_decompress_range(&compressed, &[], 64, 32, &default_params());
assert!(result.is_err());
}
#[test]
fn oversized_byte_range() {
let (compressed, offsets, _) = compress_ramp();
let rsi_bytes = 64 * 16; let result =
aec_decompress_range(&compressed, &offsets, 0, rsi_bytes + 1, &default_params());
assert!(result.is_err());
}
}
mod preallocation_hardening {
use super::*;
#[test]
fn decompress_rejects_pathological_expected_size() {
let (compressed, _, _) = compress_ramp();
let err = aec_decompress(&compressed, usize::MAX, &default_params())
.expect_err("expected allocation failure, not success nor abort");
let msg = format!("{err}");
assert!(
msg.contains("failed to reserve"),
"error should report allocation failure, got: {msg}"
);
}
#[test]
fn decompress_rejects_expected_size_overflowing_isize() {
let (compressed, _, _) = compress_ramp();
let pathological = isize::MAX as usize + 1;
let err = aec_decompress(&compressed, pathological, &default_params())
.expect_err("expected allocation failure, not success nor abort");
let msg = format!("{err}");
assert!(
msg.contains("failed to reserve"),
"error should report allocation failure, got: {msg}"
);
}
}