molframe-core 0.5.1

Core types, storage and analysis contracts for molframe
Documentation
use super::*;
use crate::{ScratchPolicy, TempStoragePolicy};
use flate2::Compression as GzipLevel;
use flate2::write::GzEncoder;
use std::io::Write;

#[test]
fn compressed_source_requires_explicit_spill() {
    let path = unique_path("disabled.gz");
    write_gzip(&path, b"abcdefgh");
    let error = WindowedSourceFile::open(&path, 8, &ExecutionContext::default())
        .expect_err("default context must not spill");
    assert_eq!(error.code(), Code::E1902);
    std::fs::remove_file(path).expect("remove fixture");
}

#[test]
fn gzip_spool_is_bounded_seekable_and_deleted_exactly_once() {
    let base = unique_path("enabled");
    let path = base.with_extension("gz");
    let spill_root = base.with_extension("spill");
    write_gzip(&path, b"abcdefghijklmnopqrstuvwxyz");
    let context = ExecutionContext::builder()
        .scratch_policy(ScratchPolicy::new(0))
        .temp_storage_policy(TempStoragePolicy::directory(&spill_root, 4096))
        .build()
        .expect("context");
    let mut source = WindowedSourceFile::open(&path, 8, &context).expect("spooled source");
    assert!(source.spill_bytes() > 26);
    assert_eq!(source.len_hint(), Some(26));
    assert_eq!(
        source.window(6, 8).expect("cross-record").bytes(),
        b"ghijklmn"
    );
    assert_eq!(source.window(0, 8).expect("rollback").bytes(), b"abcdefgh");
    assert!(context.spill_bytes() > 0);
    drop(source);
    assert_eq!(context.spill_bytes(), 0);
    assert!(
        std::fs::read_dir(&spill_root)
            .expect("spill directory")
            .next()
            .is_none()
    );
    std::fs::remove_file(path).expect("remove fixture");
    std::fs::remove_dir(spill_root).expect("remove spill root");
}

#[test]
#[cfg(feature = "zstd")]
fn zstd_spool_uses_the_same_bounded_window_contract() {
    let base = unique_path("zstd-enabled");
    let path = base.with_extension("zst");
    let spill_root = base.with_extension("spill");
    let file = File::create(&path).expect("create fixture");
    let mut encoder = zstd::stream::write::Encoder::new(file, 1).expect("zstd encoder");
    encoder
        .write_all(b"abcdefghijklmnopqrstuvwxyz")
        .expect("encode fixture");
    encoder.finish().expect("finish fixture");
    let context = ExecutionContext::builder()
        .scratch_policy(ScratchPolicy::new(0))
        .temp_storage_policy(TempStoragePolicy::directory(&spill_root, 4096))
        .build()
        .expect("context");
    let mut source = WindowedSourceFile::open(&path, 8, &context).expect("spooled source");
    assert_eq!(source.len_hint(), Some(26));
    assert_eq!(
        source.window(14, 8).expect("cross-record").bytes(),
        b"opqrstuv"
    );
    drop(source);
    assert_eq!(context.spill_bytes(), 0);
    std::fs::remove_file(path).expect("remove fixture");
    std::fs::remove_dir(spill_root).expect("remove spill root");
}

fn write_gzip(path: &Path, bytes: &[u8]) {
    let file = File::create(path).expect("create fixture");
    let mut encoder = GzEncoder::new(file, GzipLevel::fast());
    encoder.write_all(bytes).expect("encode fixture");
    encoder.finish().expect("finish fixture");
}

fn unique_path(suffix: &str) -> std::path::PathBuf {
    std::env::temp_dir().join(format!(
        "molframe-source-file-{}-{suffix}",
        std::process::id()
    ))
}