libvctrl_handler 5.2.0

Fundamental contracts for building a version control system – no implementations, only traits and types
Documentation
#![allow(missing_docs)]
#![allow(clippy::unwrap_used)]
#![allow(clippy::expect_used)]
use criterion as _;

use core::error::Error as _;
use libvctrl_handler::*;

fn make_hash(byte: u8) -> Hash {
    Hash::from_bytes(&[byte; HASH_LENGTH]).unwrap()
}

#[test]
fn from_bytes_valid_length() {
    let hash = make_hash(0xAA);
    assert_eq!(hash.as_bytes(), &[0xAA; HASH_LENGTH]);
}

#[test]
fn from_bytes_too_short() {
    let err = Hash::from_bytes(&[0; 10]).unwrap_err();
    assert_eq!(err, VctrlError::InvalidHashLength(10));
}

#[test]
fn from_bytes_too_long() {
    let err = Hash::from_bytes(&[0; 100]).unwrap_err();
    assert_eq!(err, VctrlError::InvalidHashLength(100));
}

#[test]
fn as_bytes_matches_input() {
    let hash = make_hash(0x11);
    assert_eq!(hash.as_bytes(), &[0x11; HASH_LENGTH]);
}

#[test]
fn display_is_full_hex() {
    let hash = make_hash(0xAB);
    let s = hash.to_string();
    assert_eq!(s.len(), HASH_LENGTH * 2);
    assert!(s.chars().all(|c| c.is_ascii_hexdigit()));
}

#[test]
fn debug_format_contains_short_hex_and_ellipsis() {
    let hash = make_hash(0xCD);
    let dbg = format!("{hash:?}");
    assert!(dbg.starts_with("Hash("));
    assert!(dbg.ends_with("...)"), "debug format was: {dbg}");
    assert!(dbg.contains("cdcd"));
}

#[test]
fn hash_is_copy_and_clone() {
    let h1 = make_hash(1);
    let h2 = h1;
    let _ = h2;
    assert_eq!(h1, h2);
}

#[test]
fn hash_partial_eq_and_eq() {
    let a = make_hash(5);
    let b = make_hash(5);
    let c = make_hash(6);
    assert_eq!(a, b);
    assert_ne!(a, c);
}

#[test]
fn hash_ord_and_sort() {
    let low = make_hash(0);
    let high = make_hash(1);
    assert!(low < high);
    let mut v = vec![high, low];
    v.sort();
    assert_eq!(v, vec![low, high]);
}

#[test]
fn hash_std_hash_usable_in_hashset() {
    use std::collections::HashSet;
    let a = make_hash(10);
    let b = make_hash(10);
    let mut set = HashSet::new();
    assert!(set.insert(a));
    assert!(!set.insert(b));
    assert!(set.contains(&a));
}

#[test]
fn vctrl_error_display_includes_message() {
    let e = VctrlError::InvalidName("test-name".into());
    let msg = e.to_string();
    assert!(msg.contains("Invalid name"));
    assert!(msg.contains("test-name"));
}

#[test]
fn vctrl_error_debug_and_clone() {
    let e = VctrlError::ObjectNotFound(make_hash(0xFF));
    let cloned = e.clone();
    assert_eq!(e, cloned);
    let dbg = format!("{cloned:?}");
    assert!(dbg.contains("ObjectNotFound"));
}

#[test]
fn vctrl_error_is_std_error_and_source_none() {
    let e = VctrlError::Other("oops".into());
    assert!(e.source().is_none());
}

#[test]
fn vctrl_error_from_io_wraps_error() {
    let io_err = std::io::Error::new(std::io::ErrorKind::BrokenPipe, "pipe broke");
    let vctrl_err = VctrlError::from_io(io_err);
    let display = vctrl_err.to_string();
    assert!(display.contains("I/O error"));
    assert!(display.contains("pipe broke"));
}

#[test]
fn constants_have_expected_values() {
    assert_eq!(HASH_LENGTH, 64);
    assert_eq!(MAX_NAME_LENGTH, 255);
    assert_eq!(MAX_PARENT_COUNT, 65535);
}