From 27682a58a49549be6f9699eca777e3a275b1a493 Mon Sep 17 00:00:00 2001 From: varun-doshi Date: Fri, 10 Oct 2025 12:11:33 +0530 Subject: [PATCH 1/3] feat(tests): Add tests for Span --- src/payload/span.rs | 69 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/src/payload/span.rs b/src/payload/span.rs index 9393e50..442bd7c 100644 --- a/src/payload/span.rs +++ b/src/payload/span.rs @@ -181,3 +181,72 @@ impl Display for Span

{ ) } } + +#[cfg(test)] +mod tests { + use crate::{ + payload::Span, + prelude::{BlockContext, Checkpoint, Ethereum}, + test_utils::BlockContextMocked, + }; + + #[test] + fn span_between_linear_history() { + let (block, _) = BlockContext::::mocked(); + + let checkpoint = block.start(); + let c1: Checkpoint = checkpoint.barrier(); + let c2: Checkpoint = c1.barrier(); + + // Direct ancestor-descendant pair + let span = Span::::between(&checkpoint, &c2).unwrap(); + assert_eq!(span.len(), 3); + assert_eq!(span.first().unwrap(), &checkpoint); + assert_eq!(span.len(), 2); + assert_eq!(span.last().unwrap(), &c2); + } + + #[test] + fn test_empty_span() { + let (block, _) = BlockContext::::mocked(); + + let checkpoint = block.start(); + + let span = Span::::between(&checkpoint, &checkpoint).unwrap(); + + assert_eq!(span.len(), 1); + } + + #[test] + fn test_between_nonlinear_history() { + let (block, _) = BlockContext::::mocked(); + + let checkpoint1 = block.start(); + let checkpoint2 = block.start(); + + let result = Span::between(&checkpoint1, &checkpoint2); + assert!(result.is_err()); + } + + #[test] + fn into_iter_and_iterators_work() { + let (block, _) = BlockContext::::mocked(); + + let root = block.start(); + let c1: Checkpoint = root.barrier(); + let c2: Checkpoint = c1.barrier(); + + let span = Span::::between(&root, &c2).unwrap(); + + // iter() + let ids_from_iter: Vec<_> = span.iter().map(|c| c.to_owned()).collect(); + assert_eq!(ids_from_iter.len(), 3); + assert_eq!(ids_from_iter[0], root); + assert_eq!(ids_from_iter[2], c2); + + // into_iter() + let ids_from_into_iter: Vec<_> = + span.clone().into_iter().map(|c| c).collect(); + assert_eq!(ids_from_iter, ids_from_into_iter); + } +} From 0dfe1bab52175828239f0dc19968975157e96575 Mon Sep 17 00:00:00 2001 From: varun-doshi Date: Fri, 10 Oct 2025 12:28:47 +0530 Subject: [PATCH 2/3] feat(tests): Add tests for SpanExt --- src/payload/ext/span.rs | 122 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 119 insertions(+), 3 deletions(-) diff --git a/src/payload/ext/span.rs b/src/payload/ext/span.rs index a6bdedb..cf53bfc 100644 --- a/src/payload/ext/span.rs +++ b/src/payload/ext/span.rs @@ -1,7 +1,5 @@ use crate::{ - alloy::primitives::TxHash, - prelude::*, - reth::primitives::Recovered, + alloy::primitives::TxHash, prelude::*, reth::primitives::Recovered, }; /// Quality of Life extensions for the `Span` type. @@ -106,3 +104,121 @@ impl SpanExt

for Span

