prikk-store 0.24.0

Prikk storage crate scaffold.
Documentation
use prikk_object::{NodeId, NodeKind, ObjectId};

use super::super::{StateRootContent, compute_state_root, state_leaf_preimage};
use super::vectors::{binary_entry, symlink_entry, text_entry};
use crate::path::RepoPath;

#[test]
fn rejects_noncanonical_order_collisions_and_duplicate_node_ids() -> prikk_error::Result<()> {
    let mut reversed = vec![binary_entry()?, text_entry()?];
    assert!(compute_state_root(&reversed).is_err());

    let [first, second] = reversed.as_mut_slice() else {
        unreachable!("fixture has exactly two entries");
    };
    first.path = RepoPath::parse("A.txt")?;
    second.path = RepoPath::parse("a.txt")?;
    assert!(compute_state_root(&reversed).is_err());

    let mut duplicate_node = vec![text_entry()?, binary_entry()?];
    let [first, second] = duplicate_node.as_mut_slice() else {
        unreachable!("fixture has exactly two entries");
    };
    second.node_id = first.node_id;
    assert!(compute_state_root(&duplicate_node).is_err());
    Ok(())
}

#[test]
fn rejects_zero_node_kind_content_and_mode_disagreement() -> prikk_error::Result<()> {
    let mut entry = text_entry()?;
    entry.node_id = NodeId::from_bytes([0; 32]);
    assert!(state_leaf_preimage(&entry).is_err());

    let mut entry = text_entry()?;
    entry.mode = 0o100600;
    assert!(state_leaf_preimage(&entry).is_err());

    let mut entry = text_entry()?;
    entry.kind = NodeKind::Symlink;
    assert!(state_leaf_preimage(&entry).is_err());

    let mut entry = symlink_entry()?;
    entry.mode = 0o100644;
    assert!(state_leaf_preimage(&entry).is_err());
    Ok(())
}

#[test]
fn opaque_utf8_symlink_targets_remain_identity_bytes() -> prikk_error::Result<()> {
    let mut empty = symlink_entry()?;
    empty.content = StateRootContent::Symlink(String::new());
    let mut control = symlink_entry()?;
    control.node_id = NodeId::from_bytes([4; 32]);
    control.path = RepoPath::parse("other-link")?;
    control.content = StateRootContent::Symlink("/tmp/../x\n".to_string());
    assert!(state_leaf_preimage(&empty)?.ends_with(&0_u64.to_be_bytes()));
    assert!(compute_state_root(&[empty, control]).is_ok());
    Ok(())
}

#[test]
fn every_committed_field_changes_the_root() -> prikk_error::Result<()> {
    let baseline = compute_state_root(&[text_entry()?])?;
    let mut variants = Vec::new();

    let mut path = text_entry()?;
    path.path = RepoPath::parse("b.txt")?;
    variants.push(path);
    let mut node = text_entry()?;
    node.node_id = NodeId::from_bytes([9; 32]);
    variants.push(node);
    let mut kind = text_entry()?;
    kind.kind = NodeKind::BinaryFile;
    variants.push(kind);
    let mut mode = text_entry()?;
    mode.mode = 0o100755;
    variants.push(mode);
    let mut content = text_entry()?;
    content.content = StateRootContent::Blob(ObjectId::from_bytes([0x44; 32]));
    variants.push(content);

    for variant in variants {
        assert_ne!(compute_state_root(&[variant])?, baseline);
    }
    Ok(())
}