test(legacy): cover the v0.2 decoder ABI

The v0.2 decoder implementation and C boundary were already Rust-owned, but
its public error predicate, frame-size sentinel behavior, and opaque streaming
context lifecycle lacked focused Rust coverage. Add tests for malformed input,
content-size error reporting, one-shot decoding, reset behavior, and idempotent
context release so future legacy changes are checked at the ABI boundary.

Test Plan:
- Focused v0.2 Cargo tests under both feature sets -- 6 passed each
- `make -C tests -j2 test-legacy` -- passed
- `cargo +nightly fmt --manifest-path rust/Cargo.toml -- --check` -- passed
- Scoped `git diff --check` -- passed
This commit is contained in:
2026-07-18 18:00:57 +02:00
parent 829f781855
commit c1e3f7d07a
+90
View File
@@ -1710,6 +1710,96 @@ mod tests {
decode(&RAW_FRAME[..RAW_FRAME.len() - 1], 32).unwrap_err(),
ERROR(ZstdErrorCode::SrcSizeWrong)
);
assert_eq!(
decode(RAW_FRAME, 4).unwrap_err(),
ERROR(ZstdErrorCode::DstSizeTooSmall)
);
}
}
#[test]
fn public_error_predicate_matches_the_c_abi() {
assert_eq!(ZSTDv02_isError(0), 0);
assert_eq!(ZSTDv02_isError(ERROR(ZstdErrorCode::Generic)), 1);
assert_eq!(ZSTDv02_isError(ERROR(ZstdErrorCode::SrcSizeWrong)), 1);
assert_eq!(ZSTDv02_isError(ERROR(ZstdErrorCode::MaxCode)), 0);
assert_eq!(ZSTDv02_isError(usize::MAX), 1);
}
#[test]
fn frame_size_abi_writes_error_and_content_size_sentinel() {
unsafe {
let mut c_size = 0xA5A5_A5A5usize;
let mut d_bound = 0x5A5A_5A5A_5A5A_5A5Au64;
ZSTDv02_findFrameSizeInfoLegacy(
RAW_FRAME.as_ptr() as *const c_void,
RAW_FRAME.len() - 1,
&mut c_size,
&mut d_bound,
);
assert_eq!(c_size, ERROR(ZstdErrorCode::SrcSizeWrong));
assert_eq!(d_bound, ZSTD_CONTENTSIZE_ERROR);
let mut bad_magic = RAW_FRAME.to_vec();
bad_magic[0] ^= 1;
ZSTDv02_findFrameSizeInfoLegacy(
bad_magic.as_ptr() as *const c_void,
bad_magic.len(),
&mut c_size,
&mut d_bound,
);
assert_eq!(c_size, ERROR(ZstdErrorCode::PrefixUnknown));
assert_eq!(d_bound, ZSTD_CONTENTSIZE_ERROR);
}
}
#[test]
fn context_abi_preserves_stream_state_and_supports_one_shot_decode() {
unsafe {
let dctx = ZSTDv02_createDCtx();
assert!(!dctx.is_null());
assert_eq!(ZSTDv02_nextSrcSizeToDecompress(dctx), 4);
let mut output = [0u8; 32];
assert_eq!(
ZSTDv02_decompressContinue(
dctx,
output.as_mut_ptr() as *mut c_void,
output.len(),
RAW_FRAME.as_ptr() as *const c_void,
3,
),
ERROR(ZstdErrorCode::SrcSizeWrong)
);
assert_eq!(ZSTDv02_nextSrcSizeToDecompress(dctx), 4);
let mut bad_magic = RAW_FRAME.to_vec();
bad_magic[0] ^= 1;
assert_eq!(
ZSTDv02_decompressContinue(
dctx,
output.as_mut_ptr() as *mut c_void,
output.len(),
bad_magic.as_ptr() as *const c_void,
4,
),
ERROR(ZstdErrorCode::PrefixUnknown)
);
assert_eq!(ZSTDv02_nextSrcSizeToDecompress(dctx), 4);
let decoded = ZSTDv02_decompressDCtx(
dctx as *mut c_void,
output.as_mut_ptr() as *mut c_void,
output.len(),
RAW_FRAME.as_ptr() as *const c_void,
RAW_FRAME.len(),
);
assert_eq!(decoded, b"raw v0.2!!!".len());
assert_eq!(&output[..decoded], b"raw v0.2!!!");
assert_eq!(ZSTDv02_resetDCtx(dctx), 0);
assert_eq!(ZSTDv02_nextSrcSizeToDecompress(dctx), 4);
assert_eq!(ZSTDv02_freeDCtx(dctx), 0);
assert_eq!(ZSTDv02_freeDCtx(ptr::null_mut()), 0);
}
}