Your browser sucks, JavaScript disabled! Gunnar's console needs JavaScript and WebAssembly. Git over SSH on port 2222 does not.

nordisk/edda

crates/gunnar-pack/tests/real_gix_odb.rs

//! The seam test: the writer must serve a pack out of a **real** object database, not
//! only the tidy in-memory fixture the other tests use.
//!
//! `gix::Repository::objects` is a `gix_object::Find + Exists` implementation over
//! loose objects on disk. If `gunnar-pack` composes with that unchanged, it composes
//! with `gunnar-store`'s adapter for the same traits (TOTAL-PROMPT §4). That is the
//! whole reason the read seam is gix's traits and not a bespoke one.
//!
//! `gix` porcelain appears **here only**, as a dev-dependency fixture. This crate is
//! on the server side of the dependency guard and must never link it for real.

mod common;

use std::io::Cursor;

use common::{read_from_pack_dir, PackDir};
use gix_hash::Kind;
use gunnar_pack::{index_pack, write_pack_to_vec, IndexOptions, WriteOptions};

#[test]
fn a_pack_served_from_a_real_gix_object_database_indexes_and_reads_back() -> anyhow::Result<()> {
    let repo_dir = tempfile::tempdir()?;
    let repo = gix::init_bare(repo_dir.path())?;
    assert_eq!(
        repo.object_hash(),
        Kind::Sha1,
        "gix::init_bare makes a sha1 repo"
    );

    let readme = repo
        .write_blob(b"# served straight out of a real odb\n")?
        .detach();
    let script = repo.write_blob(b"#!/bin/sh\necho gunnar\n")?.detach();

    let mut tree = gix_object::Tree {
        entries: vec![
            gix_object::tree::Entry {
                mode: gix_object::tree::EntryKind::Blob.into(),
                filename: "README.md".into(),
                oid: readme,
            },
            gix_object::tree::Entry {
                mode: gix_object::tree::EntryKind::BlobExecutable.into(),
                filename: "run.sh".into(),
                oid: script,
            },
        ],
    };
    tree.entries.sort();
    let tree_id = repo.write_object(&tree)?.detach();

    let signature = gix::actor::Signature {
        name: "Gunnar Test".into(),
        email: "gunnar@example.invalid".into(),
        time: gix::date::Time::new(1_700_000_000, 0),
    };
    let commit = gix_object::Commit {
        tree: tree_id,
        parents: Default::default(),
        author: signature.clone(),
        committer: signature,
        encoding: None,
        message: "a real commit\n".into(),
        extra_headers: Vec::new(),
    };
    let commit_id = repo.write_object(&commit)?.detach();

    // The seam: `repo.objects` is handed in as nothing but `Find + Exists`.
    let ids = vec![commit_id, tree_id, readme, script];
    let (pack, outcome) =
        write_pack_to_vec(&ids, &repo.objects, &WriteOptions::new(repo.object_hash()))?;
    assert_eq!(outcome.num_objects, 4);

    let dir = PackDir::new();
    let indexed = index_pack(
        &mut Cursor::new(&pack),
        Some(&dir.pack_dir()),
        &IndexOptions::new(Kind::Sha1),
        None,
    )?;
    assert_eq!(indexed.num_objects, 4);
    assert_eq!(indexed.pack_id, outcome.pack_id);

    // Byte-exactness is asserted against what the *repository* holds, read back out of
    // the pack by gix's own object database.
    let mut expected = Vec::new();
    for id in &ids {
        expected.clear();
        let from_repo = {
            use gix_object::Find;
            repo.objects
                .try_find(id, &mut expected)
                .map_err(|err| anyhow::anyhow!("{err}"))?
                .map(|data| (data.kind, data.data.to_vec()))
                .expect("the repository has it")
        };
        let from_pack =
            read_from_pack_dir(&dir.objects_dir(), Kind::Sha1, id).expect("the pack has it");
        assert_eq!(
            from_pack, from_repo,
            "object {id} must survive the pack byte-exact"
        );
    }

    Ok(())
}