use std::sync::Arc;
use tinyquant_core::codec::CompressedVector;
use tinyquant_io::codec_file::reader::CodecFileReader;
use tinyquant_io::compressed_vector::{from_bytes, to_bytes};
use tinyquant_io::errors::IoError;
fn valid_payload() -> Vec<u8> {
let indices = vec![0u8, 1, 2, 3];
let cv =
CompressedVector::new(indices.into_boxed_slice(), None, Arc::from("test"), 4, 8).unwrap();
to_bytes(&cv)
}
#[test]
fn truncated_at_69_bytes_errors() {
let payload = valid_payload();
let short = &payload[..69];
let err = from_bytes(short).unwrap_err();
assert!(
matches!(
err,
IoError::Truncated {
needed: 70,
got: 69
}
),
"expected Truncated{{needed:70,got:69}}, got: {err:?}"
);
}
#[test]
fn empty_slice_errors() {
let err = from_bytes(&[]).unwrap_err();
assert!(
matches!(err, IoError::Truncated { .. }),
"expected Truncated, got: {err:?}"
);
}
#[test]
fn unknown_version_errors() {
let mut payload = valid_payload();
payload[0] = 0x02; let err = from_bytes(&payload).unwrap_err();
assert!(
matches!(err, IoError::UnknownVersion { got: 0x02 }),
"expected UnknownVersion{{got:0x02}}, got: {err:?}"
);
}
#[test]
fn invalid_bit_width_errors() {
let mut payload = valid_payload();
payload[69] = 3; let err = from_bytes(&payload).unwrap_err();
assert!(
matches!(err, IoError::InvalidBitWidth { got: 3 }),
"expected InvalidBitWidth{{got:3}}, got: {err:?}"
);
}
#[test]
fn invalid_utf8_in_config_hash_errors() {
let mut payload = valid_payload();
payload[1] = 0xFF; let err = from_bytes(&payload).unwrap_err();
assert!(
matches!(err, IoError::InvalidUtf8),
"expected InvalidUtf8, got: {err:?}"
);
}
#[test]
fn invalid_residual_flag_errors() {
let mut payload = valid_payload();
let flag_offset = 70 + 4; payload[flag_offset] = 0x02; let err = from_bytes(&payload).unwrap_err();
assert!(
matches!(
err,
IoError::Decode(tinyquant_core::errors::CodecError::InvalidResidualFlag { got: 0x02 })
),
"expected Decode(InvalidResidualFlag{{got:0x02}}), got: {err:?}"
);
}
#[test]
fn truncated_after_flag_errors() {
let indices = vec![0u8, 1, 2, 3];
let residual = vec![0u8; 8]; let cv = CompressedVector::new(
indices.into_boxed_slice(),
Some(residual.into_boxed_slice()),
Arc::from("test"),
4,
8,
)
.unwrap();
let full = to_bytes(&cv);
let flag_offset = 70 + 4; let truncated = &full[..flag_offset + 2]; let err = from_bytes(truncated).unwrap_err();
assert!(
matches!(err, IoError::Truncated { .. }),
"expected Truncated, got: {err:?}"
);
}
#[test]
fn from_io_error_compiles() {
let io_err = std::io::Error::new(std::io::ErrorKind::NotFound, "not found");
let tq_err: IoError = io_err.into();
assert!(
matches!(tq_err, IoError::Io(_)),
"expected IoError::Io variant, got: {tq_err:?}"
);
}
#[test]
fn from_codec_error_compiles() {
let codec_err = tinyquant_core::errors::CodecError::UnsupportedBitWidth { got: 3 };
let tq_err: IoError = codec_err.into();
assert!(
matches!(tq_err, IoError::Decode(_)),
"expected IoError::Decode variant, got: {tq_err:?}"
);
}
#[test]
fn oversized_metadata_len_in_codec_file_header_rejected() {
let mut buf: Vec<u8> = Vec::new();
buf.extend_from_slice(b"TQCV"); buf.push(0x01); buf.extend_from_slice(&[0u8; 3]); buf.extend_from_slice(&1u64.to_le_bytes()); buf.extend_from_slice(&4u32.to_le_bytes()); buf.push(8u8); buf.push(0u8); buf.extend_from_slice(&4u16.to_le_bytes()); buf.extend_from_slice(b"test");
let bad_len: u32 = (16 * 1024 * 1024 + 1) as u32;
buf.extend_from_slice(&bad_len.to_le_bytes());
let cursor = std::io::Cursor::new(buf);
match CodecFileReader::new(cursor) {
Err(IoError::InvalidHeader) => {}
Err(e) => panic!("expected InvalidHeader for oversized metadata_len, got: {e:?}"),
Ok(_) => panic!("expected Err for oversized metadata_len, got Ok"),
}
}
#[test]
fn oversized_record_len_in_codec_file_rejected() {
let mut buf: Vec<u8> = Vec::new();
buf.extend_from_slice(b"TQCV"); buf.push(0x01); buf.extend_from_slice(&[0u8; 3]); buf.extend_from_slice(&1u64.to_le_bytes()); buf.extend_from_slice(&4u32.to_le_bytes()); buf.push(8u8); buf.push(0u8); buf.extend_from_slice(&0u16.to_le_bytes()); buf.extend_from_slice(&0u32.to_le_bytes());
buf.extend_from_slice(&[0u8; 4]);
let bad_record_len: u32 = 4 * 1024 * 1024 + 1;
buf.extend_from_slice(&bad_record_len.to_le_bytes());
let cursor = std::io::Cursor::new(buf);
let mut reader = CodecFileReader::new(cursor).unwrap();
let err = reader.next_vector().unwrap_err();
assert!(
matches!(err, IoError::InvalidHeader),
"expected InvalidHeader for oversized record_len, got: {err:?}"
);
}
#[test]
fn extreme_dimension_does_not_panic_in_from_bytes() {
use tinyquant_io::compressed_vector::from_bytes;
let mut buf = vec![0u8; 70];
buf[0] = 0x01; buf[65..69].copy_from_slice(&u32::MAX.to_le_bytes());
buf[69] = 8; let result = from_bytes(&buf);
assert!(
result.is_err(),
"expected error for extreme dimension, got success"
);
}