{ } } } + +#[cfg(test)] +mod span_ext_tests { + use crate::{ + payload::{Span, SpanExt}, + prelude::{BlockContext, Checkpoint, Ethereum}, + test_utils::BlockContextMocked, + }; + + use { + alloy::{ + consensus::{EthereumTxEnvelope, TxEip4844}, + network::{TransactionBuilder, TxSignerSync}, + primitives::{Address, U256}, + signers::local::PrivateKeySigner, + }, + rblib::{alloy, reth, test_utils::FundedAccounts}, + reth::{ + ethereum::{TransactionSigned, primitives::SignedTransaction}, + primitives::Recovered, + rpc::types::TransactionRequest, + }, + }; + + fn transfer_tx( + signer: &PrivateKeySigner, + nonce: u64, + value: U256, + ) -> Recovered> { + let mut tx = TransactionRequest::default() + .with_nonce(nonce) + .with_to(Address::random()) + .value(value) + .with_gas_price(1_000_000_000) + .with_gas_limit(21_000) + .with_max_priority_fee_per_gas(1_000_000) + .with_max_fee_per_gas(2_000_000) + .build_unsigned() + .expect("valid transaction request"); + + let sig = signer + .sign_transaction_sync(&mut tx) + .expect("signing should succeed"); + + TransactionSigned::new_unhashed(tx.into(), sig) + .with_signer(signer.address()) + } + + #[test] + fn gas_and_blob_gas_used_sum_correctly() { + let (block, _) = BlockContext::::mocked(); + + let root = block.start(); + let c1: Checkpoint = root.barrier(); + let c2: Checkpoint = c1.barrier(); + + let span = Span::::between(&root, &c2).unwrap(); + + assert_eq!(span.gas_used(), 0); + assert_eq!(span.blob_gas_used(), 0); + } + + #[test] + fn contains_transaction_hash_works() { + let (block, _) = BlockContext::::mocked(); + + let root = block.start(); + let c1: Checkpoint = root.barrier(); + + let tx1 = transfer_tx(&FundedAccounts::signer(0), 0, U256::from(50_000u64)); + + let c2 = c1.apply(tx1.clone()).unwrap(); + + let span = Span::::between(&root, &c2).unwrap(); + + assert!(span.contains(*tx1.hash())); + } + + #[test] + fn split_at_produces_valid_halves() { + let (block, _) = BlockContext::::mocked(); + + let root = block.start(); + let c1: Checkpoint = root.barrier(); + let c2: Checkpoint = c1.barrier(); + + let span = Span::::between(&root, &c2).unwrap(); + + let (left, right) = span.split_at(1); + assert_eq!(left.len(), 1); + assert_eq!(right.len(), 2); + + let (left_all, right_empty) = span.split_at(10); + assert_eq!(left_all.len(), span.len()); + assert!(right_empty.is_empty()); + } + + #[test] + fn take_and_skip_are_consistent_with_split_at() { + let (block, _) = BlockContext::::mocked(); + + let root = block.start(); + let c1: Checkpoint = root.barrier(); + let c2: Checkpoint = c1.barrier(); + + let span = Span::::between(&root, &c2).unwrap(); + + let take_1 = span.take(1); + let skip_1 = span.skip(1); + + assert_eq!(take_1.len(), 1); + assert_eq!(skip_1.len(), 2); + + let (left, right) = span.split_at(1); + assert_eq!(take_1.len(), left.len()); + assert_eq!(skip_1.len(), right.len()); + } +} From 27dfaf70fda2a0af27b53f28a390bf84473b3b19 Mon Sep 17 00:00:00 2001 From: julio4 <30329843+julio4@users.noreply.github.com> Date: Wed, 12 Nov 2025 01:20:58 +0900 Subject: [PATCH 3/3] test: span nit --- src/payload/ext/span.rs | 65 ++++++++++++----------------------------- src/payload/span.rs | 18 ++++++------ 2 files changed, 27 insertions(+), 56 deletions(-) diff --git a/src/payload/ext/span.rs b/src/payload/ext/span.rs index cf53bfc..5f03f3e 100644 --- a/src/payload/ext/span.rs +++ b/src/payload/ext/span.rs @@ -1,5 +1,7 @@ use crate::{ - alloy::primitives::TxHash, prelude::*, reth::primitives::Recovered, + alloy::primitives::TxHash, + prelude::*, + reth::primitives::Recovered, }; /// Quality of Life extensions for the `Span` type. @@ -107,54 +109,19 @@ impl SpanExt

for Span

