@@ -24,36 +24,47 @@ impl ScannerBuilder {
2424 }
2525 }
2626
27+ #[ must_use]
2728 pub fn start_block ( mut self , start_block : u64 ) -> Self {
2829 self . start_block = Some ( start_block) ;
2930 self
3031 }
3132
33+ #[ must_use]
3234 pub fn end_block ( mut self , end_block : u64 ) -> Self {
3335 self . end_block = Some ( end_block) ;
3436 self
3537 }
3638
39+ #[ must_use]
3740 pub fn max_blocks_per_filter ( mut self , max_blocks : u64 ) -> Self {
3841 self . max_blocks_per_filter = max_blocks;
3942 self
4043 }
4144
45+ #[ must_use]
4246 pub fn add_event_filter ( mut self , filter : EventFilter ) -> Self {
4347 self . tracked_events . push ( filter) ;
4448 self
4549 }
4650
51+ #[ must_use]
4752 pub fn add_event_filters ( mut self , filters : Vec < EventFilter > ) -> Self {
4853 self . tracked_events . extend ( filters) ;
4954 self
5055 }
5156
57+ #[ must_use]
5258 pub fn callback_config ( mut self , cfg : CallbackConfig ) -> Self {
5359 self . callback_config = cfg;
5460 self
5561 }
5662
63+ /// Builds the scanner
64+ ///
65+ /// # Errors
66+ ///
67+ /// Returns an error if the scanner fails to build
5768 pub async fn build ( self ) -> anyhow:: Result < Scanner > {
5869 Scanner :: new (
5970 self . rpc_url ,
@@ -66,3 +77,204 @@ impl ScannerBuilder {
6677 . await
6778 }
6879}
80+
81+ #[ cfg( test) ]
82+ mod tests {
83+ use super :: * ;
84+ use crate :: callback:: EventCallback ;
85+ use alloy:: { primitives:: address, rpc:: types:: Log } ;
86+ use async_trait:: async_trait;
87+ use std:: sync:: Arc ;
88+
89+ struct MockCallback ;
90+
91+ #[ async_trait]
92+ impl EventCallback for MockCallback {
93+ async fn on_event ( & self , _log : & Log ) -> anyhow:: Result < ( ) > {
94+ Ok ( ( ) )
95+ }
96+ }
97+
98+ const WS_URL : & str = "ws://localhost:8545" ;
99+
100+ #[ test]
101+ fn test_builder_new_defaults ( ) {
102+ let builder = ScannerBuilder :: new ( WS_URL ) ;
103+ assert_eq ! ( builder. rpc_url, WS_URL ) ;
104+ assert_eq ! ( builder. start_block, None ) ;
105+ assert_eq ! ( builder. end_block, None ) ;
106+ assert_eq ! ( builder. max_blocks_per_filter, 1000 ) ;
107+ assert ! ( builder. tracked_events. is_empty( ) ) ;
108+ }
109+
110+ #[ test]
111+ fn test_builder_start_block ( ) {
112+ let start_block = 100 ;
113+ let builder = ScannerBuilder :: new ( WS_URL ) . start_block ( start_block) ;
114+ assert_eq ! ( builder. start_block, Some ( start_block) ) ;
115+ }
116+
117+ #[ test]
118+ fn test_builder_end_block ( ) {
119+ let end_block = 500 ;
120+ let builder = ScannerBuilder :: new ( WS_URL ) . end_block ( end_block) ;
121+ assert_eq ! ( builder. end_block, Some ( end_block) ) ;
122+ }
123+
124+ #[ test]
125+ fn test_builder_block_range ( ) {
126+ let start_block = 100 ;
127+ let end_block = 500 ;
128+ let builder = ScannerBuilder :: new ( WS_URL ) . start_block ( start_block) . end_block ( end_block) ;
129+ assert_eq ! ( builder. start_block, Some ( start_block) ) ;
130+ assert_eq ! ( builder. end_block, Some ( end_block) ) ;
131+ }
132+
133+ #[ test]
134+ fn test_builder_max_blocks_per_filter ( ) {
135+ let max_blocks = 5000 ;
136+ let builder = ScannerBuilder :: new ( WS_URL ) . max_blocks_per_filter ( max_blocks) ;
137+ assert_eq ! ( builder. max_blocks_per_filter, max_blocks) ;
138+ }
139+
140+ #[ test]
141+ fn test_builder_callback_config ( ) {
142+ let max_attempts = 5 ;
143+ let delay_ms = 500 ;
144+ let config = CallbackConfig { max_attempts, delay_ms } ;
145+
146+ let builder = ScannerBuilder :: new ( WS_URL ) . callback_config ( config. clone ( ) ) ;
147+
148+ assert_eq ! ( builder. callback_config. max_attempts, max_attempts) ;
149+ assert_eq ! ( builder. callback_config. delay_ms, delay_ms) ;
150+ }
151+
152+ #[ test]
153+ fn test_builder_default_callback_config ( ) {
154+ let builder = ScannerBuilder :: new ( WS_URL ) ;
155+
156+ assert_eq ! ( builder. callback_config. max_attempts, 3 ) ;
157+ assert_eq ! ( builder. callback_config. delay_ms, 200 ) ;
158+ }
159+
160+ #[ test]
161+ fn test_builder_add_event_filter ( ) {
162+ let addr = address ! ( "f39Fd6e51aad88F6F4ce6aB8827279cffFb92266" ) ;
163+ let event = "Transfer(address,address,uint256)" . to_string ( ) ;
164+ let filter = EventFilter {
165+ contract_address : addr,
166+ event : event. clone ( ) ,
167+ callback : Arc :: new ( MockCallback ) ,
168+ } ;
169+ let builder = ScannerBuilder :: new ( WS_URL ) . add_event_filter ( filter. clone ( ) ) ;
170+
171+ assert_eq ! ( builder. tracked_events. len( ) , 1 ) ;
172+ assert_eq ! ( builder. tracked_events[ 0 ] . contract_address, addr) ;
173+ assert_eq ! ( builder. tracked_events[ 0 ] . event, event) ;
174+ }
175+
176+ #[ test]
177+ fn test_builder_add_multiple_event_filters ( ) {
178+ let addr1 = address ! ( "f39Fd6e51aad88F6F4ce6aB8827279cffFb92266" ) ;
179+ let event1 = "Transfer(address,address,uint256)" . to_string ( ) ;
180+ let addr2 = address ! ( "70997970C51812dc3A010C7d01b50e0d17dc79C8" ) ;
181+ let event2 = "Approval(address,address,uint256)" . to_string ( ) ;
182+
183+ let filter1 = EventFilter {
184+ contract_address : addr1,
185+ event : event1. clone ( ) ,
186+ callback : Arc :: new ( MockCallback ) ,
187+ } ;
188+ let filter2 = EventFilter {
189+ contract_address : addr2,
190+ event : event2. clone ( ) ,
191+ callback : Arc :: new ( MockCallback ) ,
192+ } ;
193+
194+ let builder = ScannerBuilder :: new ( WS_URL )
195+ . add_event_filter ( filter1. clone ( ) )
196+ . add_event_filter ( filter2. clone ( ) ) ;
197+
198+ assert_eq ! ( builder. tracked_events. len( ) , 2 ) ;
199+ for ( i, expected_filter) in builder. tracked_events . iter ( ) . enumerate ( ) {
200+ assert_eq ! (
201+ builder. tracked_events[ i] . contract_address,
202+ expected_filter. contract_address
203+ ) ;
204+ assert_eq ! ( builder. tracked_events[ i] . event, expected_filter. event) ;
205+ }
206+ }
207+
208+ #[ test]
209+ fn test_builder_add_event_filters_batch ( ) {
210+ let addr1 = address ! ( "f39Fd6e51aad88F6F4ce6aB8827279cffFb92266" ) ;
211+ let event1 = "Transfer(address,address,uint256)" . to_string ( ) ;
212+ let addr2 = address ! ( "70997970C51812dc3A010C7d01b50e0d17dc79C8" ) ;
213+ let event2 = "Approval(address,address,uint256)" . to_string ( ) ;
214+ let addr3 = address ! ( "3C44CdDdB6a900fa2b585dd299e03d12FA4293BC" ) ;
215+ let event3 = "Mint(address,uint256)" . to_string ( ) ;
216+
217+ let filter_1 = EventFilter {
218+ contract_address : addr1,
219+ event : event1. clone ( ) ,
220+ callback : Arc :: new ( MockCallback ) ,
221+ } ;
222+ let filter_2 = EventFilter {
223+ contract_address : addr2,
224+ event : event2. clone ( ) ,
225+ callback : Arc :: new ( MockCallback ) ,
226+ } ;
227+ let filter_3 = EventFilter {
228+ contract_address : addr3,
229+ event : event3. clone ( ) ,
230+ callback : Arc :: new ( MockCallback ) ,
231+ } ;
232+
233+ let filters = vec ! [ filter_1. clone( ) , filter_2. clone( ) , filter_3. clone( ) ] ;
234+ let builder = ScannerBuilder :: new ( WS_URL ) . add_event_filters ( filters. clone ( ) ) ;
235+
236+ assert_eq ! ( builder. tracked_events. len( ) , filters. len( ) ) ;
237+
238+ for ( i, expected_filter) in filters. iter ( ) . enumerate ( ) {
239+ assert_eq ! (
240+ builder. tracked_events[ i] . contract_address,
241+ expected_filter. contract_address
242+ ) ;
243+ assert_eq ! ( builder. tracked_events[ i] . event, expected_filter. event) ;
244+ }
245+ }
246+
247+ #[ test]
248+ fn test_builder_chain_all_methods ( ) {
249+ let start_block = 100 ;
250+ let end_block = 500 ;
251+
252+ let addr = address ! ( "f39Fd6e51aad88F6F4ce6aB8827279cffFb92266" ) ;
253+ let event = "Transfer(address,address,uint256)" . to_string ( ) ;
254+
255+ let filter = EventFilter {
256+ contract_address : addr,
257+ event : event. clone ( ) ,
258+ callback : Arc :: new ( MockCallback ) ,
259+ } ;
260+
261+ let max_attempts = 5 ;
262+ let delay_ms = 500 ;
263+ let config = CallbackConfig { max_attempts, delay_ms } ;
264+
265+ let max_blocks_per_filter = 2000 ;
266+ let builder = ScannerBuilder :: new ( WS_URL )
267+ . start_block ( start_block)
268+ . end_block ( end_block)
269+ . max_blocks_per_filter ( max_blocks_per_filter)
270+ . add_event_filter ( filter. clone ( ) )
271+ . callback_config ( config. clone ( ) ) ;
272+
273+ assert_eq ! ( builder. start_block, Some ( start_block) ) ;
274+ assert_eq ! ( builder. end_block, Some ( end_block) ) ;
275+ assert_eq ! ( builder. max_blocks_per_filter, max_blocks_per_filter) ;
276+ assert_eq ! ( builder. tracked_events. len( ) , 1 ) ;
277+ assert_eq ! ( builder. callback_config. max_attempts, max_attempts) ;
278+ assert_eq ! ( builder. callback_config. delay_ms, delay_ms) ;
279+ }
280+ }
0 commit comments