diff --git a/src/serde/de_br.rs b/src/serde/de_br.rs index b5282614..b1306aa0 100644 --- a/src/serde/de_br.rs +++ b/src/serde/de_br.rs @@ -80,105 +80,109 @@ pub fn node_from_bytes_backrefs_record( } #[cfg(test)] -use hex::FromHex; - -#[test] -fn test_deserialize_with_backrefs() { - fn deserialize_check(serialization_as_hex: &str, expected_hash_as_hex: &str) { - use crate::serde::object_cache::{treehash, ObjectCache}; - let buf = Vec::from_hex(serialization_as_hex).unwrap(); - let mut allocator = Allocator::new(); - let node = node_from_bytes_backrefs(&mut allocator, &buf).unwrap(); - - let mut oc = ObjectCache::new(&allocator, treehash); - let calculated_hash = oc.get_or_calculate(&node).unwrap(); - let ch: &[u8] = calculated_hash; - let expected_hash: Vec = Vec::from_hex(expected_hash_as_hex).unwrap(); - assert_eq!(expected_hash, ch); - } +mod tests { + use super::*; + + use hex::FromHex; + + #[test] + fn test_deserialize_with_backrefs() { + fn deserialize_check(serialization_as_hex: &str, expected_hash_as_hex: &str) { + use crate::serde::object_cache::{treehash, ObjectCache}; + let buf = Vec::from_hex(serialization_as_hex).unwrap(); + let mut allocator = Allocator::new(); + let node = node_from_bytes_backrefs(&mut allocator, &buf).unwrap(); + + let mut oc = ObjectCache::new(&allocator, treehash); + let calculated_hash = oc.get_or_calculate(&node).unwrap(); + let ch: &[u8] = calculated_hash; + let expected_hash: Vec = Vec::from_hex(expected_hash_as_hex).unwrap(); + assert_eq!(expected_hash, ch); + } - // ("foobar" "foobar") - deserialize_check( - "ff86666f6f626172ff86666f6f62617280", - "9148834131750904c023598bed28db269bdb29012514579e723d63e27829bcba", - ); - deserialize_check( - "ff86666f6f626172fe01", // ("foobar" "foobar") - "9148834131750904c023598bed28db269bdb29012514579e723d63e27829bcba", - ); + // ("foobar" "foobar") + deserialize_check( + "ff86666f6f626172ff86666f6f62617280", + "9148834131750904c023598bed28db269bdb29012514579e723d63e27829bcba", + ); + deserialize_check( + "ff86666f6f626172fe01", // ("foobar" "foobar") + "9148834131750904c023598bed28db269bdb29012514579e723d63e27829bcba", + ); - // ((1 2 3 4) 1 2 3 4) - deserialize_check( - "ffff01ff02ff03ff0480ff01ff02ff03ff0480", - "028c16eb4fec600e6153d8dde60eb3916d13d0dc446b5cd7936a1248f8963bf8", - ); - deserialize_check( - "ffff01ff02ff03ff0480fe02", // ((1 2 3 4) 1 2 3 4) - "028c16eb4fec600e6153d8dde60eb3916d13d0dc446b5cd7936a1248f8963bf8", - ); + // ((1 2 3 4) 1 2 3 4) + deserialize_check( + "ffff01ff02ff03ff0480ff01ff02ff03ff0480", + "028c16eb4fec600e6153d8dde60eb3916d13d0dc446b5cd7936a1248f8963bf8", + ); + deserialize_check( + "ffff01ff02ff03ff0480fe02", // ((1 2 3 4) 1 2 3 4) + "028c16eb4fec600e6153d8dde60eb3916d13d0dc446b5cd7936a1248f8963bf8", + ); - // `(((((a_very_long_repeated_string . 1) . (2 . 3)) . ((4 . 5) . (6 . 7))) . (8 . 9)) 10 a_very_long_repeated_string)` - deserialize_check( - "ffffffffff9b615f766572795f6c6f6e675f72657065617465645f737472696e6701ff0203ffff04\ + // `(((((a_very_long_repeated_string . 1) . (2 . 3)) . ((4 . 5) . (6 . 7))) . (8 . 9)) 10 a_very_long_repeated_string)` + deserialize_check( + "ffffffffff9b615f766572795f6c6f6e675f72657065617465645f737472696e6701ff0203ffff04\ 05ff0607ff0809ff0aff9b615f766572795f6c6f6e675f72657065617465645f737472696e6780", - "e23c73777f814e8a4e2785487b272b8b22ddaded1f7cfb808b43f1148602882f", - ); - deserialize_check( + "e23c73777f814e8a4e2785487b272b8b22ddaded1f7cfb808b43f1148602882f", + ); + deserialize_check( "ffffffffff9b615f766572795f6c6f6e675f72657065617465645f737472696e6701ff0203ffff0405ff0607ff0809ff0afffe4180", "e23c73777f814e8a4e2785487b272b8b22ddaded1f7cfb808b43f1148602882f", ); -} - -#[test] -fn test_deserialize_with_backrefs_record() { - fn deserialize_check(serialization_as_hex: &str, expected_backrefs: &[&'static str]) { - use crate::serde::node_to_bytes; - let buf = Vec::from_hex(serialization_as_hex).unwrap(); - let mut allocator = Allocator::new(); - let (_node, backrefs) = node_from_bytes_backrefs_record(&mut allocator, &buf) - .expect("node_from_bytes_backrefs_records"); - println!("backrefs: {:?}", backrefs); - assert_eq!(backrefs.len(), expected_backrefs.len()); - - let expected_backrefs = - HashSet::::from_iter(expected_backrefs.iter().map(|s| s.to_string())); - let backrefs = HashSet::from_iter( - backrefs - .iter() - .map(|br| hex::encode(node_to_bytes(&allocator, *br).expect("node_to_bytes"))), - ); - - assert_eq!(backrefs, expected_backrefs); } - // ("foobar" "foobar") - // no-backrefs - deserialize_check("ff86666f6f626172ff86666f6f62617280", &[]); - // with back-refs - deserialize_check( - "ff86666f6f626172fe01", // ("foobar" "foobar") - &["ff86666f6f62617280"], - ); + #[test] + fn test_deserialize_with_backrefs_record() { + fn deserialize_check(serialization_as_hex: &str, expected_backrefs: &[&'static str]) { + use crate::serde::node_to_bytes; + let buf = Vec::from_hex(serialization_as_hex).unwrap(); + let mut allocator = Allocator::new(); + let (_node, backrefs) = node_from_bytes_backrefs_record(&mut allocator, &buf) + .expect("node_from_bytes_backrefs_records"); + println!("backrefs: {:?}", backrefs); + assert_eq!(backrefs.len(), expected_backrefs.len()); + + let expected_backrefs = + HashSet::::from_iter(expected_backrefs.iter().map(|s| s.to_string())); + let backrefs = HashSet::from_iter( + backrefs + .iter() + .map(|br| hex::encode(node_to_bytes(&allocator, *br).expect("node_to_bytes"))), + ); + + assert_eq!(backrefs, expected_backrefs); + } - // ((1 2 3 4) 1 2 3 4) - // no-backrefs - deserialize_check("ffff01ff02ff03ff0480ff01ff02ff03ff0480", &[]); - // with back-refs - deserialize_check( - "ffff01ff02ff03ff0480fe02", // ((1 2 3 4) 1 2 3 4) - &["ff01ff02ff03ff0480"], - ); + // ("foobar" "foobar") + // no-backrefs + deserialize_check("ff86666f6f626172ff86666f6f62617280", &[]); + // with back-refs + deserialize_check( + "ff86666f6f626172fe01", // ("foobar" "foobar") + &["ff86666f6f62617280"], + ); + + // ((1 2 3 4) 1 2 3 4) + // no-backrefs + deserialize_check("ffff01ff02ff03ff0480ff01ff02ff03ff0480", &[]); + // with back-refs + deserialize_check( + "ffff01ff02ff03ff0480fe02", // ((1 2 3 4) 1 2 3 4) + &["ff01ff02ff03ff0480"], + ); - // `(((((a_very_long_repeated_string . 1) . (2 . 3)) . ((4 . 5) . (6 . 7))) . (8 . 9)) 10 a_very_long_repeated_string)` - // no-backrefs - deserialize_check( - "ffffffffff9b615f766572795f6c6f6e675f72657065617465645f737472696e6701ff0203ffff04\ + // `(((((a_very_long_repeated_string . 1) . (2 . 3)) . ((4 . 5) . (6 . 7))) . (8 . 9)) 10 a_very_long_repeated_string)` + // no-backrefs + deserialize_check( + "ffffffffff9b615f766572795f6c6f6e675f72657065617465645f737472696e6701ff0203ffff04\ 05ff0607ff0809ff0aff9b615f766572795f6c6f6e675f72657065617465645f737472696e6780", - &[], - ); - // with back-refs - deserialize_check( + &[], + ); + // with back-refs + deserialize_check( "ffffffffff9b615f766572795f6c6f6e675f72657065617465645f737472696e6701ff0203ffff0405ff0607ff0809ff0afffe4180", &["9b615f766572795f6c6f6e675f72657065617465645f737472696e67"], ); + } } diff --git a/src/serde/de_tree.rs b/src/serde/de_tree.rs index 6c595bfc..d645df09 100644 --- a/src/serde/de_tree.rs +++ b/src/serde/de_tree.rs @@ -221,136 +221,136 @@ pub fn parse_triples( } #[cfg(test)] -use std::io::Cursor; +mod tests { + use super::*; -#[cfg(test)] -use hex::FromHex; - -#[cfg(test)] -fn check_parse_tree(h: &str, expected: Vec, expected_sha_tree_hex: &str) { - let b = Vec::from_hex(h).unwrap(); - println!("{:?}", b); - let mut f = Cursor::new(b); - let (p, tree_hash) = parse_triples(&mut f, false).unwrap(); - assert_eq!(p, expected); - assert_eq!(tree_hash, None); + use hex::FromHex; + use std::io::Cursor; - let b = Vec::from_hex(h).unwrap(); - let mut f = Cursor::new(b); - let (p, tree_hash) = parse_triples(&mut f, true).unwrap(); - assert_eq!(p, expected); + fn check_parse_tree(h: &str, expected: Vec, expected_sha_tree_hex: &str) { + let b = Vec::from_hex(h).unwrap(); + println!("{:?}", b); + let mut f = Cursor::new(b); + let (p, tree_hash) = parse_triples(&mut f, false).unwrap(); + assert_eq!(p, expected); + assert_eq!(tree_hash, None); - let est = Vec::from_hex(expected_sha_tree_hex).unwrap(); - assert_eq!(tree_hash.unwrap()[0].to_vec(), est); -} + let b = Vec::from_hex(h).unwrap(); + let mut f = Cursor::new(b); + let (p, tree_hash) = parse_triples(&mut f, true).unwrap(); + assert_eq!(p, expected); -#[cfg(test)] -fn check_sha_blobs(h: &str, blobs: &[&[u8]]) { - let exp_sha = Vec::from_hex(h).unwrap(); - let actual_sha = sha_blobs(blobs); - assert_eq!(exp_sha, actual_sha); -} + let est = Vec::from_hex(expected_sha_tree_hex).unwrap(); + assert_eq!(tree_hash.unwrap()[0].to_vec(), est); + } -#[test] -fn test_sha_blobs() { - check_sha_blobs( - "4bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459a", - &[&[1_u8]], - ); - check_sha_blobs( - "9dcf97a184f32623d11a73124ceb99a5709b083721e878a16d78f596718ba7b2", - &[&[1], &[1]], - ); - check_sha_blobs( - "812195e02ed84360ceafab26f9fa6072f8aa76ba34a735894c3f3c2e4fe6911d", - &[&[1, 250, 17], &[28]], - ); -} + fn check_sha_blobs(h: &str, blobs: &[&[u8]]) { + let exp_sha = Vec::from_hex(h).unwrap(); + let actual_sha = sha_blobs(blobs); + assert_eq!(exp_sha, actual_sha); + } -#[test] -fn test_parse_tree() { - check_parse_tree( - "80", - vec![ParsedTriple::Atom { - start: 0, - end: 1, - atom_offset: 1, - }], - "4bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459a", - ); + #[test] + fn test_sha_blobs() { + check_sha_blobs( + "4bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459a", + &[&[1_u8]], + ); + check_sha_blobs( + "9dcf97a184f32623d11a73124ceb99a5709b083721e878a16d78f596718ba7b2", + &[&[1], &[1]], + ); + check_sha_blobs( + "812195e02ed84360ceafab26f9fa6072f8aa76ba34a735894c3f3c2e4fe6911d", + &[&[1, 250, 17], &[28]], + ); + } - check_parse_tree( - "ff648200c8", - vec![ - ParsedTriple::Pair { + #[test] + fn test_parse_tree() { + check_parse_tree( + "80", + vec![ParsedTriple::Atom { start: 0, - end: 5, - right_index: 2, - }, - ParsedTriple::Atom { - start: 1, - end: 2, - atom_offset: 0, - }, - ParsedTriple::Atom { - start: 2, - end: 5, + end: 1, atom_offset: 1, - }, - ], - "247f7d3f63b346ea93ca47f571cd0f4455392348b888a4286072bef0ac6069b5", - ); + }], + "4bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459a", + ); - check_parse_tree( - "ff83666f6fff83626172ff8362617a80", // `(foo bar baz)` - vec![ - ParsedTriple::Pair { - start: 0, - end: 16, - right_index: 2, - }, - ParsedTriple::Atom { - start: 1, - end: 5, - atom_offset: 1, - }, - ParsedTriple::Pair { - start: 5, - end: 16, - right_index: 4, - }, - ParsedTriple::Atom { - start: 6, - end: 10, - atom_offset: 1, - }, - ParsedTriple::Pair { - start: 10, - end: 16, - right_index: 6, - }, - ParsedTriple::Atom { - start: 11, - end: 15, - atom_offset: 1, - }, - ParsedTriple::Atom { - start: 15, - end: 16, - atom_offset: 1, - }, - ], - "47f30bf9935e25e4262023124fb5e986d755b9ed65a28ac78925c933bfd57dbd", - ); + check_parse_tree( + "ff648200c8", + vec![ + ParsedTriple::Pair { + start: 0, + end: 5, + right_index: 2, + }, + ParsedTriple::Atom { + start: 1, + end: 2, + atom_offset: 0, + }, + ParsedTriple::Atom { + start: 2, + end: 5, + atom_offset: 1, + }, + ], + "247f7d3f63b346ea93ca47f571cd0f4455392348b888a4286072bef0ac6069b5", + ); + + check_parse_tree( + "ff83666f6fff83626172ff8362617a80", // `(foo bar baz)` + vec![ + ParsedTriple::Pair { + start: 0, + end: 16, + right_index: 2, + }, + ParsedTriple::Atom { + start: 1, + end: 5, + atom_offset: 1, + }, + ParsedTriple::Pair { + start: 5, + end: 16, + right_index: 4, + }, + ParsedTriple::Atom { + start: 6, + end: 10, + atom_offset: 1, + }, + ParsedTriple::Pair { + start: 10, + end: 16, + right_index: 6, + }, + ParsedTriple::Atom { + start: 11, + end: 15, + atom_offset: 1, + }, + ParsedTriple::Atom { + start: 15, + end: 16, + atom_offset: 1, + }, + ], + "47f30bf9935e25e4262023124fb5e986d755b9ed65a28ac78925c933bfd57dbd", + ); - let s = "c0a0".to_owned() + &hex::encode([0x31u8; 160]); - check_parse_tree( - &s, - vec![ParsedTriple::Atom { - start: 0, - end: 162, - atom_offset: 2, - }], - "d1c109981a9c5a3bbe2d98795a186a0f057dc9a3a7f5e1eb4dfb63a1636efa2d", - ); + let s = "c0a0".to_owned() + &hex::encode([0x31u8; 160]); + check_parse_tree( + &s, + vec![ParsedTriple::Atom { + start: 0, + end: 162, + atom_offset: 2, + }], + "d1c109981a9c5a3bbe2d98795a186a0f057dc9a3a7f5e1eb4dfb63a1636efa2d", + ); + } } diff --git a/src/serde/object_cache.rs b/src/serde/object_cache.rs index a70b5348..4df080b1 100644 --- a/src/serde/object_cache.rs +++ b/src/serde/object_cache.rs @@ -133,129 +133,124 @@ pub fn serialized_length( } #[cfg(test)] -use std::cmp::max; - -#[cfg(test)] -use std::fmt::Debug; - -#[cfg(test)] -use std::io::Cursor; - -#[cfg(test)] -use hex::FromHex; - -#[cfg(test)] -use crate::serde::de::node_from_stream; - -/// calculate the depth of a node. Used for tests - -#[cfg(test)] -fn calculate_depth_simple( - cache: &mut ObjectCache, - allocator: &Allocator, - node: NodePtr, -) -> Option { - match allocator.sexp(node) { - SExp::Pair(left, right) => match cache.get_from_cache(&left) { - None => None, - Some(left_value) => cache - .get_from_cache(&right) - .map(|right_value| 1 + max(*left_value, *right_value)), - }, - SExp::Atom => Some(0), +mod tests { + use super::*; + + use hex::FromHex; + use std::cmp::max; + use std::fmt::Debug; + use std::io::Cursor; + + use crate::serde::de::node_from_stream; + + /// calculate the depth of a node. Used for tests + fn calculate_depth_simple( + cache: &mut ObjectCache, + allocator: &Allocator, + node: NodePtr, + ) -> Option { + match allocator.sexp(node) { + SExp::Pair(left, right) => match cache.get_from_cache(&left) { + None => None, + Some(left_value) => cache + .get_from_cache(&right) + .map(|right_value| 1 + max(*left_value, *right_value)), + }, + SExp::Atom => Some(0), + } } -} -#[cfg(test)] -fn check_cached_function(obj_as_hex: &str, expected_value: T, f: CachedFunction) -where - T: Clone + Eq + Debug, -{ - let mut allocator = Allocator::new(); - let blob: Vec = Vec::from_hex(obj_as_hex).unwrap(); - let mut cursor: Cursor<&[u8]> = Cursor::new(&blob); - let obj = node_from_stream(&mut allocator, &mut cursor).unwrap(); - let mut oc = ObjectCache::new(&allocator, f); + fn check_cached_function(obj_as_hex: &str, expected_value: T, f: CachedFunction) + where + T: Clone + Eq + Debug, + { + let mut allocator = Allocator::new(); + let blob: Vec = Vec::from_hex(obj_as_hex).unwrap(); + let mut cursor: Cursor<&[u8]> = Cursor::new(&blob); + let obj = node_from_stream(&mut allocator, &mut cursor).unwrap(); + let mut oc = ObjectCache::new(&allocator, f); - assert_eq!(oc.get_from_cache(&obj), None); + assert_eq!(oc.get_from_cache(&obj), None); - oc.calculate(&obj); + oc.calculate(&obj); - assert_eq!(oc.get_from_cache(&obj), Some(&expected_value)); + assert_eq!(oc.get_from_cache(&obj), Some(&expected_value)); - assert_eq!(oc.get_or_calculate(&obj).unwrap().clone(), expected_value); + assert_eq!(oc.get_or_calculate(&obj).unwrap().clone(), expected_value); - assert_eq!(oc.get_from_cache(&obj), Some(&expected_value)); + assert_eq!(oc.get_from_cache(&obj), Some(&expected_value)); - // do it again, but the simple way - let mut oc = ObjectCache::new(&allocator, f); - assert_eq!(oc.get_or_calculate(&obj).unwrap().clone(), expected_value); -} + // do it again, but the simple way + let mut oc = ObjectCache::new(&allocator, f); + assert_eq!(oc.get_or_calculate(&obj).unwrap().clone(), expected_value); + } -#[test] -fn test_depths_cache() { - let check = |a, b| check_cached_function(a, b, calculate_depth_simple); - check("01", 0); // 1 - check("ff83666f6f83626172", 1); // (foo . bar) - check("ff83666f6fff8362617280", 2); // (foo bar) - check("ffff0102ff0304", 2); // ((1 . 2) . (3 . 4)) - check("ff01ff02ff03ff04ff05ff0680", 6); // (1 2 3 4 5 6) -} + #[test] + fn test_depths_cache() { + let check = |a, b| check_cached_function(a, b, calculate_depth_simple); + check("01", 0); // 1 + check("ff83666f6f83626172", 1); // (foo . bar) + check("ff83666f6fff8362617280", 2); // (foo bar) + check("ffff0102ff0304", 2); // ((1 . 2) . (3 . 4)) + check("ff01ff02ff03ff04ff05ff0680", 6); // (1 2 3 4 5 6) + } -#[test] -fn test_treehash() { - let check = |a, b| check_cached_function(a, Bytes32::from_hex(b).unwrap(), treehash); - check( - "ff83666f6f83626172", - "c518e45ae6a7b4146017b7a1d81639051b132f1f5572ce3088a3898a9ed1280b", - ); // (foo . bar) - check( - "ff83666f6fff8362617280", - "c97d97cc81100a4980080ba81ff1ba3985f7cff1db9d41d904b9d512bb875144", - ); // (foo bar) - check( - "ffff0102ff0304", - "2824018d148bc6aed0847e2c86aaa8a5407b916169f15b12cea31fa932fc4c8d", - ); // ((1 . 2) . (3 . 4)) - check( - "ff01ff02ff03ff04ff05ff0680", - "65de5098d18bebd62aee37de32f0b62d1803d9c7c48f10dca25501243d7a0392", - ); // (1 2 3 4 5 6) -} + #[test] + fn test_treehash() { + let check = |a, b| check_cached_function(a, Bytes32::from_hex(b).unwrap(), treehash); + check( + "ff83666f6f83626172", + "c518e45ae6a7b4146017b7a1d81639051b132f1f5572ce3088a3898a9ed1280b", + ); // (foo . bar) + check( + "ff83666f6fff8362617280", + "c97d97cc81100a4980080ba81ff1ba3985f7cff1db9d41d904b9d512bb875144", + ); // (foo bar) + check( + "ffff0102ff0304", + "2824018d148bc6aed0847e2c86aaa8a5407b916169f15b12cea31fa932fc4c8d", + ); // ((1 . 2) . (3 . 4)) + check( + "ff01ff02ff03ff04ff05ff0680", + "65de5098d18bebd62aee37de32f0b62d1803d9c7c48f10dca25501243d7a0392", + ); // (1 2 3 4 5 6) + } -#[test] -fn test_serialized_length() { - let check = |a, b| check_cached_function(a, b, serialized_length); - check("ff83666f6f83626172", 9); // (foo . bar) - check("ff83666f6fff8362617280", 11); // (foo bar) - check("ffff0102ff0304", 7); // ((1 . 2) . (3 . 4)) - check("ff01ff02ff03ff04ff05ff0680", 13); // (1 2 3 4 5 6) -} + #[test] + fn test_serialized_length() { + let check = |a, b| check_cached_function(a, b, serialized_length); + check("ff83666f6f83626172", 9); // (foo . bar) + check("ff83666f6fff8362617280", 11); // (foo bar) + check("ffff0102ff0304", 7); // ((1 . 2) . (3 . 4)) + check("ff01ff02ff03ff04ff05ff0680", 13); // (1 2 3 4 5 6) + } -// this test takes a very long time (>60s) in debug mode, so it only runs in release mode + // this test takes a very long time (>60s) in debug mode, so it only runs in release mode + + #[cfg(not(debug_assertions))] + #[test] + fn test_very_long_list() { + // in this test, we check that `treehash` and `serialized_length` can handle very deep trees that + // would normally blow out the stack. It's expensive to create such a long list, so we do both + // tests here so we only have to to create the list once + + const LIST_SIZE: u64 = 20_000_000; + let mut allocator = Allocator::new(); + let mut top = allocator.nil(); + for _ in 0..LIST_SIZE { + let atom = allocator.one(); + top = allocator.new_pair(atom, top).unwrap(); + } -#[cfg(not(debug_assertions))] -#[test] -fn test_very_long_list() { - // in this test, we check that `treehash` and `serialized_length` can handle very deep trees that - // would normally blow out the stack. It's expensive to create such a long list, so we do both - // tests here so we only have to to create the list once + let expected_value = LIST_SIZE * 2 + 1; + let mut oc = ObjectCache::new(&allocator, serialized_length); + assert_eq!(oc.get_or_calculate(&top).unwrap().clone(), expected_value); - const LIST_SIZE: u64 = 20_000_000; - let mut allocator = Allocator::new(); - let mut top = allocator.nil(); - for _ in 0..LIST_SIZE { - let atom = allocator.one(); - top = allocator.new_pair(atom, top).unwrap(); + let expected_value = <[u8; 32]>::from_hex( + "a168fce695099a30c0745075e6db3722ed7f059e0d7cc4d7e7504e215db5017b", + ) + .unwrap(); + let mut oc = ObjectCache::new(&allocator, treehash); + assert_eq!(oc.get_or_calculate(&top).unwrap().clone(), expected_value); } - - let expected_value = LIST_SIZE * 2 + 1; - let mut oc = ObjectCache::new(&allocator, serialized_length); - assert_eq!(oc.get_or_calculate(&top).unwrap().clone(), expected_value); - - let expected_value = - <[u8; 32]>::from_hex("a168fce695099a30c0745075e6db3722ed7f059e0d7cc4d7e7504e215db5017b") - .unwrap(); - let mut oc = ObjectCache::new(&allocator, treehash); - assert_eq!(oc.get_or_calculate(&top).unwrap().clone(), expected_value); } diff --git a/src/serde/parse_atom.rs b/src/serde/parse_atom.rs index 5bdd866a..ce5c5990 100644 --- a/src/serde/parse_atom.rs +++ b/src/serde/parse_atom.rs @@ -52,7 +52,6 @@ pub fn decode_size(f: &mut R, initial_b: u8) -> Result { /// parse an atom from the stream and return a pointer to it /// the first byte has already been read - fn parse_atom_ptr<'a>(f: &'a mut Cursor<&[u8]>, first_byte: u8) -> Result<&'a [u8]> { let blob = if first_byte <= MAX_SINGLE_BYTE { let pos = f.position() as usize; @@ -73,7 +72,6 @@ fn parse_atom_ptr<'a>(f: &'a mut Cursor<&[u8]>, first_byte: u8) -> Result<&'a [u /// At this point, the first byte has already been read to ensure it's /// not a special code like `CONS_BOX_MARKER` = 0xff, so it must be /// passed in too - pub fn parse_atom( allocator: &mut Allocator, first_byte: u8, @@ -90,7 +88,6 @@ pub fn parse_atom( } /// parse an atom from the stream and return a pointer to it - pub fn parse_path<'a>(f: &'a mut Cursor<&[u8]>) -> Result<&'a [u8]> { let mut buf1: [u8; 1] = [0]; f.read_exact(&mut buf1)?; @@ -98,131 +95,132 @@ pub fn parse_path<'a>(f: &'a mut Cursor<&[u8]>) -> Result<&'a [u8]> { } #[cfg(test)] -use std::io::ErrorKind; - -#[cfg(test)] -use super::write_atom::write_atom; - -#[test] -fn test_decode_size() { - // single-byte length prefix - let mut buffer = Cursor::new(&[]); - assert_eq!( - decode_size_with_offset(&mut buffer, 0x80 | 0x20).unwrap(), - (1, 0x20) - ); - - // two-byte length prefix - let first = 0b11001111; - let mut buffer = Cursor::new(&[0xaa]); - assert_eq!( - decode_size_with_offset(&mut buffer, first).unwrap(), - (2, 0xfaa) - ); -} - -#[test] -fn test_large_decode_size() { - // this is an atom length-prefix 0xffffffffffff, or (2^48 - 1). - // We don't support atoms this large and we should fail before attempting to - // allocate this much memory - let first = 0b11111110; - let mut buffer = Cursor::new(&[0xff, 0xff, 0xff, 0xff, 0xff, 0xff]); - let ret = decode_size_with_offset(&mut buffer, first); - let e = ret.unwrap_err(); - assert_eq!(e.kind(), bad_encoding().kind()); - assert_eq!(e.to_string(), "bad encoding"); - - // this is still too large - let first = 0b11111100; - let mut buffer = Cursor::new(&[0x4, 0, 0, 0, 0]); - let ret = decode_size_with_offset(&mut buffer, first); - let e = ret.unwrap_err(); - assert_eq!(e.kind(), bad_encoding().kind()); - assert_eq!(e.to_string(), "bad encoding"); - - // But this is *just* within what we support - // Still a very large blob, probably enough for a DoS attack - let first = 0b11111100; - let mut buffer = Cursor::new(&[0x3, 0xff, 0xff, 0xff, 0xff]); - assert_eq!( - decode_size_with_offset(&mut buffer, first).unwrap(), - (6, 0x3ffffffff) - ); - - // this ensures a fuzzer-found bug doesn't reoccur - let mut buffer = Cursor::new(&[0xff, 0xfe]); - let ret = decode_size_with_offset(&mut buffer, first); - let e = ret.unwrap_err(); - assert_eq!(e.kind(), ErrorKind::UnexpectedEof); - assert_eq!(e.to_string(), "failed to fill whole buffer"); -} +mod tests { + use crate::serde::write_atom::write_atom; + + use super::*; + + use std::io::ErrorKind; + + #[test] + fn test_decode_size() { + // single-byte length prefix + let mut buffer = Cursor::new(&[]); + assert_eq!( + decode_size_with_offset(&mut buffer, 0x80 | 0x20).unwrap(), + (1, 0x20) + ); + + // two-byte length prefix + let first = 0b11001111; + let mut buffer = Cursor::new(&[0xaa]); + assert_eq!( + decode_size_with_offset(&mut buffer, first).unwrap(), + (2, 0xfaa) + ); + } -#[test] -fn test_truncated_decode_size() { - // the stream is truncated - let first = 0b11111100; - let mut cursor = Cursor::new(&[0x4, 0, 0, 0]); - let ret = decode_size_with_offset(&mut cursor, first); - let e = ret.unwrap_err(); - assert_eq!(e.kind(), ErrorKind::UnexpectedEof); -} + #[test] + fn test_large_decode_size() { + // this is an atom length-prefix 0xffffffffffff, or (2^48 - 1). + // We don't support atoms this large and we should fail before attempting to + // allocate this much memory + let first = 0b11111110; + let mut buffer = Cursor::new(&[0xff, 0xff, 0xff, 0xff, 0xff, 0xff]); + let ret = decode_size_with_offset(&mut buffer, first); + let e = ret.unwrap_err(); + assert_eq!(e.kind(), bad_encoding().kind()); + assert_eq!(e.to_string(), "bad encoding"); + + // this is still too large + let first = 0b11111100; + let mut buffer = Cursor::new(&[0x4, 0, 0, 0, 0]); + let ret = decode_size_with_offset(&mut buffer, first); + let e = ret.unwrap_err(); + assert_eq!(e.kind(), bad_encoding().kind()); + assert_eq!(e.to_string(), "bad encoding"); + + // But this is *just* within what we support + // Still a very large blob, probably enough for a DoS attack + let first = 0b11111100; + let mut buffer = Cursor::new(&[0x3, 0xff, 0xff, 0xff, 0xff]); + assert_eq!( + decode_size_with_offset(&mut buffer, first).unwrap(), + (6, 0x3ffffffff) + ); + + // this ensures a fuzzer-found bug doesn't reoccur + let mut buffer = Cursor::new(&[0xff, 0xfe]); + let ret = decode_size_with_offset(&mut buffer, first); + let e = ret.unwrap_err(); + assert_eq!(e.kind(), ErrorKind::UnexpectedEof); + assert_eq!(e.to_string(), "failed to fill whole buffer"); + } -#[cfg(test)] -fn check_parse_atom(blob: &[u8], expected_atom: &[u8]) { - let mut cursor = Cursor::<&[u8]>::new(blob); - let mut first: [u8; 1] = [0]; - cursor.read_exact(&mut first).unwrap(); - let first = first[0]; + #[test] + fn test_truncated_decode_size() { + // the stream is truncated + let first = 0b11111100; + let mut cursor = Cursor::new(&[0x4, 0, 0, 0]); + let ret = decode_size_with_offset(&mut cursor, first); + let e = ret.unwrap_err(); + assert_eq!(e.kind(), ErrorKind::UnexpectedEof); + } - let mut allocator = Allocator::new(); - let atom_node = parse_atom(&mut allocator, first, &mut cursor).unwrap(); + fn check_parse_atom(blob: &[u8], expected_atom: &[u8]) { + let mut cursor = Cursor::<&[u8]>::new(blob); + let mut first: [u8; 1] = [0]; + cursor.read_exact(&mut first).unwrap(); + let first = first[0]; - let atom = allocator.atom(atom_node); + let mut allocator = Allocator::new(); + let atom_node = parse_atom(&mut allocator, first, &mut cursor).unwrap(); - assert_eq!(expected_atom, atom.as_ref()); -} + let atom = allocator.atom(atom_node); -#[cfg(test)] -fn check_parse_atom_str(blob_hex: &str, expected_atom_hex: &str) { - let blob = hex::decode(blob_hex).unwrap(); - let expected_atom: &[u8] = &hex::decode(expected_atom_hex).unwrap(); - check_parse_atom(&blob, expected_atom); -} + assert_eq!(expected_atom, atom.as_ref()); + } -#[test] -fn test_parse_atom() { - check_parse_atom_str("80", ""); - // try "00", "01", "02", ..., "7f" - for idx in 0..128 { - check_parse_atom(&[idx], &[idx]); + fn check_parse_atom_str(blob_hex: &str, expected_atom_hex: &str) { + let blob = hex::decode(blob_hex).unwrap(); + let expected_atom: &[u8] = &hex::decode(expected_atom_hex).unwrap(); + check_parse_atom(&blob, expected_atom); } - // check a short atom - check_parse_atom_str("83666f6f", "666f6f"); - - // check long atoms near boundary conditions - let n = 3; - let base_lengths = [0, 0x40 - n, 0x2000 - n, 0x100000 - n, 0x08000000 - n]; - let mut atom_vec = vec![]; - for base_length in base_lengths.iter() { - for size_offset in 0..6 { - let size = base_length + size_offset; - atom_vec.resize(size, 0x66); - let mut buffer: Vec = vec![]; - let mut cursor = Cursor::new(&mut buffer); - write_atom(&mut cursor, &atom_vec).unwrap(); + #[test] + fn test_parse_atom() { + check_parse_atom_str("80", ""); + // try "00", "01", "02", ..., "7f" + for idx in 0..128 { + check_parse_atom(&[idx], &[idx]); + } + + // check a short atom + check_parse_atom_str("83666f6f", "666f6f"); + + // check long atoms near boundary conditions + let n = 3; + let base_lengths = [0, 0x40 - n, 0x2000 - n, 0x100000 - n, 0x08000000 - n]; + let mut atom_vec = vec![]; + for base_length in base_lengths.iter() { + for size_offset in 0..6 { + let size = base_length + size_offset; + atom_vec.resize(size, 0x66); + let mut buffer: Vec = vec![]; + let mut cursor = Cursor::new(&mut buffer); + write_atom(&mut cursor, &atom_vec).unwrap(); + } } } -} -#[test] -fn test_truncated_parse_atom() { - // the stream is truncated - let first = 0b11111100; - let mut cursor = Cursor::<&[u8]>::new(&[0x4, 0, 0, 0]); - let mut allocator = Allocator::new(); - let ret = parse_atom(&mut allocator, first, &mut cursor); - let err = ret.unwrap_err(); - assert_eq!(err.kind(), ErrorKind::UnexpectedEof); + #[test] + fn test_truncated_parse_atom() { + // the stream is truncated + let first = 0b11111100; + let mut cursor = Cursor::<&[u8]>::new(&[0x4, 0, 0, 0]); + let mut allocator = Allocator::new(); + let ret = parse_atom(&mut allocator, first, &mut cursor); + let err = ret.unwrap_err(); + assert_eq!(err.kind(), ErrorKind::UnexpectedEof); + } } diff --git a/src/serde/read_cache_lookup.rs b/src/serde/read_cache_lookup.rs index 37e79261..d01e2b1d 100644 --- a/src/serde/read_cache_lookup.rs +++ b/src/serde/read_cache_lookup.rs @@ -185,7 +185,6 @@ impl ReadCacheLookup { /// If `A` => `v` then `[A] + [0]` => `v * 2` and `[A] + [1]` => `v * 2 + 1` /// Then the integer is turned into the minimal-length array of `u8` representing /// that value as an unsigned integer. - fn reversed_path_to_vec_u8(path: &[u8]) -> Vec { let byte_count = (path.len() + 1 + 7) >> 3; let mut v = vec![0; byte_count]; @@ -208,164 +207,169 @@ fn reversed_path_to_vec_u8(path: &[u8]) -> Vec { v } -#[test] -fn test_path_to_vec_u8() { - assert_eq!(reversed_path_to_vec_u8(&[]), vec!(0b1)); - assert_eq!(reversed_path_to_vec_u8(&[0]), vec!(0b10)); - assert_eq!(reversed_path_to_vec_u8(&[1]), vec!(0b11)); - assert_eq!(reversed_path_to_vec_u8(&[0, 0]), vec!(0b100)); - assert_eq!(reversed_path_to_vec_u8(&[0, 1]), vec!(0b101)); - assert_eq!(reversed_path_to_vec_u8(&[1, 0]), vec!(0b110)); - assert_eq!(reversed_path_to_vec_u8(&[1, 1]), vec!(0b111)); - assert_eq!(reversed_path_to_vec_u8(&[1, 1, 1]), vec!(0b1111)); - assert_eq!(reversed_path_to_vec_u8(&[0, 1, 1, 1]), vec!(0b10111)); - assert_eq!(reversed_path_to_vec_u8(&[1, 0, 1, 1, 1]), vec!(0b110111)); - assert_eq!( - reversed_path_to_vec_u8(&[1, 1, 0, 1, 1, 1]), - vec!(0b1110111) - ); - assert_eq!( - reversed_path_to_vec_u8(&[0, 1, 1, 0, 1, 1, 1]), - vec!(0b10110111) - ); - assert_eq!( - reversed_path_to_vec_u8(&[0, 0, 1, 1, 0, 1, 1, 1]), - vec!(0b1, 0b00110111) - ); - assert_eq!( - reversed_path_to_vec_u8(&[1, 0, 0, 1, 1, 0, 1, 1, 1]), - vec!(0b11, 0b00110111) - ); -} +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_path_to_vec_u8() { + assert_eq!(reversed_path_to_vec_u8(&[]), vec!(0b1)); + assert_eq!(reversed_path_to_vec_u8(&[0]), vec!(0b10)); + assert_eq!(reversed_path_to_vec_u8(&[1]), vec!(0b11)); + assert_eq!(reversed_path_to_vec_u8(&[0, 0]), vec!(0b100)); + assert_eq!(reversed_path_to_vec_u8(&[0, 1]), vec!(0b101)); + assert_eq!(reversed_path_to_vec_u8(&[1, 0]), vec!(0b110)); + assert_eq!(reversed_path_to_vec_u8(&[1, 1]), vec!(0b111)); + assert_eq!(reversed_path_to_vec_u8(&[1, 1, 1]), vec!(0b1111)); + assert_eq!(reversed_path_to_vec_u8(&[0, 1, 1, 1]), vec!(0b10111)); + assert_eq!(reversed_path_to_vec_u8(&[1, 0, 1, 1, 1]), vec!(0b110111)); + assert_eq!( + reversed_path_to_vec_u8(&[1, 1, 0, 1, 1, 1]), + vec!(0b1110111) + ); + assert_eq!( + reversed_path_to_vec_u8(&[0, 1, 1, 0, 1, 1, 1]), + vec!(0b10110111) + ); + assert_eq!( + reversed_path_to_vec_u8(&[0, 0, 1, 1, 0, 1, 1, 1]), + vec!(0b1, 0b00110111) + ); + assert_eq!( + reversed_path_to_vec_u8(&[1, 0, 0, 1, 1, 0, 1, 1, 1]), + vec!(0b11, 0b00110111) + ); + } -#[test] -fn test_read_cache_lookup() { - let large_max = 30; - let mut rcl = ReadCacheLookup::new(); - - // the only thing cached right now is a nil, right at the top of the tree (ie. `1`) - let hash_of_nil = hash_blob(&[1]); - assert_eq!(rcl.find_paths(&hash_of_nil, large_max), [[1]]); - - assert_eq!(rcl.count.get(&hash_of_nil).unwrap(), &1); - - // the atom `1` is not in the tree anywhere - let hash_of_1_atom = hash_blobs(&[&[1], &[1]]); - assert!(rcl.find_paths(&hash_of_1_atom, large_max).is_empty()); - - // now let's push a `5` atom to the top - // tree: `(5 . 0)` - let hash_of_5_atom = hash_blobs(&[&[1], &[5]]); - rcl.push(hash_of_5_atom); - let hash_of_cons_5_nil = hash_blobs(&[&[2], &hash_of_5_atom, &hash_of_nil]); - assert_eq!(rcl.find_paths(&hash_of_cons_5_nil, large_max), [[1]]); - assert_eq!(rcl.find_paths(&hash_of_5_atom, large_max), [[2]]); - assert_eq!(rcl.find_paths(&hash_of_nil, large_max), [[3]]); - - assert_eq!(rcl.count.get(&hash_of_cons_5_nil).unwrap(), &1); - assert_eq!(rcl.count.get(&hash_of_5_atom).unwrap(), &1); - assert_eq!(rcl.count.get(&hash_of_nil).unwrap(), &1); - - // the atom `1` is still not in the tree anywhere - assert!(rcl.find_paths(&hash_of_1_atom, large_max).is_empty()); - - // now let's push a `9` atom to the top - // tree: `(9 . (5 . 0))` - let hash_of_9_atom = hash_blobs(&[&[1], &[9]]); - rcl.push(hash_of_9_atom); - let hash_of_cons_9_cons_5_nil = hash_blobs(&[&[2], &hash_of_9_atom, &hash_of_cons_5_nil]); - - assert_eq!(rcl.find_paths(&hash_of_cons_9_cons_5_nil, large_max), [[1]]); - assert_eq!(rcl.find_paths(&hash_of_9_atom, large_max), [[2]]); - assert_eq!(rcl.find_paths(&hash_of_cons_5_nil, large_max), [[3]]); - assert_eq!(rcl.find_paths(&hash_of_5_atom, large_max), [[5]]); - assert_eq!(rcl.find_paths(&hash_of_nil, large_max), [[7]]); - - assert_eq!(rcl.count.get(&hash_of_cons_9_cons_5_nil).unwrap(), &1); - assert_eq!(rcl.count.get(&hash_of_9_atom).unwrap(), &1); - assert_eq!(rcl.count.get(&hash_of_cons_5_nil).unwrap(), &1); - assert_eq!(rcl.count.get(&hash_of_5_atom).unwrap(), &1); - assert_eq!(rcl.count.get(&hash_of_nil).unwrap(), &1); - - // the atom `1` is still not in the tree anywhere - assert!(rcl.find_paths(&hash_of_1_atom, large_max).is_empty()); - - // now let's push a `10` atom to the top - // tree: `(10 . (9 . (5 . 0)))` - - let hash_of_10_atom = hash_blobs(&[&[1], &[10]]); - rcl.push(hash_of_10_atom); - let hash_of_cons_10_cons_9_cons_5_nil = - hash_blobs(&[&[2], &hash_of_10_atom, &hash_of_cons_9_cons_5_nil]); - assert_eq!( - rcl.find_paths(&hash_of_cons_10_cons_9_cons_5_nil, large_max), - [[1]] - ); - assert_eq!(rcl.find_paths(&hash_of_10_atom, large_max), [[2]]); - assert_eq!(rcl.find_paths(&hash_of_cons_9_cons_5_nil, large_max), [[3]]); - assert_eq!(rcl.find_paths(&hash_of_9_atom, large_max), [[5]]); - assert_eq!(rcl.find_paths(&hash_of_cons_5_nil, large_max), [[7]]); - assert_eq!(rcl.find_paths(&hash_of_5_atom, large_max), [[11]]); - assert_eq!(rcl.find_paths(&hash_of_nil, large_max), [[15]]); - - assert_eq!( - rcl.count.get(&hash_of_cons_10_cons_9_cons_5_nil).unwrap(), - &1 - ); - assert_eq!(rcl.count.get(&hash_of_10_atom).unwrap(), &1); - assert_eq!(rcl.count.get(&hash_of_cons_9_cons_5_nil).unwrap(), &1); - assert_eq!(rcl.count.get(&hash_of_9_atom).unwrap(), &1); - assert_eq!(rcl.count.get(&hash_of_cons_5_nil).unwrap(), &1); - assert_eq!(rcl.count.get(&hash_of_5_atom).unwrap(), &1); - assert_eq!(rcl.count.get(&hash_of_nil).unwrap(), &1); - - // the atom `1` is still not in the tree anywhere - assert!(rcl.find_paths(&hash_of_1_atom, large_max).is_empty()); - - // now let's do a `pop2_and_cons` - // tree: `((9 . 10) . (5 . 0))` - // 2 => (9 . 10) - // 3 => (5 . 0) - // 4 => 9 - // 5 => 5 - // 6 => 10 - // 7 => 0 - rcl.pop2_and_cons(); - let hash_of_cons_9_10 = hash_blobs(&[&[2], &hash_of_9_atom, &hash_of_10_atom]); - let hash_of_cons_cons_9_10_cons_5_nil = - hash_blobs(&[&[2], &hash_of_cons_9_10, &hash_of_cons_5_nil]); - assert_eq!( - rcl.find_paths(&hash_of_cons_cons_9_10_cons_5_nil, large_max), - [[1]] - ); - assert_eq!(rcl.find_paths(&hash_of_cons_9_10, large_max), [[2]]); - assert_eq!(rcl.find_paths(&hash_of_cons_5_nil, large_max), [[3]]); - assert_eq!(rcl.find_paths(&hash_of_9_atom, large_max), [[4]]); - assert_eq!(rcl.find_paths(&hash_of_10_atom, large_max), [[6]]); - assert_eq!(rcl.find_paths(&hash_of_5_atom, large_max), [[5]]); - assert_eq!(rcl.find_paths(&hash_of_nil, large_max), [[7]]); - - // `(9 . (5 . 0))` is no longer in the tree - assert!(rcl - .find_paths(&hash_of_cons_9_cons_5_nil, large_max) - .is_empty()); - - assert_eq!( - rcl.count.get(&hash_of_cons_cons_9_10_cons_5_nil).unwrap(), - &1 - ); - assert_eq!(rcl.count.get(&hash_of_cons_9_10).unwrap(), &1); - assert_eq!(rcl.count.get(&hash_of_cons_5_nil).unwrap(), &1); - assert_eq!(rcl.count.get(&hash_of_9_atom).unwrap(), &1); - assert_eq!(rcl.count.get(&hash_of_10_atom).unwrap(), &1); - assert_eq!(rcl.count.get(&hash_of_5_atom).unwrap(), &1); - assert_eq!(rcl.count.get(&hash_of_nil).unwrap(), &1); - - // `(9 . (5 . 0))` is no longer in the tree - assert_eq!(rcl.count.get(&hash_of_cons_9_cons_5_nil).unwrap(), &0); - - // the atom `1` is still not in the tree anywhere - assert!(rcl.find_paths(&hash_of_1_atom, large_max).is_empty()); - - assert!(!rcl.count.contains_key(&hash_of_1_atom)); + #[test] + fn test_read_cache_lookup() { + let large_max = 30; + let mut rcl = ReadCacheLookup::new(); + + // the only thing cached right now is a nil, right at the top of the tree (ie. `1`) + let hash_of_nil = hash_blob(&[1]); + assert_eq!(rcl.find_paths(&hash_of_nil, large_max), [[1]]); + + assert_eq!(rcl.count.get(&hash_of_nil).unwrap(), &1); + + // the atom `1` is not in the tree anywhere + let hash_of_1_atom = hash_blobs(&[&[1], &[1]]); + assert!(rcl.find_paths(&hash_of_1_atom, large_max).is_empty()); + + // now let's push a `5` atom to the top + // tree: `(5 . 0)` + let hash_of_5_atom = hash_blobs(&[&[1], &[5]]); + rcl.push(hash_of_5_atom); + let hash_of_cons_5_nil = hash_blobs(&[&[2], &hash_of_5_atom, &hash_of_nil]); + assert_eq!(rcl.find_paths(&hash_of_cons_5_nil, large_max), [[1]]); + assert_eq!(rcl.find_paths(&hash_of_5_atom, large_max), [[2]]); + assert_eq!(rcl.find_paths(&hash_of_nil, large_max), [[3]]); + + assert_eq!(rcl.count.get(&hash_of_cons_5_nil).unwrap(), &1); + assert_eq!(rcl.count.get(&hash_of_5_atom).unwrap(), &1); + assert_eq!(rcl.count.get(&hash_of_nil).unwrap(), &1); + + // the atom `1` is still not in the tree anywhere + assert!(rcl.find_paths(&hash_of_1_atom, large_max).is_empty()); + + // now let's push a `9` atom to the top + // tree: `(9 . (5 . 0))` + let hash_of_9_atom = hash_blobs(&[&[1], &[9]]); + rcl.push(hash_of_9_atom); + let hash_of_cons_9_cons_5_nil = hash_blobs(&[&[2], &hash_of_9_atom, &hash_of_cons_5_nil]); + + assert_eq!(rcl.find_paths(&hash_of_cons_9_cons_5_nil, large_max), [[1]]); + assert_eq!(rcl.find_paths(&hash_of_9_atom, large_max), [[2]]); + assert_eq!(rcl.find_paths(&hash_of_cons_5_nil, large_max), [[3]]); + assert_eq!(rcl.find_paths(&hash_of_5_atom, large_max), [[5]]); + assert_eq!(rcl.find_paths(&hash_of_nil, large_max), [[7]]); + + assert_eq!(rcl.count.get(&hash_of_cons_9_cons_5_nil).unwrap(), &1); + assert_eq!(rcl.count.get(&hash_of_9_atom).unwrap(), &1); + assert_eq!(rcl.count.get(&hash_of_cons_5_nil).unwrap(), &1); + assert_eq!(rcl.count.get(&hash_of_5_atom).unwrap(), &1); + assert_eq!(rcl.count.get(&hash_of_nil).unwrap(), &1); + + // the atom `1` is still not in the tree anywhere + assert!(rcl.find_paths(&hash_of_1_atom, large_max).is_empty()); + + // now let's push a `10` atom to the top + // tree: `(10 . (9 . (5 . 0)))` + + let hash_of_10_atom = hash_blobs(&[&[1], &[10]]); + rcl.push(hash_of_10_atom); + let hash_of_cons_10_cons_9_cons_5_nil = + hash_blobs(&[&[2], &hash_of_10_atom, &hash_of_cons_9_cons_5_nil]); + assert_eq!( + rcl.find_paths(&hash_of_cons_10_cons_9_cons_5_nil, large_max), + [[1]] + ); + assert_eq!(rcl.find_paths(&hash_of_10_atom, large_max), [[2]]); + assert_eq!(rcl.find_paths(&hash_of_cons_9_cons_5_nil, large_max), [[3]]); + assert_eq!(rcl.find_paths(&hash_of_9_atom, large_max), [[5]]); + assert_eq!(rcl.find_paths(&hash_of_cons_5_nil, large_max), [[7]]); + assert_eq!(rcl.find_paths(&hash_of_5_atom, large_max), [[11]]); + assert_eq!(rcl.find_paths(&hash_of_nil, large_max), [[15]]); + + assert_eq!( + rcl.count.get(&hash_of_cons_10_cons_9_cons_5_nil).unwrap(), + &1 + ); + assert_eq!(rcl.count.get(&hash_of_10_atom).unwrap(), &1); + assert_eq!(rcl.count.get(&hash_of_cons_9_cons_5_nil).unwrap(), &1); + assert_eq!(rcl.count.get(&hash_of_9_atom).unwrap(), &1); + assert_eq!(rcl.count.get(&hash_of_cons_5_nil).unwrap(), &1); + assert_eq!(rcl.count.get(&hash_of_5_atom).unwrap(), &1); + assert_eq!(rcl.count.get(&hash_of_nil).unwrap(), &1); + + // the atom `1` is still not in the tree anywhere + assert!(rcl.find_paths(&hash_of_1_atom, large_max).is_empty()); + + // now let's do a `pop2_and_cons` + // tree: `((9 . 10) . (5 . 0))` + // 2 => (9 . 10) + // 3 => (5 . 0) + // 4 => 9 + // 5 => 5 + // 6 => 10 + // 7 => 0 + rcl.pop2_and_cons(); + let hash_of_cons_9_10 = hash_blobs(&[&[2], &hash_of_9_atom, &hash_of_10_atom]); + let hash_of_cons_cons_9_10_cons_5_nil = + hash_blobs(&[&[2], &hash_of_cons_9_10, &hash_of_cons_5_nil]); + assert_eq!( + rcl.find_paths(&hash_of_cons_cons_9_10_cons_5_nil, large_max), + [[1]] + ); + assert_eq!(rcl.find_paths(&hash_of_cons_9_10, large_max), [[2]]); + assert_eq!(rcl.find_paths(&hash_of_cons_5_nil, large_max), [[3]]); + assert_eq!(rcl.find_paths(&hash_of_9_atom, large_max), [[4]]); + assert_eq!(rcl.find_paths(&hash_of_10_atom, large_max), [[6]]); + assert_eq!(rcl.find_paths(&hash_of_5_atom, large_max), [[5]]); + assert_eq!(rcl.find_paths(&hash_of_nil, large_max), [[7]]); + + // `(9 . (5 . 0))` is no longer in the tree + assert!(rcl + .find_paths(&hash_of_cons_9_cons_5_nil, large_max) + .is_empty()); + + assert_eq!( + rcl.count.get(&hash_of_cons_cons_9_10_cons_5_nil).unwrap(), + &1 + ); + assert_eq!(rcl.count.get(&hash_of_cons_9_10).unwrap(), &1); + assert_eq!(rcl.count.get(&hash_of_cons_5_nil).unwrap(), &1); + assert_eq!(rcl.count.get(&hash_of_9_atom).unwrap(), &1); + assert_eq!(rcl.count.get(&hash_of_10_atom).unwrap(), &1); + assert_eq!(rcl.count.get(&hash_of_5_atom).unwrap(), &1); + assert_eq!(rcl.count.get(&hash_of_nil).unwrap(), &1); + + // `(9 . (5 . 0))` is no longer in the tree + assert_eq!(rcl.count.get(&hash_of_cons_9_cons_5_nil).unwrap(), &0); + + // the atom `1` is still not in the tree anywhere + assert!(rcl.find_paths(&hash_of_1_atom, large_max).is_empty()); + + assert!(!rcl.count.contains_key(&hash_of_1_atom)); + } } diff --git a/src/serde/ser.rs b/src/serde/ser.rs index 314bcaf3..478f8cbf 100644 --- a/src/serde/ser.rs +++ b/src/serde/ser.rs @@ -70,36 +70,41 @@ pub fn node_to_bytes(a: &Allocator, node: NodePtr) -> io::Result> { node_to_bytes_limit(a, node, 2000000) } -#[test] -fn test_serialize_limit() { - let mut a = Allocator::new(); +#[cfg(test)] +mod tests { + use super::*; - let leaf = a.new_atom(&[1, 2, 3, 4, 5]).unwrap(); - let l1 = a.new_pair(leaf, leaf).unwrap(); - let l2 = a.new_pair(l1, l1).unwrap(); - let l3 = a.new_pair(l2, l2).unwrap(); + #[test] + fn test_serialize_limit() { + let mut a = Allocator::new(); - { - let buffer = Cursor::new(Vec::new()); - let mut writer = LimitedWriter::new(buffer, 55); - node_to_stream(&a, l3, &mut writer).unwrap(); - let vec = writer.into_inner().into_inner(); - assert_eq!( - vec, - &[ - 0xff, 0xff, 0xff, 133, 1, 2, 3, 4, 5, 133, 1, 2, 3, 4, 5, 0xff, 133, 1, 2, 3, 4, 5, - 133, 1, 2, 3, 4, 5, 0xff, 0xff, 133, 1, 2, 3, 4, 5, 133, 1, 2, 3, 4, 5, 0xff, 133, - 1, 2, 3, 4, 5, 133, 1, 2, 3, 4, 5 - ] - ); - } + let leaf = a.new_atom(&[1, 2, 3, 4, 5]).unwrap(); + let l1 = a.new_pair(leaf, leaf).unwrap(); + let l2 = a.new_pair(l1, l1).unwrap(); + let l3 = a.new_pair(l2, l2).unwrap(); + + { + let buffer = Cursor::new(Vec::new()); + let mut writer = LimitedWriter::new(buffer, 55); + node_to_stream(&a, l3, &mut writer).unwrap(); + let vec = writer.into_inner().into_inner(); + assert_eq!( + vec, + &[ + 0xff, 0xff, 0xff, 133, 1, 2, 3, 4, 5, 133, 1, 2, 3, 4, 5, 0xff, 133, 1, 2, 3, + 4, 5, 133, 1, 2, 3, 4, 5, 0xff, 0xff, 133, 1, 2, 3, 4, 5, 133, 1, 2, 3, 4, 5, + 0xff, 133, 1, 2, 3, 4, 5, 133, 1, 2, 3, 4, 5 + ] + ); + } - { - let buffer = Cursor::new(Vec::new()); - let mut writer = LimitedWriter::new(buffer, 54); - assert_eq!( - node_to_stream(&a, l3, &mut writer).unwrap_err().kind(), - io::ErrorKind::OutOfMemory - ); + { + let buffer = Cursor::new(Vec::new()); + let mut writer = LimitedWriter::new(buffer, 54); + assert_eq!( + node_to_stream(&a, l3, &mut writer).unwrap_err().kind(), + io::ErrorKind::OutOfMemory + ); + } } } diff --git a/src/serde/ser_br.rs b/src/serde/ser_br.rs index c7dc0d27..9bc63e04 100644 --- a/src/serde/ser_br.rs +++ b/src/serde/ser_br.rs @@ -18,13 +18,6 @@ enum ReadOp { Cons, } -// these test cases were produced by: - -// from chia.types.blockchain_format.program import Program -// a = Program.to(...) -// print(bytes(a).hex()) -// print(a.get_tree_hash().hex()) - pub fn node_to_stream_backrefs( allocator: &Allocator, node: NodePtr, @@ -97,26 +90,22 @@ pub fn node_to_bytes_backrefs(a: &Allocator, node: NodePtr) -> io::Result io::Result { } } -#[test] -fn test_tree_hash_max_single_byte() { - let mut ctx = Sha256::new(); - ctx.update([1_u8]); - ctx.update([0x7f_u8]); - let mut cursor = Cursor::<&[u8]>::new(&[0x7f_u8]); - assert_eq!( - tree_hash_from_stream(&mut cursor).unwrap(), - ctx.finalize().as_slice() - ); -} - -#[test] -fn test_tree_hash_one() { - let mut ctx = Sha256::new(); - ctx.update([1_u8]); - ctx.update([1_u8]); - let mut cursor = Cursor::<&[u8]>::new(&[1_u8]); - assert_eq!( - tree_hash_from_stream(&mut cursor).unwrap(), - ctx.finalize().as_slice() - ); -} - -#[test] -fn test_tree_hash_zero() { - let mut ctx = Sha256::new(); - ctx.update([1_u8]); - ctx.update([0_u8]); - let mut cursor = Cursor::<&[u8]>::new(&[0_u8]); - assert_eq!( - tree_hash_from_stream(&mut cursor).unwrap(), - ctx.finalize().as_slice() - ); -} - -#[test] -fn test_tree_hash_nil() { - let mut ctx = Sha256::new(); - ctx.update([1_u8]); - let mut cursor = Cursor::<&[u8]>::new(&[0x80_u8]); - assert_eq!( - tree_hash_from_stream(&mut cursor).unwrap(), - ctx.finalize().as_slice() - ); -} - -#[test] -fn test_tree_hash_overlong() { - let mut cursor = Cursor::<&[u8]>::new(&[0x8f, 0xff]); - let e = tree_hash_from_stream(&mut cursor).unwrap_err(); - assert_eq!(e.kind(), bad_encoding().kind()); - - let mut cursor = Cursor::<&[u8]>::new(&[0b11001111, 0xff]); - let e = tree_hash_from_stream(&mut cursor).unwrap_err(); - assert_eq!(e.kind(), bad_encoding().kind()); - - let mut cursor = Cursor::<&[u8]>::new(&[0b11001111, 0xff, 0, 0]); - let e = tree_hash_from_stream(&mut cursor).unwrap_err(); - assert_eq!(e.kind(), bad_encoding().kind()); -} - #[cfg(test)] -use hex::FromHex; - -// these test cases were produced by: - -// from chia.types.blockchain_format.program import Program -// a = Program.to(...) -// print(bytes(a).hex()) -// print(a.get_tree_hash().hex()) - -#[test] -fn test_tree_hash_list() { - // this is the list (1 (2 (3 (4 (5 ()))))) - let buf = Vec::from_hex("ff01ff02ff03ff04ff0580").unwrap(); - let mut cursor = Cursor::<&[u8]>::new(&buf); - assert_eq!( - tree_hash_from_stream(&mut cursor).unwrap().to_vec(), - Vec::from_hex("123190dddde51acfc61f48429a879a7b905d1726a52991f7d63349863d06b1b6").unwrap() - ); -} - -#[test] -fn test_tree_hash_tree() { - // this is the tree ((1, 2), (3, 4)) - let buf = Vec::from_hex("ffff0102ff0304").unwrap(); - let mut cursor = Cursor::<&[u8]>::new(&buf); - assert_eq!( - tree_hash_from_stream(&mut cursor).unwrap().to_vec(), - Vec::from_hex("2824018d148bc6aed0847e2c86aaa8a5407b916169f15b12cea31fa932fc4c8d").unwrap() - ); -} - -#[test] -fn test_tree_hash_tree_large_atom() { - // this is the tree ((1, 2), (3, b"foobar")) - let buf = Vec::from_hex("ffff0102ff0386666f6f626172").unwrap(); - let mut cursor = Cursor::<&[u8]>::new(&buf); - assert_eq!( - tree_hash_from_stream(&mut cursor).unwrap().to_vec(), - Vec::from_hex("b28d5b401bd02b65b7ed93de8e916cfc488738323e568bcca7e032c3a97a12e4").unwrap() - ); -} - -#[cfg(test)] -mod test { +mod tests { use super::*; - use crate::serde::node_from_bytes_backrefs; - use crate::Allocator; - use rstest::rstest; + + use hex::FromHex; #[test] - fn test_serialized_length_from_bytes_trusted() { - assert_eq!( - serialized_length_from_bytes_trusted(&[0x7f, 0x00, 0x00, 0x00]).unwrap(), - 1 - ); + fn test_tree_hash_max_single_byte() { + let mut ctx = Sha256::new(); + ctx.update([1_u8]); + ctx.update([0x7f_u8]); + let mut cursor = Cursor::<&[u8]>::new(&[0x7f_u8]); assert_eq!( - serialized_length_from_bytes_trusted(&[0x80, 0x00, 0x00, 0x00]).unwrap(), - 1 + tree_hash_from_stream(&mut cursor).unwrap(), + ctx.finalize().as_slice() ); + } + + #[test] + fn test_tree_hash_one() { + let mut ctx = Sha256::new(); + ctx.update([1_u8]); + ctx.update([1_u8]); + let mut cursor = Cursor::<&[u8]>::new(&[1_u8]); assert_eq!( - serialized_length_from_bytes_trusted(&[0xff, 0x00, 0x00, 0x00]).unwrap(), - 3 + tree_hash_from_stream(&mut cursor).unwrap(), + ctx.finalize().as_slice() ); + } + + #[test] + fn test_tree_hash_zero() { + let mut ctx = Sha256::new(); + ctx.update([1_u8]); + ctx.update([0_u8]); + let mut cursor = Cursor::<&[u8]>::new(&[0_u8]); assert_eq!( - serialized_length_from_bytes_trusted(&[0xff, 0x01, 0xff, 0x80, 0x80, 0x00]).unwrap(), - 5 + tree_hash_from_stream(&mut cursor).unwrap(), + ctx.finalize().as_slice() ); + } - // this is an invalid back-ref - // but it's not validated + #[test] + fn test_tree_hash_nil() { + let mut ctx = Sha256::new(); + ctx.update([1_u8]); + let mut cursor = Cursor::<&[u8]>::new(&[0x80_u8]); assert_eq!( - serialized_length_from_bytes_trusted(&[0xff, 0x01, 0xff, 0xfe, 0x10, 0x80, 0x00]) - .unwrap(), - 6 + tree_hash_from_stream(&mut cursor).unwrap(), + ctx.finalize().as_slice() ); + } - let e = serialized_length_from_bytes_trusted(&[0x8f, 0xff]).unwrap_err(); + #[test] + fn test_tree_hash_overlong() { + let mut cursor = Cursor::<&[u8]>::new(&[0x8f, 0xff]); + let e = tree_hash_from_stream(&mut cursor).unwrap_err(); assert_eq!(e.kind(), bad_encoding().kind()); - assert_eq!(e.to_string(), "bad encoding"); - let e = serialized_length_from_bytes_trusted(&[0b11001111, 0xff]).unwrap_err(); + let mut cursor = Cursor::<&[u8]>::new(&[0b11001111, 0xff]); + let e = tree_hash_from_stream(&mut cursor).unwrap_err(); assert_eq!(e.kind(), bad_encoding().kind()); - assert_eq!(e.to_string(), "bad encoding"); - let e = serialized_length_from_bytes_trusted(&[0b11001111, 0xff, 0, 0]).unwrap_err(); + let mut cursor = Cursor::<&[u8]>::new(&[0b11001111, 0xff, 0, 0]); + let e = tree_hash_from_stream(&mut cursor).unwrap_err(); assert_eq!(e.kind(), bad_encoding().kind()); - assert_eq!(e.to_string(), "bad encoding"); + } + // these test cases were produced by: + + // from chia.types.blockchain_format.program import Program + // a = Program.to(...) + // print(bytes(a).hex()) + // print(a.get_tree_hash().hex()) + + #[test] + fn test_tree_hash_list() { + // this is the list (1 (2 (3 (4 (5 ()))))) + let buf = Vec::from_hex("ff01ff02ff03ff04ff0580").unwrap(); + let mut cursor = Cursor::<&[u8]>::new(&buf); assert_eq!( - serialized_length_from_bytes_trusted(&[ - 0x8f, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - ]) - .unwrap(), - 16 + tree_hash_from_stream(&mut cursor).unwrap().to_vec(), + Vec::from_hex("123190dddde51acfc61f48429a879a7b905d1726a52991f7d63349863d06b1b6") + .unwrap() ); } #[test] - fn test_serialized_length_from_bytes() { - use std::io::ErrorKind; - assert_eq!( - serialized_length_from_bytes(&[0x7f, 0x00, 0x00, 0x00]).unwrap(), - 1 - ); - assert_eq!( - serialized_length_from_bytes(&[0x80, 0x00, 0x00, 0x00]).unwrap(), - 1 - ); - assert_eq!( - serialized_length_from_bytes(&[0xff, 0x00, 0x00, 0x00]).unwrap(), - 3 - ); + fn test_tree_hash_tree() { + // this is the tree ((1, 2), (3, 4)) + let buf = Vec::from_hex("ffff0102ff0304").unwrap(); + let mut cursor = Cursor::<&[u8]>::new(&buf); assert_eq!( - serialized_length_from_bytes(&[0xff, 0x01, 0xff, 0x80, 0x80, 0x00]).unwrap(), - 5 + tree_hash_from_stream(&mut cursor).unwrap().to_vec(), + Vec::from_hex("2824018d148bc6aed0847e2c86aaa8a5407b916169f15b12cea31fa932fc4c8d") + .unwrap() ); + } - // this is an invalid back-ref - let e = - serialized_length_from_bytes(&[0xff, 0x01, 0xff, 0xfe, 0x10, 0x80, 0x00]).unwrap_err(); - assert_eq!(e.kind(), ErrorKind::Other); - assert_eq!(e.to_string(), "path into atom"); - - let e = serialized_length_from_bytes(&[0x8f, 0xff]).unwrap_err(); - assert_eq!(e.kind(), bad_encoding().kind()); - assert_eq!(e.to_string(), "bad encoding"); - - let e = serialized_length_from_bytes(&[0b11001111, 0xff]).unwrap_err(); - assert_eq!(e.kind(), bad_encoding().kind()); - assert_eq!(e.to_string(), "bad encoding"); - - let e = serialized_length_from_bytes(&[0b11001111, 0xff, 0, 0]).unwrap_err(); - assert_eq!(e.kind(), bad_encoding().kind()); - assert_eq!(e.to_string(), "bad encoding"); - + #[test] + fn test_tree_hash_tree_large_atom() { + // this is the tree ((1, 2), (3, b"foobar")) + let buf = Vec::from_hex("ffff0102ff0386666f6f626172").unwrap(); + let mut cursor = Cursor::<&[u8]>::new(&buf); assert_eq!( - serialized_length_from_bytes(&[0x8f, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) - .unwrap(), - 16 + tree_hash_from_stream(&mut cursor).unwrap().to_vec(), + Vec::from_hex("b28d5b401bd02b65b7ed93de8e916cfc488738323e568bcca7e032c3a97a12e4") + .unwrap() ); } - #[rstest] - // ("foobar" "foobar") - #[case("ff86666f6f626172ff86666f6f62617280")] - // ("foobar" "foobar") - #[case("ff86666f6f626172fe01")] - // ((1 2 3 4) 1 2 3 4) - #[case("ffff01ff02ff03ff0480ff01ff02ff03ff0480")] - // ((1 2 3 4) 1 2 3 4) - #[case("ffff01ff02ff03ff0480fe02")] - // `(((((a_very_long_repeated_string . 1) . (2 . 3)) . ((4 . 5) . (6 . 7))) . (8 . 9)) 10 a_very_long_repeated_string)` - #[case( - "ffffffffff9b615f766572795f6c6f6e675f72657065617465645f737472696e6701ff0203ffff04\ + #[cfg(test)] + mod test { + use super::*; + use crate::serde::node_from_bytes_backrefs; + use crate::Allocator; + use rstest::rstest; + + #[test] + fn test_serialized_length_from_bytes_trusted() { + assert_eq!( + serialized_length_from_bytes_trusted(&[0x7f, 0x00, 0x00, 0x00]).unwrap(), + 1 + ); + assert_eq!( + serialized_length_from_bytes_trusted(&[0x80, 0x00, 0x00, 0x00]).unwrap(), + 1 + ); + assert_eq!( + serialized_length_from_bytes_trusted(&[0xff, 0x00, 0x00, 0x00]).unwrap(), + 3 + ); + assert_eq!( + serialized_length_from_bytes_trusted(&[0xff, 0x01, 0xff, 0x80, 0x80, 0x00]) + .unwrap(), + 5 + ); + + // this is an invalid back-ref + // but it's not validated + assert_eq!( + serialized_length_from_bytes_trusted(&[0xff, 0x01, 0xff, 0xfe, 0x10, 0x80, 0x00]) + .unwrap(), + 6 + ); + + let e = serialized_length_from_bytes_trusted(&[0x8f, 0xff]).unwrap_err(); + assert_eq!(e.kind(), bad_encoding().kind()); + assert_eq!(e.to_string(), "bad encoding"); + + let e = serialized_length_from_bytes_trusted(&[0b11001111, 0xff]).unwrap_err(); + assert_eq!(e.kind(), bad_encoding().kind()); + assert_eq!(e.to_string(), "bad encoding"); + + let e = serialized_length_from_bytes_trusted(&[0b11001111, 0xff, 0, 0]).unwrap_err(); + assert_eq!(e.kind(), bad_encoding().kind()); + assert_eq!(e.to_string(), "bad encoding"); + + assert_eq!( + serialized_length_from_bytes_trusted(&[ + 0x8f, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + ]) + .unwrap(), + 16 + ); + } + + #[test] + fn test_serialized_length_from_bytes() { + use std::io::ErrorKind; + assert_eq!( + serialized_length_from_bytes(&[0x7f, 0x00, 0x00, 0x00]).unwrap(), + 1 + ); + assert_eq!( + serialized_length_from_bytes(&[0x80, 0x00, 0x00, 0x00]).unwrap(), + 1 + ); + assert_eq!( + serialized_length_from_bytes(&[0xff, 0x00, 0x00, 0x00]).unwrap(), + 3 + ); + assert_eq!( + serialized_length_from_bytes(&[0xff, 0x01, 0xff, 0x80, 0x80, 0x00]).unwrap(), + 5 + ); + + // this is an invalid back-ref + let e = serialized_length_from_bytes(&[0xff, 0x01, 0xff, 0xfe, 0x10, 0x80, 0x00]) + .unwrap_err(); + assert_eq!(e.kind(), ErrorKind::Other); + assert_eq!(e.to_string(), "path into atom"); + + let e = serialized_length_from_bytes(&[0x8f, 0xff]).unwrap_err(); + assert_eq!(e.kind(), bad_encoding().kind()); + assert_eq!(e.to_string(), "bad encoding"); + + let e = serialized_length_from_bytes(&[0b11001111, 0xff]).unwrap_err(); + assert_eq!(e.kind(), bad_encoding().kind()); + assert_eq!(e.to_string(), "bad encoding"); + + let e = serialized_length_from_bytes(&[0b11001111, 0xff, 0, 0]).unwrap_err(); + assert_eq!(e.kind(), bad_encoding().kind()); + assert_eq!(e.to_string(), "bad encoding"); + + assert_eq!( + serialized_length_from_bytes(&[0x8f, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) + .unwrap(), + 16 + ); + } + + #[rstest] + // ("foobar" "foobar") + #[case("ff86666f6f626172ff86666f6f62617280")] + // ("foobar" "foobar") + #[case("ff86666f6f626172fe01")] + // ((1 2 3 4) 1 2 3 4) + #[case("ffff01ff02ff03ff0480ff01ff02ff03ff0480")] + // ((1 2 3 4) 1 2 3 4) + #[case("ffff01ff02ff03ff0480fe02")] + // `(((((a_very_long_repeated_string . 1) . (2 . 3)) . ((4 . 5) . (6 . 7))) . (8 . 9)) 10 a_very_long_repeated_string)` + #[case( + "ffffffffff9b615f766572795f6c6f6e675f72657065617465645f737472696e6701ff0203ffff04\ 05ff0607ff0809ff0aff9b615f766572795f6c6f6e675f72657065617465645f737472696e6780" - )] - #[case("ffffffffff9b615f766572795f6c6f6e675f72657065617465645f737472696e6701ff0203ffff0405ff0607ff0809ff0afffe4180")] - #[case( - "ff01ffffffa022cf3c17be4e0e0e0b2e2a3f6dd1ee955528f737f0cb724247bc2e4a776cb989ff\ + )] + #[case("ffffffffff9b615f766572795f6c6f6e675f72657065617465645f737472696e6701ff0203ffff0405ff0607ff0809ff0afffe4180")] + #[case( + "ff01ffffffa022cf3c17be4e0e0e0b2e2a3f6dd1ee955528f737f0cb724247bc2e4a776cb989ff\ ff02ffff01ff02ffff01ff02ffff03ffff18ff2fffff010180ffff01ff02ff36ffff04ff02ffff\ 04ff05ffff04ff17ffff04ffff02ff26ffff04ff02ffff04ff0bff80808080ffff04ff2fffff04\ ff0bffff04ff5fff808080808080808080ffff01ff088080fe81ffffff04ffff01ffffffff4602\ @@ -513,15 +520,16 @@ eb09d18d83bd56482aee566820f5afdce595b3ed095eb36c5cef9301a5383a3b9a6c1a94a85e4f\ 982e1fa3af2c99087e5f6df8b887d30c109f71043671683a1ae985d7d874fbe07dfa6d88b70100\ 00001868747470733a2f2f6368696170702e68706f6f6c2e636f6d0000004080ffa0fc0b1e9409\ ae5c3c40c50832a7aecc0b3ba4646568a00c01289c45e1f03b2b488080808080" - )] - fn serialized_length_with_backrefs(#[case] serialization_as_hex: &str) { - let buf = Vec::from_hex(serialization_as_hex).unwrap(); - let len = serialized_length_from_bytes(&buf).expect("serialized_length_from_bytes"); + )] + fn serialized_length_with_backrefs(#[case] serialization_as_hex: &str) { + let buf = Vec::from_hex(serialization_as_hex).unwrap(); + let len = serialized_length_from_bytes(&buf).expect("serialized_length_from_bytes"); - // make sure the serialization is valid - let mut allocator = Allocator::new(); - assert!(node_from_bytes_backrefs(&mut allocator, &buf).is_ok()); + // make sure the serialization is valid + let mut allocator = Allocator::new(); + assert!(node_from_bytes_backrefs(&mut allocator, &buf).is_ok()); - assert_eq!(len, buf.len() as u64); + assert_eq!(len, buf.len() as u64); + } } } diff --git a/src/serde/write_atom.rs b/src/serde/write_atom.rs index e42f13fa..1ab4f2fb 100644 --- a/src/serde/write_atom.rs +++ b/src/serde/write_atom.rs @@ -52,124 +52,129 @@ pub fn write_atom(f: &mut W, atom: &[u8]) -> io::Result<()> { f.write_all(atom) } -#[test] -fn test_write_atom_encoding_prefix_with_size() { - let mut buf = Vec::::new(); - assert!(write_atom_encoding_prefix_with_size(&mut buf, 0, 0).is_ok()); - assert_eq!(buf, vec![0x80]); +#[cfg(test)] +mod tests { + use super::*; - for v in 0..0x7f { + #[test] + fn test_write_atom_encoding_prefix_with_size() { let mut buf = Vec::::new(); - assert!(write_atom_encoding_prefix_with_size(&mut buf, v, 1).is_ok()); - assert_eq!(buf, vec![]); - } + assert!(write_atom_encoding_prefix_with_size(&mut buf, 0, 0).is_ok()); + assert_eq!(buf, vec![0x80]); + + for v in 0..0x7f { + let mut buf = Vec::::new(); + assert!(write_atom_encoding_prefix_with_size(&mut buf, v, 1).is_ok()); + assert_eq!(buf, vec![]); + } + + for v in 0x80..0xff { + let mut buf = Vec::::new(); + assert!(write_atom_encoding_prefix_with_size(&mut buf, v, 1).is_ok()); + assert_eq!(buf, vec![0x81]); + } + + for size in 0x1_u8..0x3f_u8 { + let mut buf = Vec::::new(); + assert!(write_atom_encoding_prefix_with_size(&mut buf, 0xaa, size as u64).is_ok()); + assert_eq!(buf, vec![0x80 + size]); + } - for v in 0x80..0xff { let mut buf = Vec::::new(); - assert!(write_atom_encoding_prefix_with_size(&mut buf, v, 1).is_ok()); - assert_eq!(buf, vec![0x81]); - } + assert!(write_atom_encoding_prefix_with_size(&mut buf, 0xaa, 0b111111).is_ok()); + assert_eq!(buf, vec![0b10111111]); - for size in 0x1_u8..0x3f_u8 { let mut buf = Vec::::new(); - assert!(write_atom_encoding_prefix_with_size(&mut buf, 0xaa, size as u64).is_ok()); - assert_eq!(buf, vec![0x80 + size]); - } + assert!(write_atom_encoding_prefix_with_size(&mut buf, 0xaa, 0b1000000).is_ok()); + assert_eq!(buf, vec![0b11000000, 0b1000000]); + + let mut buf = Vec::::new(); + assert!(write_atom_encoding_prefix_with_size(&mut buf, 0xaa, 0xfffff).is_ok()); + assert_eq!(buf, vec![0b11101111, 0xff, 0xff]); + + let mut buf = Vec::::new(); + assert!(write_atom_encoding_prefix_with_size(&mut buf, 0xaa, 0xffffff).is_ok()); + assert_eq!(buf, vec![0b11110000, 0xff, 0xff, 0xff]); + + let mut buf = Vec::::new(); + assert!(write_atom_encoding_prefix_with_size(&mut buf, 0xaa, 0xffffffff).is_ok()); + assert_eq!(buf, vec![0b11111000, 0xff, 0xff, 0xff, 0xff]); + + // this is the largest possible atom size + let mut buf = Vec::::new(); + assert!(write_atom_encoding_prefix_with_size(&mut buf, 0xaa, 0x3ffffffff).is_ok()); + assert_eq!(buf, vec![0b11111011, 0xff, 0xff, 0xff, 0xff]); - let mut buf = Vec::::new(); - assert!(write_atom_encoding_prefix_with_size(&mut buf, 0xaa, 0b111111).is_ok()); - assert_eq!(buf, vec![0b10111111]); - - let mut buf = Vec::::new(); - assert!(write_atom_encoding_prefix_with_size(&mut buf, 0xaa, 0b1000000).is_ok()); - assert_eq!(buf, vec![0b11000000, 0b1000000]); - - let mut buf = Vec::::new(); - assert!(write_atom_encoding_prefix_with_size(&mut buf, 0xaa, 0xfffff).is_ok()); - assert_eq!(buf, vec![0b11101111, 0xff, 0xff]); - - let mut buf = Vec::::new(); - assert!(write_atom_encoding_prefix_with_size(&mut buf, 0xaa, 0xffffff).is_ok()); - assert_eq!(buf, vec![0b11110000, 0xff, 0xff, 0xff]); - - let mut buf = Vec::::new(); - assert!(write_atom_encoding_prefix_with_size(&mut buf, 0xaa, 0xffffffff).is_ok()); - assert_eq!(buf, vec![0b11111000, 0xff, 0xff, 0xff, 0xff]); - - // this is the largest possible atom size - let mut buf = Vec::::new(); - assert!(write_atom_encoding_prefix_with_size(&mut buf, 0xaa, 0x3ffffffff).is_ok()); - assert_eq!(buf, vec![0b11111011, 0xff, 0xff, 0xff, 0xff]); - - // this is too large - let mut buf = Vec::::new(); - assert!(write_atom_encoding_prefix_with_size(&mut buf, 0xaa, 0x400000000).is_err()); - - for (size, expected_prefix) in [ - (0x1, vec![0x81]), - (0x2, vec![0x82]), - (0x3f, vec![0xbf]), - (0x40, vec![0xc0, 0x40]), - (0x1fff, vec![0xdf, 0xff]), - (0x2000, vec![0xe0, 0x20, 0x00]), - (0xf_ffff, vec![0xef, 0xff, 0xff]), - (0x10_0000, vec![0xf0, 0x10, 0x00, 0x00]), - (0x7ff_ffff, vec![0xf7, 0xff, 0xff, 0xff]), - (0x800_0000, vec![0xf8, 0x08, 0x00, 0x00, 0x00]), - (0x3_ffff_ffff, vec![0xfb, 0xff, 0xff, 0xff, 0xff]), - ] { + // this is too large let mut buf = Vec::::new(); - assert!(write_atom_encoding_prefix_with_size(&mut buf, 0xaa, size).is_ok()); - assert_eq!(buf, expected_prefix); + assert!(write_atom_encoding_prefix_with_size(&mut buf, 0xaa, 0x400000000).is_err()); + + for (size, expected_prefix) in [ + (0x1, vec![0x81]), + (0x2, vec![0x82]), + (0x3f, vec![0xbf]), + (0x40, vec![0xc0, 0x40]), + (0x1fff, vec![0xdf, 0xff]), + (0x2000, vec![0xe0, 0x20, 0x00]), + (0xf_ffff, vec![0xef, 0xff, 0xff]), + (0x10_0000, vec![0xf0, 0x10, 0x00, 0x00]), + (0x7ff_ffff, vec![0xf7, 0xff, 0xff, 0xff]), + (0x800_0000, vec![0xf8, 0x08, 0x00, 0x00, 0x00]), + (0x3_ffff_ffff, vec![0xfb, 0xff, 0xff, 0xff, 0xff]), + ] { + let mut buf = Vec::::new(); + assert!(write_atom_encoding_prefix_with_size(&mut buf, 0xaa, size).is_ok()); + assert_eq!(buf, expected_prefix); + } } -} -#[test] -fn test_write_atom() { - let mut buf = Vec::::new(); - assert!(write_atom(&mut buf, &[]).is_ok()); - assert_eq!(buf, vec![0b10000000]); - - let mut buf = Vec::::new(); - assert!(write_atom(&mut buf, &[0x00]).is_ok()); - assert_eq!(buf, vec![0b00000000]); - - let mut buf = Vec::::new(); - assert!(write_atom(&mut buf, &[0x7f]).is_ok()); - assert_eq!(buf, vec![0x7f]); - - let mut buf = Vec::::new(); - assert!(write_atom(&mut buf, &[0x80]).is_ok()); - assert_eq!(buf, vec![0x81, 0x80]); - - let mut buf = Vec::::new(); - assert!(write_atom(&mut buf, &[0xff]).is_ok()); - assert_eq!(buf, vec![0x81, 0xff]); - - let mut buf = Vec::::new(); - assert!(write_atom(&mut buf, &[0xaa, 0xbb]).is_ok()); - assert_eq!(buf, vec![0x82, 0xaa, 0xbb]); - - for (size, mut expected_prefix) in [ - (0x1, vec![0x81]), - (0x2, vec![0x82]), - (0x3f, vec![0xbf]), - (0x40, vec![0xc0, 0x40]), - (0x1fff, vec![0xdf, 0xff]), - (0x2000, vec![0xe0, 0x20, 0x00]), - (0xf_ffff, vec![0xef, 0xff, 0xff]), - (0x10_0000, vec![0xf0, 0x10, 0x00, 0x00]), - (0x7ff_ffff, vec![0xf7, 0xff, 0xff, 0xff]), - (0x800_0000, vec![0xf8, 0x08, 0x00, 0x00, 0x00]), - // the next one represents 17 GB of memory, which it then has to serialize - // so let's not do it until some time in the future when all machines have - // 64 GB of memory - // (0x3_ffff_ffff, vec![0xfb, 0xff, 0xff, 0xff, 0xff]), - ] { + #[test] + fn test_write_atom() { + let mut buf = Vec::::new(); + assert!(write_atom(&mut buf, &[]).is_ok()); + assert_eq!(buf, vec![0b10000000]); + + let mut buf = Vec::::new(); + assert!(write_atom(&mut buf, &[0x00]).is_ok()); + assert_eq!(buf, vec![0b00000000]); + + let mut buf = Vec::::new(); + assert!(write_atom(&mut buf, &[0x7f]).is_ok()); + assert_eq!(buf, vec![0x7f]); + + let mut buf = Vec::::new(); + assert!(write_atom(&mut buf, &[0x80]).is_ok()); + assert_eq!(buf, vec![0x81, 0x80]); + + let mut buf = Vec::::new(); + assert!(write_atom(&mut buf, &[0xff]).is_ok()); + assert_eq!(buf, vec![0x81, 0xff]); + let mut buf = Vec::::new(); - let atom = vec![0xaa; size]; - assert!(write_atom(&mut buf, &atom).is_ok()); - expected_prefix.extend(atom); - assert_eq!(buf, expected_prefix); + assert!(write_atom(&mut buf, &[0xaa, 0xbb]).is_ok()); + assert_eq!(buf, vec![0x82, 0xaa, 0xbb]); + + for (size, mut expected_prefix) in [ + (0x1, vec![0x81]), + (0x2, vec![0x82]), + (0x3f, vec![0xbf]), + (0x40, vec![0xc0, 0x40]), + (0x1fff, vec![0xdf, 0xff]), + (0x2000, vec![0xe0, 0x20, 0x00]), + (0xf_ffff, vec![0xef, 0xff, 0xff]), + (0x10_0000, vec![0xf0, 0x10, 0x00, 0x00]), + (0x7ff_ffff, vec![0xf7, 0xff, 0xff, 0xff]), + (0x800_0000, vec![0xf8, 0x08, 0x00, 0x00, 0x00]), + // the next one represents 17 GB of memory, which it then has to serialize + // so let's not do it until some time in the future when all machines have + // 64 GB of memory + // (0x3_ffff_ffff, vec![0xfb, 0xff, 0xff, 0xff, 0xff]), + ] { + let mut buf = Vec::::new(); + let atom = vec![0xaa; size]; + assert!(write_atom(&mut buf, &atom).is_ok()); + expected_prefix.extend(atom); + assert_eq!(buf, expected_prefix); + } } }