{ #[cfg(test)] mod span_ext_tests { - use crate::{ - payload::{Span, SpanExt}, - prelude::{BlockContext, Checkpoint, Ethereum}, - test_utils::BlockContextMocked, - }; - use { - alloy::{ - consensus::{EthereumTxEnvelope, TxEip4844}, - network::{TransactionBuilder, TxSignerSync}, - primitives::{Address, U256}, - signers::local::PrivateKeySigner, - }, - rblib::{alloy, reth, test_utils::FundedAccounts}, - reth::{ - ethereum::{TransactionSigned, primitives::SignedTransaction}, - primitives::Recovered, - rpc::types::TransactionRequest, + crate::{ + payload::{Span, SpanExt}, + prelude::{BlockContext, Checkpoint, Ethereum}, + test_utils::{BlockContextMocked, transfer_tx}, }, + alloy::primitives::U256, + rblib::{alloy, test_utils::FundedAccounts}, }; - fn transfer_tx( - signer: &PrivateKeySigner, - nonce: u64, - value: U256, - ) -> Recovered> { - let mut tx = TransactionRequest::default() - .with_nonce(nonce) - .with_to(Address::random()) - .value(value) - .with_gas_price(1_000_000_000) - .with_gas_limit(21_000) - .with_max_priority_fee_per_gas(1_000_000) - .with_max_fee_per_gas(2_000_000) - .build_unsigned() - .expect("valid transaction request"); - - let sig = signer - .sign_transaction_sync(&mut tx) - .expect("signing should succeed"); - - TransactionSigned::new_unhashed(tx.into(), sig) - .with_signer(signer.address()) - } - #[test] fn gas_and_blob_gas_used_sum_correctly() { - let (block, _) = BlockContext::::mocked(); + let block = BlockContext::::mocked(); let root = block.start(); let c1: Checkpoint = root.barrier(); @@ -168,12 +135,16 @@ mod span_ext_tests { #[test] fn contains_transaction_hash_works() { - let (block, _) = BlockContext::::mocked(); + let block = BlockContext::::mocked(); let root = block.start(); let c1: Checkpoint = root.barrier(); - let tx1 = transfer_tx(&FundedAccounts::signer(0), 0, U256::from(50_000u64)); + let tx1 = transfer_tx::( + &FundedAccounts::signer(0), + 0, + U256::from(50_000u64), + ); let c2 = c1.apply(tx1.clone()).unwrap(); @@ -184,7 +155,7 @@ mod span_ext_tests { #[test] fn split_at_produces_valid_halves() { - let (block, _) = BlockContext::::mocked(); + let block = BlockContext::::mocked(); let root = block.start(); let c1: Checkpoint = root.barrier(); @@ -203,7 +174,7 @@ mod span_ext_tests { #[test] fn take_and_skip_are_consistent_with_split_at() { - let (block, _) = BlockContext::::mocked(); + let block = BlockContext::::mocked(); let root = block.start(); let c1: Checkpoint = root.barrier(); diff --git a/src/payload/span.rs b/src/payload/span.rs index 442bd7c..cace757 100644 --- a/src/payload/span.rs +++ b/src/payload/span.rs @@ -192,23 +192,24 @@ mod tests { #[test] fn span_between_linear_history() { - let (block, _) = BlockContext::::mocked(); + let block = BlockContext::::mocked(); let checkpoint = block.start(); let c1: Checkpoint = checkpoint.barrier(); let c2: Checkpoint = c1.barrier(); // Direct ancestor-descendant pair - let span = Span::::between(&checkpoint, &c2).unwrap(); + let mut span = Span::::between(&checkpoint, &c2).unwrap(); assert_eq!(span.len(), 3); - assert_eq!(span.first().unwrap(), &checkpoint); + assert_eq!(span.pop_first().unwrap(), checkpoint); assert_eq!(span.len(), 2); - assert_eq!(span.last().unwrap(), &c2); + assert_eq!(span.pop_last().unwrap(), c2); + assert_eq!(span.len(), 1); } #[test] fn test_empty_span() { - let (block, _) = BlockContext::::mocked(); + let block = BlockContext::::mocked(); let checkpoint = block.start(); @@ -219,7 +220,7 @@ mod tests { #[test] fn test_between_nonlinear_history() { - let (block, _) = BlockContext::::mocked(); + let block = BlockContext::::mocked(); let checkpoint1 = block.start(); let checkpoint2 = block.start(); @@ -230,7 +231,7 @@ mod tests { #[test] fn into_iter_and_iterators_work() { - let (block, _) = BlockContext::::mocked(); + let block = BlockContext::::mocked(); let root = block.start(); let c1: Checkpoint = root.barrier(); @@ -245,8 +246,7 @@ mod tests { assert_eq!(ids_from_iter[2], c2); // into_iter() - let ids_from_into_iter: Vec<_> = - span.clone().into_iter().map(|c| c).collect(); + let ids_from_into_iter: Vec<_> = span.clone().into_iter().collect(); assert_eq!(ids_from_iter, ids_from_into_iter); } }