hf2q 0.1.7

Pure Rust CLI for converting HuggingFace models to hardware-optimized formats and serving them over an OpenAI-compatible API on Apple Silicon
use serde_json::Value;
use sha2::Digest;

use super::model_recipe::{
    ModelPreparationReceiptV2, PreparedModelProfileV1, SourceRetentionChoice,
    MAX_PREPARED_MODEL_PROFILE_BYTES,
};

const PREPARATION_BYTES: &[u8] =
    include_bytes!("../../data/model-recipes/qwen38-27b-preparation-receipt-v2.json");
const PROFILE_BYTES: &[u8] =
    include_bytes!("../../data/model-recipes/qwen38-27b-prepared-profile-v1.json");

#[test]
fn prepared_profile_golden_is_exact_and_cross_binds_the_pair_receipt() {
    let receipt = ModelPreparationReceiptV2::parse(PREPARATION_BYTES).unwrap();
    let profile = PreparedModelProfileV1::build_keep(&receipt, PREPARATION_BYTES).unwrap();
    assert_eq!(profile.to_deterministic_json().unwrap(), PROFILE_BYTES);
    assert_eq!(
        PreparedModelProfileV1::parse(PROFILE_BYTES).unwrap(),
        profile
    );
    assert_eq!(profile.repository_id(), "Qwen/Qwen3.8-27B");
    assert_eq!(
        profile.revision(),
        "1d4bf0f2ff6012fd82039f2fa52739d0dd7c60c0"
    );
    assert_eq!(profile.recipe_id(), "qwen38-27b-official-v1");
    assert_eq!(profile.source_retention(), SourceRetentionChoice::Keep);
    assert_eq!(PROFILE_BYTES.len(), 1_240);
    assert_eq!(
        hex::encode(sha2::Sha256::digest(PROFILE_BYTES)),
        "a48bf14c469597f7567e9c11e689aeac9ccb39b1506afa57d79754f8f19c312b"
    );
    assert_eq!(
        profile.preparation_receipt_sha256(),
        "050900cc0bb998272504a5be94b3105092134a59d47ee1fcca28747464d8240a"
    );
    assert_eq!(
        profile
            .verify_preparation_receipt(PREPARATION_BYTES)
            .unwrap(),
        receipt
    );
}

#[test]
fn parser_rejects_size_duplicate_unknown_trailing_and_noncanonical_bytes() {
    let oversized = vec![b' '; MAX_PREPARED_MODEL_PROFILE_BYTES + 1];
    assert!(PreparedModelProfileV1::parse(&oversized).is_err());

    let text = std::str::from_utf8(PROFILE_BYTES).unwrap();
    let duplicate = text.replacen(
        "{\"kind\":\"hf2q.prepared-model-profile\",",
        "{\"kind\":\"hf2q.prepared-model-profile\",\"kind\":\"hf2q.prepared-model-profile\",",
        1,
    );
    assert!(PreparedModelProfileV1::parse(duplicate.as_bytes()).is_err());

    let unknown = text.replacen("{\"kind\":", "{\"unknown\":true,\"kind\":", 1);
    assert!(PreparedModelProfileV1::parse(unknown.as_bytes()).is_err());

    let mut trailing = PROFILE_BYTES.to_vec();
    trailing.extend_from_slice(b"{}");
    assert!(PreparedModelProfileV1::parse(&trailing).is_err());

    let value: Value = serde_json::from_slice(PROFILE_BYTES).unwrap();
    let mut pretty = serde_json::to_vec_pretty(&value).unwrap();
    pretty.push(b'\n');
    assert!(PreparedModelProfileV1::parse(&pretty).is_err());

    let deep = format!("{{\"deep\":{} }}", "[".repeat(65) + "0" + &"]".repeat(65));
    assert!(PreparedModelProfileV1::parse(deep.as_bytes()).is_err());
}

#[test]
fn parser_rejects_identity_retention_state_and_descriptor_mutations() {
    let cases: Vec<Box<dyn Fn(&mut Value)>> = vec![
        Box::new(|value| value["kind"] = Value::String("other".into())),
        Box::new(|value| value["schema_version"] = Value::from(2)),
        Box::new(|value| value["package"] = Value::String("other".into())),
        Box::new(|value| value["repository"]["id"] = Value::String("other/model".into())),
        Box::new(|value| value["recipe"]["sha256"] = Value::String("a".repeat(64))),
        Box::new(|value| value["preparation_receipt"]["schema_version"] = Value::from(1)),
        Box::new(|value| value["source_retention"] = Value::String("delete".into())),
        Box::new(|value| value["state"] = Value::String("ready".into())),
        Box::new(|value| {
            value["artifacts"]
                .as_array_mut()
                .unwrap()
                .pop()
                .map(|_| ())
                .unwrap()
        }),
        Box::new(|value| {
            value["artifacts"][0]["path"] = Value::String("artifacts/other.gguf".into())
        }),
        Box::new(|value| {
            value["artifacts"][0]["conversion_receipt_sha256"] = Value::String("A".repeat(64))
        }),
    ];
    for mutate in cases {
        let mut value: Value = serde_json::from_slice(PROFILE_BYTES).unwrap();
        mutate(&mut value);
        let mut bytes = serde_json::to_vec(&value).unwrap();
        bytes.push(b'\n');
        assert!(PreparedModelProfileV1::parse(&bytes).is_err());
    }
}

#[test]
fn profile_rejects_mutated_or_cross_pair_receipt_bytes() {
    let profile = PreparedModelProfileV1::parse(PROFILE_BYTES).unwrap();
    let mut value: Value = serde_json::from_slice(PREPARATION_BYTES).unwrap();
    value["artifacts"][0]["conversion_receipt_sha256"] = Value::String("b".repeat(64));
    let mut bytes = serde_json::to_vec(&value).unwrap();
    bytes.push(b'\n');
    assert!(ModelPreparationReceiptV2::parse(&bytes).is_ok());
    assert!(profile.verify_preparation_receipt(&bytes).is_err());
}