Skip to content

Commit 0b0edc0

Browse files
committed
refactor tests
1 parent d9a3193 commit 0b0edc0

2 files changed

Lines changed: 59 additions & 512 deletions

File tree

program-libs/batched-merkle-tree/tests/merkle_tree_ref.rs

Lines changed: 31 additions & 280 deletions
Original file line numberDiff line numberDiff line change
@@ -3,93 +3,13 @@ mod test_helpers;
33
use light_batched_merkle_tree::{
44
merkle_tree::BatchedMerkleTreeAccount, merkle_tree_ref::BatchedMerkleTreeRef,
55
};
6-
use light_compressed_account::{pubkey::Pubkey, TreeType, STATE_MERKLE_TREE_TYPE_V2};
7-
use light_merkle_tree_metadata::{errors::MerkleTreeMetadataError, merkle_tree::MerkleTreeMetadata};
6+
use light_compressed_account::{pubkey::Pubkey, TreeType};
7+
use light_merkle_tree_metadata::errors::MerkleTreeMetadataError;
88
use test_helpers::{account_builders::MerkleTreeAccountBuilder, assertions::*};
99

10-
#[test]
11-
fn test_merkle_tree_ref_matches_mutable() {
12-
let mut account_data = vec![0u8; 3376];
13-
let batch_size = 5;
14-
let zkp_batch_size = 1;
15-
let root_history_len = 10;
16-
let num_iter = 1;
17-
let bloom_filter_capacity = 8000;
18-
let height = 40;
19-
let pubkey = Pubkey::new_unique();
20-
21-
// Initialize via mutable path.
22-
let _account = BatchedMerkleTreeAccount::init(
23-
&mut account_data,
24-
&pubkey,
25-
MerkleTreeMetadata::default(),
26-
root_history_len,
27-
batch_size,
28-
zkp_batch_size,
29-
height,
30-
num_iter,
31-
bloom_filter_capacity,
32-
TreeType::AddressV2,
33-
)
34-
.unwrap();
35-
36-
// Collect expected values from the mutable path.
37-
let expected_metadata;
38-
let expected_height;
39-
let expected_tree_type;
40-
let expected_seq;
41-
let expected_pubkey;
42-
let mut expected_roots = Vec::new();
43-
let expected_bf0;
44-
let expected_bf1;
45-
{
46-
let tree_mut =
47-
BatchedMerkleTreeAccount::address_from_bytes(&mut account_data, &pubkey).unwrap();
48-
expected_metadata = *tree_mut.get_metadata();
49-
expected_height = tree_mut.height;
50-
expected_tree_type = tree_mut.tree_type;
51-
expected_seq = tree_mut.sequence_number;
52-
expected_pubkey = *tree_mut.pubkey();
53-
for i in 0..root_history_len as usize {
54-
expected_roots.push(tree_mut.get_root_by_index(i).copied());
55-
}
56-
expected_bf0 = tree_mut.bloom_filter_stores[0].to_vec();
57-
expected_bf1 = tree_mut.bloom_filter_stores[1].to_vec();
58-
}
59-
60-
// Read via immutable ref.
61-
let tree_ref = BatchedMerkleTreeRef::address_from_bytes(&account_data, &pubkey).unwrap();
62-
63-
// Metadata should match (use Deref trait).
64-
assert_eq!(*tree_ref, expected_metadata);
65-
assert_eq!(tree_ref.height, expected_height);
66-
assert_eq!(tree_ref.tree_type, expected_tree_type);
67-
assert_eq!(tree_ref.sequence_number, expected_seq);
68-
assert_eq!(*tree_ref.pubkey(), expected_pubkey);
69-
70-
// Root history should match (using root_history() accessor).
71-
for (i, expected) in expected_roots.iter().enumerate() {
72-
assert_eq!(Some(*tree_ref.get_root_by_index(i).unwrap()), *expected);
73-
}
74-
75-
// Bloom filter stores should match.
76-
assert_eq!(tree_ref.bloom_filter_stores[0], expected_bf0.as_slice());
77-
assert_eq!(tree_ref.bloom_filter_stores[1], expected_bf1.as_slice());
78-
79-
// Non-inclusion check should work.
80-
let random_value = [42u8; 32];
81-
tree_ref
82-
.check_input_queue_non_inclusion(&random_value)
83-
.unwrap();
84-
}
85-
86-
// ============================================================================
87-
// New comprehensive tests for 100% coverage
88-
// ============================================================================
89-
9010
#[test]
9111
fn test_merkle_tree_ref_deserialization_matrix() {
92-
// Test matrix: tree type × API method (table-driven test)
12+
// Test matrix: tree type x API method (table-driven test)
9313
let test_cases = vec![
9414
("State tree with state API", TreeType::StateV2, "state", true),
9515
("Address tree with address API", TreeType::AddressV2, "address", true),
@@ -160,211 +80,15 @@ fn test_merkle_tree_ref_from_bytes_errors() {
16080
MerkleTreeMetadataError::InvalidTreeType,
16181
"Wrong tree type should fail",
16282
);
163-
}
164-
165-
#[test]
166-
fn test_merkle_tree_ref_root_history_access() {
167-
let (mut account_data, pubkey) = MerkleTreeAccountBuilder::state_tree().build();
168-
let root_history_len = 10;
169-
170-
// Populate root history via mutable ref and collect expected values
171-
let mut expected_roots = Vec::new();
172-
{
173-
let mut tree_mut = BatchedMerkleTreeAccount::state_from_bytes(&mut account_data, &pubkey).unwrap();
174-
// Init already pushed an initial root at index 0. Push additional values.
175-
for i in 1u8..6 {
176-
tree_mut.root_history.push([i; 32]);
177-
}
178-
// Collect expected root values from mutable path
179-
for i in 0..root_history_len as usize {
180-
expected_roots.push(tree_mut.get_root_by_index(i).copied());
181-
}
182-
}
183-
184-
// Access via immutable ref
185-
let tree_ref = BatchedMerkleTreeRef::state_from_bytes(&account_data, &pubkey).unwrap();
186-
187-
// Verify root_history at physical indices matches mutable path
188-
for (i, expected) in expected_roots.iter().enumerate() {
189-
assert_eq!(
190-
Some(*tree_ref.get_root_by_index(i).unwrap()),
191-
*expected,
192-
"Root at index {} should match",
193-
i
194-
);
195-
}
196-
}
19783

198-
#[test]
199-
fn test_merkle_tree_ref_root_history_boundaries() {
200-
let (mut account_data, pubkey) = MerkleTreeAccountBuilder::state_tree().build();
201-
let root_history_len = 10;
202-
203-
// Collect boundary values from the mutable path
204-
let first_root;
205-
let last_root;
206-
{
207-
let tree_mut = BatchedMerkleTreeAccount::state_from_bytes(&mut account_data, &pubkey).unwrap();
208-
// Init already pushed an initial root. Collect it at index 0.
209-
first_root = tree_mut.get_root_by_index(0).copied().unwrap();
210-
last_root = tree_mut.get_root_by_index((root_history_len - 1) as usize).copied().unwrap();
211-
}
212-
213-
let tree_ref = BatchedMerkleTreeRef::state_from_bytes(&account_data, &pubkey).unwrap();
214-
215-
// Verify boundary access works (index 0 and capacity-1)
216-
assert_eq!(
217-
*tree_ref.get_root_by_index(0).unwrap(),
218-
first_root,
219-
"First root should be accessible"
220-
);
221-
assert_eq!(
222-
*tree_ref
223-
.get_root_by_index((root_history_len - 1) as usize)
224-
.unwrap(),
225-
last_root,
226-
"Last root should be accessible"
227-
);
228-
}
229-
230-
#[test]
231-
fn test_merkle_tree_ref_root_history_out_of_bounds() {
84+
// Test 5: Root history out-of-bounds returns None
23285
let (data, pubkey) = MerkleTreeAccountBuilder::state_tree()
23386
.with_root_history_capacity(5)
23487
.build();
235-
23688
let tree_ref = BatchedMerkleTreeRef::state_from_bytes(&data, &pubkey).unwrap();
237-
238-
// Access beyond length returns None
23989
assert!(tree_ref.get_root_by_index(10).is_none());
24090
}
24191

242-
#[test]
243-
fn test_merkle_tree_ref_bloom_filter_stores() {
244-
let (data, pubkey) = MerkleTreeAccountBuilder::state_tree()
245-
.with_bloom_filter_capacity(8000)
246-
.build();
247-
248-
let tree_ref = BatchedMerkleTreeRef::state_from_bytes(&data, &pubkey).unwrap();
249-
250-
// Verify bloom filter stores are accessible
251-
assert_eq!(
252-
tree_ref.bloom_filter_stores.len(),
253-
2,
254-
"Should have 2 bloom filter stores"
255-
);
256-
257-
// Each bloom filter store should have the correct size (capacity / 8)
258-
let expected_size = 8000 / 8;
259-
assert_eq!(
260-
tree_ref.bloom_filter_stores[0].len(),
261-
expected_size,
262-
"First bloom filter store should have correct size"
263-
);
264-
assert_eq!(
265-
tree_ref.bloom_filter_stores[1].len(),
266-
expected_size,
267-
"Second bloom filter store should have correct size"
268-
);
269-
}
270-
271-
#[test]
272-
fn test_merkle_tree_ref_check_non_inclusion_empty() {
273-
// Table-driven test: various values against empty bloom filters
274-
let test_values = vec![
275-
[0u8; 32],
276-
[0xFF; 32],
277-
[0x55; 32],
278-
[0xAA; 32],
279-
];
280-
281-
let (data, pubkey) = MerkleTreeAccountBuilder::state_tree().build();
282-
let tree_ref = BatchedMerkleTreeRef::state_from_bytes(&data, &pubkey).unwrap();
283-
284-
// All should pass non-inclusion check (no values inserted yet)
285-
for (i, value) in test_values.iter().enumerate() {
286-
tree_ref
287-
.check_input_queue_non_inclusion(value)
288-
.unwrap_or_else(|_| panic!("Test value {} should pass non-inclusion on empty filter", i));
289-
}
290-
}
291-
292-
#[test]
293-
fn test_merkle_tree_ref_check_non_inclusion_with_values() {
294-
let (mut account_data, pubkey) = MerkleTreeAccountBuilder::state_tree()
295-
.with_num_iters(3)
296-
.build();
297-
298-
let inserted_value = [0x42; 32];
299-
let non_inserted_value = [0x99; 32];
300-
301-
// Insert value into bloom filter via mutable path
302-
{
303-
let mut tree_mut = BatchedMerkleTreeAccount::state_from_bytes(&mut account_data, &pubkey).unwrap();
304-
// Insert into current batch's bloom filter
305-
use light_bloom_filter::BloomFilter;
306-
// Get metadata values first before borrowing bloom_filter_stores
307-
let num_iters = tree_mut.queue_batches.batches[0].num_iters as usize;
308-
let capacity = tree_mut.queue_batches.batches[0].bloom_filter_capacity;
309-
let bloom_filter = &mut tree_mut.bloom_filter_stores[0];
310-
let mut bf = BloomFilter::new(num_iters, capacity, bloom_filter).unwrap();
311-
bf.insert(&inserted_value).unwrap();
312-
}
313-
314-
// Read via immutable ref
315-
let tree_ref = BatchedMerkleTreeRef::state_from_bytes(&account_data, &pubkey).unwrap();
316-
317-
// Check inserted value fails non-inclusion
318-
assert!(
319-
tree_ref.check_input_queue_non_inclusion(&inserted_value).is_err(),
320-
"Inserted value should fail non-inclusion check"
321-
);
322-
323-
// Check non-inserted value passes non-inclusion
324-
assert!(
325-
tree_ref.check_input_queue_non_inclusion(&non_inserted_value).is_ok(),
326-
"Non-inserted value should pass non-inclusion check"
327-
);
328-
}
329-
330-
#[test]
331-
fn test_merkle_tree_ref_metadata_deref() {
332-
let (data, pubkey) = MerkleTreeAccountBuilder::state_tree()
333-
.with_height(26)
334-
.build();
335-
336-
let tree_ref = BatchedMerkleTreeRef::state_from_bytes(&data, &pubkey).unwrap();
337-
338-
// Access metadata fields via Deref
339-
assert_eq!(
340-
tree_ref.tree_type,
341-
STATE_MERKLE_TREE_TYPE_V2,
342-
"tree_type should be accessible via Deref"
343-
);
344-
assert_eq!(
345-
tree_ref.height,
346-
26,
347-
"height should be accessible via Deref"
348-
);
349-
assert_eq!(
350-
tree_ref.sequence_number,
351-
0,
352-
"sequence_number should be accessible via Deref"
353-
);
354-
355-
// Access queue_batches fields
356-
assert_eq!(
357-
tree_ref.queue_batches.num_batches,
358-
2,
359-
"num_batches should be accessible"
360-
);
361-
assert_eq!(
362-
tree_ref.queue_batches.batch_size,
363-
5,
364-
"batch_size should be accessible"
365-
);
366-
}
367-
36892
#[test]
36993
fn test_merkle_tree_ref_different_configurations() {
37094
// Table-driven test: different tree configurations
@@ -529,4 +253,31 @@ fn test_merkle_tree_ref_randomized_equivalence() {
529253
// Pubkey.
530254
assert_eq!(tree_ref.pubkey(), tree_mut.pubkey());
531255
}
256+
257+
// Non-inclusion coverage: insert a known value and verify it fails non-inclusion,
258+
// while a non-inserted value passes.
259+
let inserted_value = [0x42; 32];
260+
let non_inserted_value = [0x99; 32];
261+
{
262+
let mut tree_mut =
263+
BatchedMerkleTreeAccount::state_from_bytes(&mut account_data, &pubkey).unwrap();
264+
let num_iters = tree_mut.queue_batches.batches[0].num_iters as usize;
265+
let capacity = tree_mut.queue_batches.batches[0].bloom_filter_capacity;
266+
let mut bf =
267+
BloomFilter::new(num_iters, capacity, &mut tree_mut.bloom_filter_stores[0]).unwrap();
268+
bf.insert(&inserted_value).unwrap();
269+
}
270+
let tree_ref = BatchedMerkleTreeRef::state_from_bytes(&account_data, &pubkey).unwrap();
271+
assert!(
272+
tree_ref
273+
.check_input_queue_non_inclusion(&inserted_value)
274+
.is_err(),
275+
"Inserted value should fail non-inclusion check"
276+
);
277+
assert!(
278+
tree_ref
279+
.check_input_queue_non_inclusion(&non_inserted_value)
280+
.is_ok(),
281+
"Non-inserted value should pass non-inclusion check"
282+
);
532283
}

0 commit comments

Comments
 (0)