Something went wrong. Try again.
STreaming ARchive format: simpler, stricter, smaller than CARs for a subset of use-cases. forked from microcosm.blue/star
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226#[cfg(test)]mod tests { use crate::parser::StarParser; use crate::ser::{StarEncoder, StarSerializer}; use crate::types::{ RepoMstEntry, RepoMstNode, StarCommit, StarItem, StarMstEntry, StarMstNode, }; use cid::Cid; use serde_bytes::ByteBuf; use sha2::{Digest, Sha256};
fn create_test_cid(data: &[u8]) -> Cid { let hash = Sha256::digest(data); Cid::new_v1(0x71, cid::multihash::Multihash::wrap(0x12, &hash).unwrap()) }
#[test] fn test_roundtrip_basic() { // 1. Create a dummy record // Use "bar" (sha256 starts with fc... -> 0 leading zeros -> height 0) let record_data = b"hello world"; let record_cid = create_test_cid(record_data); let key = b"bar".to_vec();
// 2. Create a dummy MST Node (Layer 0, implicit record) let node_entry = StarMstEntry { p: 0, k: ByteBuf::from(key.clone()), v: None, v_archived: Some(true), t: None, t_archived: None, };
let star_node = StarMstNode { l: None, l_archived: None, e: vec![node_entry], };
// 3. Manually compute the expected Node CID for verification let repo_entry = RepoMstEntry { p: 0, k: ByteBuf::from(key.clone()), v: record_cid, t: None, }; let repo_node = RepoMstNode { l: None, e: vec![repo_entry], }; let repo_bytes = serde_ipld_dagcbor::to_vec(&repo_node).unwrap(); let node_cid = create_test_cid(&repo_bytes);
// 4. Create Commit let commit = StarCommit { did: "did:example:test".into(), version: 3, data: Some(node_cid), rev: "rev1".into(), prev: None, sig: None, };
// 5. Serialize to Buffer let mut buf = Vec::new(); StarEncoder::write_header(&commit, &mut buf).unwrap(); StarEncoder::write_node(&star_node, &mut buf).unwrap(); StarEncoder::write_record(record_data, &mut buf).unwrap();
// 6. Deserialize and Verify let mut parser = StarParser::new();
// Helper to mimic Decoder loop for tests fn parse_helper( parser: &mut StarParser, buf: &mut Vec<u8>, offset: &mut usize, ) -> Option<StarItem> { let (consumed, item) = parser.parse(&buf[*offset..]).unwrap(); *offset += consumed; item }
let mut offset = 0;
// Header let item1 = parse_helper(&mut parser, &mut buf, &mut offset).unwrap(); match item1 { StarItem::Commit(c) => assert_eq!(c, commit), _ => panic!("Expected commit"), }
// Node let item2 = parse_helper(&mut parser, &mut buf, &mut offset).unwrap(); match item2 { StarItem::Node(n) => { assert_eq!(n.e[0].v, None); assert_eq!(n.e[0].v_archived, Some(true)); } _ => panic!("Expected node"), }
// Record let item3 = parse_helper(&mut parser, &mut buf, &mut offset).unwrap(); match item3 { StarItem::Record { key: k, cid, content, } => { assert_eq!(k, key); assert_eq!(cid, record_cid); assert_eq!(content.unwrap(), record_data); } _ => panic!("Expected record"), }
// Done assert!(parse_helper(&mut parser, &mut buf, &mut offset).is_none()); }
#[test] fn test_verification_failure() { // 1. Create a dummy record let record_data = b"hello world"; let key = b"bar".to_vec(); // Height 0
// 2. Create STAR Node let node_entry = StarMstEntry { p: 0, k: ByteBuf::from(key.clone()), v: None, v_archived: Some(true), t: None, t_archived: None, }; let star_node = StarMstNode { l: None, l_archived: None, e: vec![node_entry], };
// 3. Create Commit with WRONG CID let wrong_cid = create_test_cid(b"garbage"); let commit = StarCommit { did: "did:example:test".into(), version: 3, data: Some(wrong_cid), rev: "rev1".into(), prev: None, sig: None, };
// 4. Serialize let mut buf = Vec::new(); StarEncoder::write_header(&commit, &mut buf).unwrap(); StarEncoder::write_node(&star_node, &mut buf).unwrap(); StarEncoder::write_record(record_data, &mut buf).unwrap();
// 5. Parse let mut parser = StarParser::new(); let mut offset = 0;
fn parse_helper( parser: &mut StarParser, buf: &mut Vec<u8>, offset: &mut usize, ) -> Result<Option<StarItem>, crate::error::StarError> { let (consumed, item) = parser.parse(&buf[*offset..])?; *offset += consumed; Ok(item) }
parse_helper(&mut parser, &mut buf, &mut offset).unwrap(); // Header OK parse_helper(&mut parser, &mut buf, &mut offset).unwrap(); // Node OK parse_helper(&mut parser, &mut buf, &mut offset).unwrap(); // Record OK
// 6. Trigger verification let result = parse_helper(&mut parser, &mut buf, &mut offset);
assert!(result.is_err()); match result.unwrap_err() { crate::error::StarError::VerificationFailed { .. } => {} e => panic!("Expected VerificationFailed, got {:?}", e), } }
#[test] fn test_strict_serializer() { // Test that strict serializer enforces constraints let mut buf = Vec::new(); let mut serializer = StarSerializer::new(&mut buf);
// 1. Create invalid node (root empty) let invalid_node = StarMstNode { l: None, l_archived: None, e: vec![], };
// 2. Commit pointing to root let cid = create_test_cid(b"foo"); let commit = StarCommit { did: "did".into(), version: 3, data: Some(cid), rev: "1".into(), prev: None, sig: None, };
// Header OK serializer.write_header(&commit).unwrap();
// Node Fail let err = serializer.write_node(&invalid_node).unwrap_err(); match err { crate::error::StarError::InvalidStructure(msg) => { assert!(msg.contains("Root cannot be empty"), "Got message: {}", msg); } e => panic!("Expected InvalidStructure, got {:?}", e), } }}