use luna_core::jit::aot_meta::{
AOT_META_MAGIC, AOT_META_VERSION, AotTraceMetaHeader, decode_meta_blob,
};
fn empty_header() -> Vec<u8> {
let header = AotTraceMetaHeader {
magic: AOT_META_MAGIC,
version: AOT_META_VERSION,
head_pc: 0,
n_ops: 0,
window_size: 0,
dispatchable: 0,
tag_res_kind: 0,
entry_tags_len: 0,
exit_tags_len: 0,
};
let mut b = Vec::with_capacity(AotTraceMetaHeader::SIZE);
b.extend_from_slice(&header.magic.to_le_bytes());
b.extend_from_slice(&header.version.to_le_bytes());
b.extend_from_slice(&header.head_pc.to_le_bytes());
b.extend_from_slice(&header.n_ops.to_le_bytes());
b.extend_from_slice(&header.window_size.to_le_bytes());
b.push(header.dispatchable);
b.push(header.tag_res_kind);
b.extend_from_slice(&header.entry_tags_len.to_le_bytes());
b.extend_from_slice(&header.exit_tags_len.to_le_bytes());
b
}
#[test]
fn decode_rejects_blob_shorter_than_header() {
let blob = vec![0u8; 7];
let err = decode_meta_blob(&blob).unwrap_err();
assert!(
err.contains("shorter than header"),
"expected 'shorter than header' err, got {err:?}"
);
}
#[test]
fn decode_rejects_v2_tail_truncated_at_count() {
let mut blob = empty_header();
blob.push(0);
let err = decode_meta_blob(&blob).unwrap_err();
assert!(
err.contains("v2 tail truncated at count"),
"expected v2-count truncation err, got {err:?}"
);
}
#[test]
fn decode_rejects_v2_tail_truncated_at_entry_header() {
let mut blob = empty_header();
blob.extend_from_slice(&1u32.to_le_bytes()); blob.extend_from_slice(&[0u8, 0, 0]);
let err = decode_meta_blob(&blob).unwrap_err();
assert!(
err.contains("v2 tail truncated at entry header"),
"expected v2-entry-header truncation err, got {err:?}"
);
}
#[test]
fn decode_rejects_v2_tail_truncated_at_entry_tags() {
let mut blob = empty_header();
blob.extend_from_slice(&1u32.to_le_bytes()); blob.extend_from_slice(&5u32.to_le_bytes()); blob.extend_from_slice(&10u32.to_le_bytes()); blob.extend_from_slice(&[0u8, 0, 0]); let err = decode_meta_blob(&blob).unwrap_err();
assert!(
err.contains("v2 tail truncated at entry tags"),
"expected v2-entry-tags truncation err, got {err:?}"
);
}
#[test]
fn decode_rejects_v3_tail_truncated_at_count() {
let mut blob = empty_header();
blob.extend_from_slice(&0u32.to_le_bytes()); blob.push(0); let err = decode_meta_blob(&blob).unwrap_err();
assert!(
err.contains("v3 tail truncated at count"),
"expected v3-count truncation err, got {err:?}"
);
}
#[test]
fn decode_rejects_v3_tail_truncated_at_entry_header() {
let mut blob = empty_header();
blob.extend_from_slice(&0u32.to_le_bytes()); blob.extend_from_slice(&1u32.to_le_bytes()); blob.extend_from_slice(&[0u8; 5]);
let err = decode_meta_blob(&blob).unwrap_err();
assert!(
err.contains("v3 tail truncated at entry header"),
"expected v3-entry-header truncation err, got {err:?}"
);
}
#[test]
fn decode_rejects_v3_tail_truncated_at_entry_tags() {
let mut blob = empty_header();
blob.extend_from_slice(&0u32.to_le_bytes()); blob.extend_from_slice(&1u32.to_le_bytes()); blob.extend_from_slice(&3u32.to_le_bytes()); blob.extend_from_slice(&4u32.to_le_bytes()); blob.extend_from_slice(&8u32.to_le_bytes()); blob.extend_from_slice(&[0u8, 0]); let err = decode_meta_blob(&blob).unwrap_err();
assert!(
err.contains("v3 tail truncated at entry tags"),
"expected v3-entry-tags truncation err, got {err:?}"
);
}
#[test]
fn decode_rejects_v3_tail_truncated_at_chain_header() {
let mut blob = empty_header();
blob.extend_from_slice(&0u32.to_le_bytes()); blob.extend_from_slice(&1u32.to_le_bytes()); blob.extend_from_slice(&3u32.to_le_bytes()); blob.extend_from_slice(&4u32.to_le_bytes()); blob.extend_from_slice(&0u32.to_le_bytes()); let err = decode_meta_blob(&blob).unwrap_err();
assert!(
err.contains("v3 tail truncated at chain header"),
"expected v3-chain-header truncation err, got {err:?}"
);
}
#[test]
fn decode_rejects_v3_tail_truncated_at_chain_bytes() {
let mut blob = empty_header();
blob.extend_from_slice(&0u32.to_le_bytes()); blob.extend_from_slice(&1u32.to_le_bytes()); blob.extend_from_slice(&3u32.to_le_bytes()); blob.extend_from_slice(&4u32.to_le_bytes()); blob.extend_from_slice(&0u32.to_le_bytes()); blob.extend_from_slice(&24u32.to_le_bytes()); blob.extend_from_slice(&[0u8; 6]); let err = decode_meta_blob(&blob).unwrap_err();
assert!(
err.contains("v3 tail truncated at chain bytes"),
"expected v3-chain-bytes truncation err, got {err:?}"
);
}
#[test]
fn decode_accepts_minimal_well_formed_blob() {
let mut blob = empty_header();
blob.extend_from_slice(&0u32.to_le_bytes()); blob.extend_from_slice(&0u32.to_le_bytes()); let decoded = decode_meta_blob(&blob).expect("minimal blob decodes");
assert!(decoded.entry_tags.is_empty());
assert!(decoded.exit_tags.is_empty());
assert!(decoded.per_exit_tags.is_empty());
assert!(decoded.per_exit_inline.is_empty());
}