use std::io::Write;
use alloy_primitives::hex;
use crate::bmt::DEFAULT_BODY_SIZE;
use crate::file::SyncSplitter;
use crate::store::MemoryStore;
const CHUNK_SIZE: usize = DEFAULT_BODY_SIZE;
fn sequential_bytes(len: usize) -> Vec<u8> {
(0..len).map(|i| (i % 255) as u8).collect()
}
const TEST_VECTORS: &[(usize, &str)] = &[
(
31,
"ece86edb20669cc60d142789d464d57bdf5e33cb789d443f608cbd81cfa5697d",
), (
32,
"0be77f0bb7abc9cd0abed640ee29849a3072ccfd1020019fe03658c38f087e02",
), (
33,
"3463b46d4f9d5bfcbf9a23224d635e51896c1daef7d225b86679db17c5fd868e",
), (
63,
"95510c2ff18276ed94be2160aed4e69c9116573b6f69faaeed1b426fea6a3db8",
), (
64,
"490072cc55b8ad381335ff882ac51303cc069cbcb8d8d3f7aa152d9c617829fe",
), (
65,
"541552bae05e9a63a6cb561f69edf36ffe073e441667dbf7a0e9a3864bb744ea",
), (
CHUNK_SIZE,
"c10090961e7682a10890c334d759a28426647141213abda93b096b892824d2ef",
), (
CHUNK_SIZE + 31,
"91699c83ed93a1f87e326a29ccd8cc775323f9e7260035a5f014c975c5f3cd28",
), (
CHUNK_SIZE + 32,
"73759673a52c1f1707cbb61337645f4fcbd209cdc53d7e2cedaaa9f44df61285",
), (
CHUNK_SIZE + 63,
"db1313a727ffc184ae52a70012fbbf7235f551b9f2d2da04bf476abe42a3cb42",
), (
CHUNK_SIZE + 64,
"ade7af36ac0c7297dc1c11fd7b46981b629c6077bce75300f85b02a6153f161b",
), (
CHUNK_SIZE * 2,
"29a5fb121ce96194ba8b7b823a1f9c6af87e1791f824940a53b5a7efe3f790d9",
), (
CHUNK_SIZE * 2 + 32,
"61416726988f77b874435bdd89a419edc3861111884fd60e8adf54e2f299efd6",
), (
CHUNK_SIZE * 128,
"3047d841077898c26bbe6be652a2ec590a5d9bd7cd45d290ea42511b48753c09",
), (
CHUNK_SIZE * 128 + 31,
"e5c76afa931e33ac94bce2e754b1bb6407d07f738f67856783d93934ca8fc576",
), (
CHUNK_SIZE * 128 + 32,
"485a526fc74c8a344c43a4545a5987d17af9ab401c0ef1ef63aefcc5c2c086df",
), (
CHUNK_SIZE * 128 + 64,
"624b2abb7aefc0978f891b2a56b665513480e5dc195b4a66cd8def074a6d2e94",
), (
CHUNK_SIZE * 129,
"b8e1804e37a064d28d161ab5f256cc482b1423d5cd0a6b30fde7b0f51ece9199",
), (
CHUNK_SIZE * 130,
"59de730bf6c67a941f3b2ffa2f920acfaa1713695ad5deea12b4a121e5f23fa1",
), ];
const LARGE_TEST_VECTORS: &[(usize, &str)] = &[
(
CHUNK_SIZE * 128 * 128,
"522194562123473dcfd7a457b18ee7dee8b7db70ed3cfa2b73f348a992fdfd3b",
), (
CHUNK_SIZE * 128 * 128 + 32,
"ed0cc44c93b14fef2d91ab3a3674eeb6352a42ac2f0bbe524711824aae1e7bcc",
), ];
fn run_vector_test(size: usize, expected_hex: &str) {
let data = sequential_bytes(size);
let store = MemoryStore::<DEFAULT_BODY_SIZE>::new();
let mut splitter = SyncSplitter::new(store, data.len() as u64);
splitter.write_all(&data).unwrap();
let (root, _) = splitter.finish().unwrap();
assert_eq!(
hex::encode(root.as_slice()),
expected_hex,
"Root hash mismatch for size {} bytes",
size
);
}
#[test]
fn test_go_vectors() {
for (i, &(size, expected)) in TEST_VECTORS.iter().enumerate() {
run_vector_test(size, expected);
eprintln!(" vector {i}: {size} bytes OK");
}
}
#[test]
#[ignore]
fn test_go_vectors_large() {
for (i, &(size, expected)) in LARGE_TEST_VECTORS.iter().enumerate() {
run_vector_test(size, expected);
eprintln!(" large vector {i}: {size} bytes OK");
}
}
#[cfg(feature = "encryption")]
mod encrypted {
use crate::bmt::DEFAULT_BODY_SIZE;
use crate::file::{sync_join, sync_split_encrypted};
const TEST_SIZES: &[usize] = &[
0,
10,
100,
1000,
4095,
4096,
4097,
4096 * 2,
4096 * 64,
4096 * 64 + 1,
4096 * 65,
1_000_000,
];
fn run_encrypted_roundtrip(size: usize) {
let data: Vec<u8> = (0..size).map(|i| (i % 255) as u8).collect();
let (root_ref, store) = sync_split_encrypted::<DEFAULT_BODY_SIZE>(&data).unwrap();
assert_eq!(
Vec::from(&root_ref).len(),
64,
"Root ref must be 64 bytes for size {size}"
);
let recovered = sync_join(&store, root_ref).unwrap();
assert_eq!(recovered, data, "Round-trip failed for size {size}");
}
#[test]
fn encrypted_roundtrip_all_sizes() {
for &size in TEST_SIZES {
run_encrypted_roundtrip(size);
eprintln!(" encrypted roundtrip: {size} bytes OK");
}
}
#[test]
fn encrypted_chunk_count_single() {
let data = b"small data";
let (_, store) = sync_split_encrypted::<DEFAULT_BODY_SIZE>(data).unwrap();
assert_eq!(store.len(), 1);
}
#[test]
fn encrypted_chunk_count_two_data() {
let data = vec![0xAB; 4097];
let (_, store) = sync_split_encrypted::<DEFAULT_BODY_SIZE>(&data).unwrap();
assert_eq!(store.len(), 3);
}
#[test]
fn encrypted_nondeterministic() {
let data = b"test determinism";
let (ref1, _) = sync_split_encrypted::<DEFAULT_BODY_SIZE>(data).unwrap();
let (ref2, _) = sync_split_encrypted::<DEFAULT_BODY_SIZE>(data).unwrap();
assert_ne!(ref1.address(), ref2.address());
}
}
mod write_file_ext {
use crate::bmt::DEFAULT_BODY_SIZE;
use crate::file::{SyncChunkGetExt, SyncChunkPutExt};
use crate::store::MemoryStore;
#[test]
fn write_file_roundtrip() {
let store = MemoryStore::<DEFAULT_BODY_SIZE>::new();
let addr = store.write_file(b"hello swarm").unwrap();
let recovered = store.read_file(addr).unwrap();
assert_eq!(recovered, b"hello swarm");
}
#[test]
fn write_file_large() {
let data = vec![0xAB; 8192];
let store = MemoryStore::<DEFAULT_BODY_SIZE>::new();
let addr = store.write_file(&data).unwrap();
let recovered = store.read_file(addr).unwrap();
assert_eq!(recovered, data);
}
#[test]
fn writer_roundtrip() {
use std::io::Write;
let store = MemoryStore::<DEFAULT_BODY_SIZE>::new();
let data = b"streaming via writer";
let mut writer = store.writer(data.len() as u64);
writer.write_all(data).unwrap();
let (root, _) = writer.finish().unwrap();
let recovered = store.read_file(root).unwrap();
assert_eq!(recovered, data);
}
#[cfg(feature = "encryption")]
mod encrypted {
use crate::bmt::DEFAULT_BODY_SIZE;
use crate::file::{SyncChunkGetExt, SyncChunkPutExt};
use crate::store::MemoryStore;
#[test]
fn write_encrypted_file_roundtrip() {
let store = MemoryStore::<DEFAULT_BODY_SIZE>::new();
let enc_ref = store.write_encrypted_file(b"secret data").unwrap();
let recovered = store.read_file(enc_ref).unwrap();
assert_eq!(recovered, b"secret data");
}
}
}