Streaming Tree ARchive format
at rust-impl 225 lines 6.9 kB view raw
1#[cfg(test)] 2mod tests { 3 use crate::parser::StarParser; 4 use crate::ser::{StarEncoder, StarSerializer}; 5 use crate::types::{ 6 RepoMstEntry, RepoMstNode, StarCommit, StarItem, StarMstEntry, StarMstNode, 7 }; 8 use cid::Cid; 9 use serde_bytes::ByteBuf; 10 use sha2::{Digest, Sha256}; 11 12 fn create_test_cid(data: &[u8]) -> Cid { 13 let hash = Sha256::digest(data); 14 Cid::new_v1(0x71, cid::multihash::Multihash::wrap(0x12, &hash).unwrap()) 15 } 16 17 #[test] 18 fn test_roundtrip_basic() { 19 // 1. Create a dummy record 20 // Use "bar" (sha256 starts with fc... -> 0 leading zeros -> height 0) 21 let record_data = b"hello world"; 22 let record_cid = create_test_cid(record_data); 23 let key = b"bar".to_vec(); 24 25 // 2. Create a dummy MST Node (Layer 0, implicit record) 26 let node_entry = StarMstEntry { 27 p: 0, 28 k: ByteBuf::from(key.clone()), 29 v: None, 30 v_archived: Some(true), 31 t: None, 32 t_archived: None, 33 }; 34 35 let star_node = StarMstNode { 36 l: None, 37 l_archived: None, 38 e: vec![node_entry], 39 }; 40 41 // 3. Manually compute the expected Node CID for verification 42 let repo_entry = RepoMstEntry { 43 p: 0, 44 k: ByteBuf::from(key.clone()), 45 v: record_cid, 46 t: None, 47 }; 48 let repo_node = RepoMstNode { 49 l: None, 50 e: vec![repo_entry], 51 }; 52 let repo_bytes = serde_ipld_dagcbor::to_vec(&repo_node).unwrap(); 53 let node_cid = create_test_cid(&repo_bytes); 54 55 // 4. Create Commit 56 let commit = StarCommit { 57 did: "did:example:test".into(), 58 version: 3, 59 data: Some(node_cid), 60 rev: "rev1".into(), 61 prev: None, 62 sig: None, 63 }; 64 65 // 5. Serialize to Buffer 66 let mut buf = Vec::new(); 67 StarEncoder::write_header(&commit, &mut buf).unwrap(); 68 StarEncoder::write_node(&star_node, &mut buf).unwrap(); 69 StarEncoder::write_record(record_data, &mut buf).unwrap(); 70 71 // 6. Deserialize and Verify 72 let mut parser = StarParser::new(); 73 74 // Helper to mimic Decoder loop for tests 75 fn parse_helper( 76 parser: &mut StarParser, 77 buf: &mut Vec<u8>, 78 offset: &mut usize, 79 ) -> Option<StarItem> { 80 let (consumed, item) = parser.parse(&buf[*offset..]).unwrap(); 81 *offset += consumed; 82 item 83 } 84 85 let mut offset = 0; 86 87 // Header 88 let item1 = parse_helper(&mut parser, &mut buf, &mut offset).unwrap(); 89 match item1 { 90 StarItem::Commit(c) => assert_eq!(c, commit), 91 _ => panic!("Expected commit"), 92 } 93 94 // Node 95 let item2 = parse_helper(&mut parser, &mut buf, &mut offset).unwrap(); 96 match item2 { 97 StarItem::Node(n) => { 98 assert_eq!(n.e[0].v, None); 99 assert_eq!(n.e[0].v_archived, Some(true)); 100 } 101 _ => panic!("Expected node"), 102 } 103 104 // Record 105 let item3 = parse_helper(&mut parser, &mut buf, &mut offset).unwrap(); 106 match item3 { 107 StarItem::Record { 108 key: k, 109 cid, 110 content, 111 } => { 112 assert_eq!(k, key); 113 assert_eq!(cid, record_cid); 114 assert_eq!(content.unwrap(), record_data); 115 } 116 _ => panic!("Expected record"), 117 } 118 119 // Done 120 assert!(parse_helper(&mut parser, &mut buf, &mut offset).is_none()); 121 } 122 123 #[test] 124 fn test_verification_failure() { 125 // 1. Create a dummy record 126 let record_data = b"hello world"; 127 let key = b"bar".to_vec(); // Height 0 128 129 // 2. Create STAR Node 130 let node_entry = StarMstEntry { 131 p: 0, 132 k: ByteBuf::from(key.clone()), 133 v: None, 134 v_archived: Some(true), 135 t: None, 136 t_archived: None, 137 }; 138 let star_node = StarMstNode { 139 l: None, 140 l_archived: None, 141 e: vec![node_entry], 142 }; 143 144 // 3. Create Commit with WRONG CID 145 let wrong_cid = create_test_cid(b"garbage"); 146 let commit = StarCommit { 147 did: "did:example:test".into(), 148 version: 3, 149 data: Some(wrong_cid), 150 rev: "rev1".into(), 151 prev: None, 152 sig: None, 153 }; 154 155 // 4. Serialize 156 let mut buf = Vec::new(); 157 StarEncoder::write_header(&commit, &mut buf).unwrap(); 158 StarEncoder::write_node(&star_node, &mut buf).unwrap(); 159 StarEncoder::write_record(record_data, &mut buf).unwrap(); 160 161 // 5. Parse 162 let mut parser = StarParser::new(); 163 let mut offset = 0; 164 165 fn parse_helper( 166 parser: &mut StarParser, 167 buf: &mut Vec<u8>, 168 offset: &mut usize, 169 ) -> Result<Option<StarItem>, crate::error::StarError> { 170 let (consumed, item) = parser.parse(&buf[*offset..])?; 171 *offset += consumed; 172 Ok(item) 173 } 174 175 parse_helper(&mut parser, &mut buf, &mut offset).unwrap(); // Header OK 176 parse_helper(&mut parser, &mut buf, &mut offset).unwrap(); // Node OK 177 parse_helper(&mut parser, &mut buf, &mut offset).unwrap(); // Record OK 178 179 // 6. Trigger verification 180 let result = parse_helper(&mut parser, &mut buf, &mut offset); 181 182 assert!(result.is_err()); 183 match result.unwrap_err() { 184 crate::error::StarError::VerificationFailed { .. } => {} 185 e => panic!("Expected VerificationFailed, got {:?}", e), 186 } 187 } 188 189 #[test] 190 fn test_strict_serializer() { 191 // Test that strict serializer enforces constraints 192 let mut buf = Vec::new(); 193 let mut serializer = StarSerializer::new(&mut buf); 194 195 // 1. Create invalid node (root empty) 196 let invalid_node = StarMstNode { 197 l: None, 198 l_archived: None, 199 e: vec![], 200 }; 201 202 // 2. Commit pointing to root 203 let cid = create_test_cid(b"foo"); 204 let commit = StarCommit { 205 did: "did".into(), 206 version: 3, 207 data: Some(cid), 208 rev: "1".into(), 209 prev: None, 210 sig: None, 211 }; 212 213 // Header OK 214 serializer.write_header(&commit).unwrap(); 215 216 // Node Fail 217 let err = serializer.write_node(&invalid_node).unwrap_err(); 218 match err { 219 crate::error::StarError::InvalidStructure(msg) => { 220 assert!(msg.contains("Root cannot be empty"), "Got message: {}", msg); 221 } 222 e => panic!("Expected InvalidStructure, got {:?}", e), 223 } 224 } 225}